From 2523d870fc333584038e43c594b0137b49fb1090 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 7 Jun 2018 16:23:25 +0300 Subject: [PATCH 001/250] Added postfix "_operations" in plugin. --- plugins/operation_history/plugin.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 5138b9bbfc..c3f4b7b719 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -196,7 +196,13 @@ namespace golos { namespace plugins { namespace operation_history { for (const auto& op : ops) { if (op.size()) { - pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op); + std::string ops_postfix("_operation"); + stp::size_t pos = op.find(ops_postfix); + if (pos != std::string::npos && pos + ops_postfix.size() == op.size()) { + pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); + } else { + pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op); + } } } } From e520a3ee45f26527db2c73991f8021a1596b23e7 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 7 Jun 2018 21:56:37 +0300 Subject: [PATCH 002/250] Added template for test. --- plugins/operation_history/plugin.cpp | 2 +- tests/plugin_tests/plugin_ops.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index c3f4b7b719..4c8214d73a 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -197,7 +197,7 @@ namespace golos { namespace plugins { namespace operation_history { for (const auto& op : ops) { if (op.size()) { std::string ops_postfix("_operation"); - stp::size_t pos = op.find(ops_postfix); + std::size_t pos = op.find(ops_postfix); if (pos != std::string::npos && pos + ops_postfix.size() == op.size()) { pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); } else { diff --git a/tests/plugin_tests/plugin_ops.cpp b/tests/plugin_tests/plugin_ops.cpp index d691de0f3c..80e3dbb17f 100644 --- a/tests/plugin_tests/plugin_ops.cpp +++ b/tests/plugin_tests/plugin_ops.cpp @@ -110,4 +110,4 @@ BOOST_AUTO_TEST_CASE( custom_binary ) } */ BOOST_AUTO_TEST_SUITE_END() -#endif \ No newline at end of file +#endif From b42a9fc4564b752234314ceda4ea44690e53370a Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 7 Jun 2018 21:58:32 +0300 Subject: [PATCH 003/250] Added new test file. --- tests/plugin_tests/options_postfix.cpp | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/plugin_tests/options_postfix.cpp diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp new file mode 100644 index 0000000000..d266467a37 --- /dev/null +++ b/tests/plugin_tests/options_postfix.cpp @@ -0,0 +1,72 @@ +/// Runnung example: +/// ./plugin_test --log_level=test_suite --run_test=options_postfix + +#include + +#include + +#include + + + +namespace golos { namespace tests { + +typedef golos::plugins::operation_history::plugin plugin; + + +struct option_with_postfix { + std::string opt = "history-whitelist-ops = " \ + "account_create_operation " \ + "account_update_operation " \ + "comment_operation " \ + "delete_comment_operation"; +}; + + +struct option_without_postfix { + std::string opt = "history-whitelist-ops = " \ + "account_create " \ + "account_update " \ + "comment " \ + "delete_comment"; +}; + + +template +class test_options_postfix : public opt_type { + std::unique_ptr plg; + +public: + test_options_postfix() { + BOOST_TEST_MESSAGE("\"" + opt_type::opt + "\""); + plg.reset(new plugin); + plg->initialise(); + } + + ~test_options_postfix() { + plg.reset(); + } +}; +}} + + +typedef golos::tests::option_with_postfix option_with_postfix; +typedef golos::tests::option_without_postfix option_without_postfix; +typedef golos::tests::test_options_postfix test_with_postfix; +typedef golos::tests::test_options_postfix test_without_postfix; + + +BOOST_AUTO_TEST_SUITE(options_postfix); + +BOOST_AUTO_TEST_CASE(options_with_postfix) { + BOOST_TEST_MESSAGE("options_with_postfix: "); + test_with_postfix(); +} + + +BOOST_AUTO_TEST_CASE(options_without_postfix) { + BOOST_TEST_MESSAGE("options_without_postfix: "); + test_without_postfix(); +} + +BOOST_AUTO_TEST_SUITE_END() From 31cea4baed2ae89507569e95f481f158983f8d50 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 8 Jun 2018 21:46:51 +0300 Subject: [PATCH 004/250] Added basic logic test. --- plugins/operation_history/plugin.cpp | 11 ++- tests/plugin_tests/options_postfix.cpp | 105 +++++++++++++++++++++---- 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 4c8214d73a..d707850a24 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -179,15 +179,19 @@ namespace golos { namespace plugins { namespace operation_history { } void plugin::plugin_initialize(const boost::program_options::variables_map& options) { + ilog("###: plugin_initialize() 0"); ilog("operation_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); + ilog("###: plugin_initialize() 1"); pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ pimpl->on_operation(note); }); + ilog("###: plugin_initialize() 2"); golos::chain::add_plugin_index(pimpl->database); + ilog("###: plugin_initialize() 3"); auto split_list = [&](const std::vector& ops_list) { for (const auto& raw: ops_list) { @@ -196,17 +200,21 @@ namespace golos { namespace plugins { namespace operation_history { for (const auto& op : ops) { if (op.size()) { + ilog("#: opt ${s}", ("s", op)); std::string ops_postfix("_operation"); std::size_t pos = op.find(ops_postfix); - if (pos != std::string::npos && pos + ops_postfix.size() == op.size()) { + if (pos not_eq std::string::npos and (pos + ops_postfix.size()) == op.size()) { + ilog("#: without opt ${s}", ("s", STEEM_NAMESPACE_PREFIX + op + ops_postfix)); pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); } else { + ilog("#: with opt ${s}", ("s", STEEM_NAMESPACE_PREFIX + op)); pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op); } } } } }; + ilog("###: plugin_initialize() 4"); if (options.count("history-whitelist-ops")) { FC_ASSERT( @@ -223,6 +231,7 @@ namespace golos { namespace plugins { namespace operation_history { split_list(options.at("history-blacklist-ops").as>()); ilog("operation_history: blacklisting ops ${o}", ("o", pimpl->ops_list)); } + ilog("###: plugin_initialize() 5"); if (options.count("history-start-block")) { pimpl->filter_content = true; diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index d266467a37..c339ab1a36 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -2,8 +2,12 @@ /// ./plugin_test --log_level=test_suite --run_test=options_postfix #include +#include +#include +#include #include +#include #include @@ -11,11 +15,14 @@ namespace golos { namespace tests { -typedef golos::plugins::operation_history::plugin plugin; +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; +typedef golos::plugins::operation_history::plugin test_plugin; + struct option_with_postfix { - std::string opt = "history-whitelist-ops = " \ + std::string opt = "account_create_operation " \ "account_update_operation " \ "comment_operation " \ @@ -24,7 +31,7 @@ struct option_with_postfix { struct option_without_postfix { - std::string opt = "history-whitelist-ops = " \ + std::string opt = "account_create " \ "account_update " \ "comment " \ @@ -34,17 +41,86 @@ struct option_without_postfix { template class test_options_postfix : public opt_type { - std::unique_ptr plg; + std::unique_ptr _plg; + bpo::options_description _cfg_opts; + bpo::options_description _cli_opts; + bpo::variables_map _vm_opts; + + void fill_default_options() { + bpo::options_description cfg_opts("Application Config Options"); + cfg_opts.add_options() + ("plugin", bpo::value< vector >()->composing(), + "Plugin(s) to enable, may be specified multiple times") + ; + _cfg_opts.add(cfg_opts); + bpo::options_description cli_opts("Application Command Line Options"); + cli_opts.add_options() + ("help,h", "Print this help message and exit.") + ("version,v", "Print version information.") + ("data-dir,d", bpo::value()->default_value("./"), + "Directory containing configuration file config.ini") + ("config,c", bpo::value()->default_value("config.ini"), + "Configuration file name relative to data-dir") + ; + _cli_opts.add(cli_opts); + } + + void fill_testing_options() { + bpo::options_description all_opts; + all_opts + .add(_cli_opts) + .add(_cfg_opts) + ; + int argc = 0; + char **argv = nullptr; + bpo::store(bpo::parse_command_line(argc, argv, all_opts), _vm_opts); + bfs::path cfg_file_name = _vm_opts["config"].as(); + bfs::path cfg_dir = _vm_opts["data-dir"].as(); + cfg_file_name = cfg_dir / cfg_file_name; + if (bfs::exists(cfg_file_name)) { + bfs::remove(cfg_file_name); + } + std::ofstream out_cfg(bfs::path(cfg_file_name).make_preferred().string()); + out_cfg << "history-whitelist-ops = " << opt_type::opt << "\n"; + out_cfg << "history-blacklist-ops = " << opt_type::opt << "\n"; + bfs::path cfg_path = cfg_file_name.make_preferred(); + auto parsed_cfg = bpo::parse_config_file(cfg_path.string().c_str(), _cfg_opts, true); + //_cli_opts.add_options() + // ("history-whitelist-ops", "") + // ("history-blacklist-ops", "") + // ; + //std::string str_opts( + // "history-whitelist-ops = " + opt_type::opt + "\n" + + // "history-blacklist-ops = " + opt_type::opt + "\n"); + //std::istringstream iss_opts(str_opts); + //auto parsed_cfg = bpo::parse_config_file(iss_opts, all_opts); + //auto parsed_cfg = bpo::parse_command_line(argc, test_opt, all_options); + BOOST_TEST_MESSAGE("# PARSE OPTS"); + std::vector args = parsed_cfg.options; + for (auto arg : args) { + for (auto val : arg.value) { + std::string msg("> {" + arg.string_key + " : " + val + "}"); + BOOST_TEST_MESSAGE(msg); + } + } + bpo::store(parsed_cfg, _vm_opts); + bpo::notify(_vm_opts); + + if (bfs::exists(cfg_file_name)) { + bfs::remove(cfg_file_name); + } + } public: test_options_postfix() { - BOOST_TEST_MESSAGE("\"" + opt_type::opt + "\""); - plg.reset(new plugin); - plg->initialise(); + fill_default_options(); + fill_testing_options(); + _plg.reset(new test_plugin); + BOOST_TEST_MESSAGE("# plugin :" + _plg->name()); + _plg->initialize(_vm_opts); } ~test_options_postfix() { - plg.reset(); } }; }} @@ -58,15 +134,14 @@ typedef golos::tests::test_options_postfix test_without_ BOOST_AUTO_TEST_SUITE(options_postfix); -BOOST_AUTO_TEST_CASE(options_with_postfix) { - BOOST_TEST_MESSAGE("options_with_postfix: "); - test_with_postfix(); -} - - BOOST_AUTO_TEST_CASE(options_without_postfix) { - BOOST_TEST_MESSAGE("options_without_postfix: "); + BOOST_TEST_MESSAGE("@ options_without_postfix: "); test_without_postfix(); } +BOOST_AUTO_TEST_CASE(options_with_postfix) { + BOOST_TEST_MESSAGE("@ options_with_postfix: "); + test_with_postfix(); +} + BOOST_AUTO_TEST_SUITE_END() From 6217c22e66643951bfe7708214edd0e3953d05b3 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 13 Jun 2018 10:11:31 +0300 Subject: [PATCH 005/250] Added using database fixture. --- plugins/operation_history/plugin.cpp | 10 +- tests/plugin_tests/options_postfix.cpp | 239 +++++++++++++++++-------- 2 files changed, 172 insertions(+), 77 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index d707850a24..487f5b9812 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -179,19 +179,15 @@ namespace golos { namespace plugins { namespace operation_history { } void plugin::plugin_initialize(const boost::program_options::variables_map& options) { - ilog("###: plugin_initialize() 0"); ilog("operation_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); - ilog("###: plugin_initialize() 1"); pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ pimpl->on_operation(note); }); - ilog("###: plugin_initialize() 2"); golos::chain::add_plugin_index(pimpl->database); - ilog("###: plugin_initialize() 3"); auto split_list = [&](const std::vector& ops_list) { for (const auto& raw: ops_list) { @@ -214,24 +210,26 @@ namespace golos { namespace plugins { namespace operation_history { } } }; - ilog("###: plugin_initialize() 4"); if (options.count("history-whitelist-ops")) { + ilog("###: plugin_initialize() 1.1"); FC_ASSERT( !options.count("history-blacklist-ops"), "history-blacklist-ops and history-whitelist-ops can't be specified together"); + ilog("###: plugin_initialize() 1.2"); pimpl->filter_content = true; pimpl->blacklist = false; split_list(options.at("history-whitelist-ops").as>()); ilog("operation_history: whitelisting ops ${o}", ("o", pimpl->ops_list)); } else if (options.count("history-blacklist-ops")) { + ilog("###: plugin_initialize() 1.3"); pimpl->filter_content = true; pimpl->blacklist = true; split_list(options.at("history-blacklist-ops").as>()); ilog("operation_history: blacklisting ops ${o}", ("o", pimpl->ops_list)); } - ilog("###: plugin_initialize() 5"); + ilog("###: plugin_initialize() 2"); if (options.count("history-start-block")) { pimpl->filter_content = true; diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index c339ab1a36..929065677c 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -10,46 +10,97 @@ #include #include +#include "database_fixture.hpp" - -namespace golos { namespace tests { - +namespace golos { namespace test { namespace bpo = boost::program_options; namespace bfs = boost::filesystem; -typedef golos::plugins::operation_history::plugin test_plugin; - +typedef golos::plugins::operation_history::plugin gpoh_plugin; +typedef golos::plugins::operation_history::applied_operation applied_operation; +typedef golos::chain::database_fixture database_fixture; +//using namespace golos::protocol; + + +struct key_option_whitelist { + std::string key = "history-whitelist-ops"; +}; + + +struct key_option_blacklist { + std::string key = "history-blacklist-ops"; +}; + struct option_with_postfix { std::string opt = - "account_create_operation " \ - "account_update_operation " \ - "comment_operation " \ + "account_create_operation," \ + "account_update_operation," \ + "comment_operation," \ "delete_comment_operation"; }; struct option_without_postfix { std::string opt = - "account_create " \ - "account_update " \ - "comment " \ + "account_create," \ + "account_update," \ + "comment," \ "delete_comment"; }; -template -class test_options_postfix : public opt_type { - std::unique_ptr _plg; +template +struct test_options_postfix + : public key_opt_type + , public opt_type +{ + //std::unique_ptr _plg; bpo::options_description _cfg_opts; bpo::options_description _cli_opts; bpo::variables_map _vm_opts; + + void print_applied_opts(const applied_operation &opts) { + std::stringstream ss; + ss << opts.trx_id << ", "; /// golos::protocol::transaction_id_type + ss << opts.block << ", "; + ss << opts.trx_in_block << ", "; + ss << opts.op_in_trx << ", "; + ss << opts.virtual_op << ", "; + ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec + //ss << opts.op << "\n"; /// golos::protocol::operation + } + + void print_options(const std::vector &args) { + for (auto arg : args) { + for (auto val : arg.value) { + std::string msg("op > {" + arg.string_key + " : " + val + "}"); + BOOST_TEST_MESSAGE(msg); + } + } + } + + void print_vmap(const bpo::variables_map &vm) { + for (const auto& it : vm) { + std::stringstream ss; + ss << it.first.c_str() << " : "; + auto& value = it.second.value(); + if (auto v = boost::any_cast(&value)) { + ss << *v; + } else if (auto v = boost::any_cast(&value)) { + ss << *v; + } else { + ss << "TYPE"; + } + BOOST_TEST_MESSAGE("vm > {" + ss.str() + "}"); + } + } void fill_default_options() { bpo::options_description cfg_opts("Application Config Options"); cfg_opts.add_options() - ("plugin", bpo::value< vector >()->composing(), + ("plugin", bpo::value>()->composing(), "Plugin(s) to enable, may be specified multiple times") ; _cfg_opts.add(cfg_opts); @@ -71,53 +122,60 @@ class test_options_postfix : public opt_type { .add(_cli_opts) .add(_cfg_opts) ; - int argc = 0; - char **argv = nullptr; - bpo::store(bpo::parse_command_line(argc, argv, all_opts), _vm_opts); - bfs::path cfg_file_name = _vm_opts["config"].as(); - bfs::path cfg_dir = _vm_opts["data-dir"].as(); - cfg_file_name = cfg_dir / cfg_file_name; - if (bfs::exists(cfg_file_name)) { - bfs::remove(cfg_file_name); - } - std::ofstream out_cfg(bfs::path(cfg_file_name).make_preferred().string()); - out_cfg << "history-whitelist-ops = " << opt_type::opt << "\n"; - out_cfg << "history-blacklist-ops = " << opt_type::opt << "\n"; - bfs::path cfg_path = cfg_file_name.make_preferred(); - auto parsed_cfg = bpo::parse_config_file(cfg_path.string().c_str(), _cfg_opts, true); - //_cli_opts.add_options() - // ("history-whitelist-ops", "") - // ("history-blacklist-ops", "") - // ; - //std::string str_opts( - // "history-whitelist-ops = " + opt_type::opt + "\n" + - // "history-blacklist-ops = " + opt_type::opt + "\n"); - //std::istringstream iss_opts(str_opts); - //auto parsed_cfg = bpo::parse_config_file(iss_opts, all_opts); - //auto parsed_cfg = bpo::parse_command_line(argc, test_opt, all_options); + const char *argv = "plugin_test"; + auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); + print_options(parsed_cmd_line.options); + bpo::store(parsed_cmd_line, _vm_opts); + print_vmap(_vm_opts); + + //bfs::path cfg_file_name = _vm_opts["config"].as(); + //bfs::path cfg_dir = _vm_opts["data-dir"].as(); + //cfg_file_name = cfg_dir / cfg_file_name; + //if (bfs::exists(cfg_file_name)) { + // bfs::remove(cfg_file_name); + //} + //std::ofstream out_cfg(bfs::path(cfg_file_name).make_preferred().string()); + //out_cfg << "history-whitelist-ops = " << opt_type::opt << "\n"; + //out_cfg << "history-blacklist-ops = " << opt_type::opt << "\n"; + //bfs::path cfg_path = cfg_file_name.make_preferred(); + + std::stringstream ss_opts; + ss_opts << "history-whitelist-ops = " << opt_type::opt << "\n"; + ss_opts << "history-blacklist-ops = " << opt_type::opt << "\n"; + std::istringstream iss_opts(ss_opts.str()); + _cfg_opts.add_options() + (key_opt_type::key.c_str(), bpo::value>()) + ; + auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); + + //auto parsed_cfg = bpo::parse_config_file(cfg_path.string().c_str(), _cfg_opts, true); BOOST_TEST_MESSAGE("# PARSE OPTS"); - std::vector args = parsed_cfg.options; - for (auto arg : args) { - for (auto val : arg.value) { - std::string msg("> {" + arg.string_key + " : " + val + "}"); - BOOST_TEST_MESSAGE(msg); - } - } + print_options(parsed_cfg.options); bpo::store(parsed_cfg, _vm_opts); - bpo::notify(_vm_opts); - - if (bfs::exists(cfg_file_name)) { - bfs::remove(cfg_file_name); - } + print_vmap(_vm_opts); + //BOOST_TEST_MESSAGE((_vm_opts.count("history-whitelist-ops") ? "TRUE":"FALSE")); + //BOOST_TEST_MESSAGE((_vm_opts.count("history-blacklist-ops") ? "TRUE":"FALSE")); + + //bpo::notify(_vm_opts); + + //if (bfs::exists(cfg_file_name)) { + // bfs::remove(cfg_file_name); + //} } -public: + + //test_options_postfix(oh_plugin *oh_plg) { test_options_postfix() { fill_default_options(); fill_testing_options(); - _plg.reset(new test_plugin); - BOOST_TEST_MESSAGE("# plugin :" + _plg->name()); - _plg->initialize(_vm_opts); + //BOOST_TEST_REQUIRE(oh_plg); + //BOOST_TEST_MESSAGE("# plugin: \"" + oh_plg->name() + "\""); + //oh_plg->initialize(_vm_opts); + + //std::vector opts_list = _plg->get_ops_in_block(); + //for(auto opts : opts_list) { + // BOOST_TEST_MESSAGE("# ops_in_block :" + opts); + //} } ~test_options_postfix() { @@ -125,23 +183,62 @@ class test_options_postfix : public opt_type { }; }} +using namespace golos::test; + +typedef option_with_postfix opt_with_postfix; +typedef option_without_postfix opt_without_postfix; +typedef key_option_whitelist key_opt_whitelist; +typedef key_option_blacklist key_opt_blacklist; +typedef test_options_postfix test_white_with_postfix; +typedef test_options_postfix test_white_without_postfix; +typedef test_options_postfix test_black_with_postfix; +typedef test_options_postfix test_black_without_postfix; +//typedef std::unique_ptr ptest_white_with_postfix; +//typedef std::unique_ptr ptest_white_without_postfix; +//typedef std::unique_ptr ptest_black_with_postfix; +//typedef std::unique_ptr ptest_black_without_postfix; + + +//BOOST_AUTO_TEST_SUITE(options_postfix); +BOOST_FIXTURE_TEST_SUITE(options_postfix, database_fixture); + + BOOST_AUTO_TEST_CASE(options_white_with_postfix) { + BOOST_TEST_MESSAGE("\n@ white options with postfix: "); + try { + test_white_with_postfix o; + //appbase::app().add_program_options(o._cli_opts, o._cfg_opts); + gpoh_plugin *plg = &appbase::app().register_plugin(); + + //initialize(); + BOOST_TEST_REQUIRE(plg); + BOOST_TEST_MESSAGE("# plugin: \"" + plg->name() + "\""); + plg->initialize(o._vm_opts); + //plg->initialize(getVmOptions()); + //ptest_white_with_postfix test_obj(new test_white_with_postfix(plg)); + //test_white_with_postfix(plg); + //open_database(); + //close_database(); + } FC_LOG_AND_RETHROW(); + } -typedef golos::tests::option_with_postfix option_with_postfix; -typedef golos::tests::option_without_postfix option_without_postfix; -typedef golos::tests::test_options_postfix test_with_postfix; -typedef golos::tests::test_options_postfix test_without_postfix; - - -BOOST_AUTO_TEST_SUITE(options_postfix); + //BOOST_AUTO_TEST_CASE(options_white_without_postfix) { + // BOOST_TEST_MESSAGE("\n@ white options without postfix: "); + // //test_white_with_postfix(); + //} + // + //BOOST_AUTO_TEST_CASE(options_black_with_postfix) { + // BOOST_TEST_MESSAGE("\n@ black options with postfix: "); + // //test_black_without_postfix(); + //} + // + //BOOST_AUTO_TEST_CASE(options_black_without_postfix) { + // BOOST_TEST_MESSAGE("\n@ black options without postfix: "); + // //test_black_with_postfix(); + //} -BOOST_AUTO_TEST_CASE(options_without_postfix) { - BOOST_TEST_MESSAGE("@ options_without_postfix: "); - test_without_postfix(); -} +BOOST_AUTO_TEST_SUITE_END() -BOOST_AUTO_TEST_CASE(options_with_postfix) { - BOOST_TEST_MESSAGE("@ options_with_postfix: "); - test_with_postfix(); -} -BOOST_AUTO_TEST_SUITE_END() +// - там есть настройка history-start-block - это номер блока до которого не хранить историю +// - хранить историю только за последний день, неделю, месяц это более удобно потому, +// что делегатов сейчас интересует только последняя история операций. From 5be9e2607d9aff945016bcd2175b18950161e9d1 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 13 Jun 2018 18:00:29 +0300 Subject: [PATCH 006/250] Added various options for the plug-in list operations. --- plugins/operation_history/plugin.cpp | 11 +-- tests/plugin_tests/options_postfix.cpp | 111 ++++++++----------------- 2 files changed, 37 insertions(+), 85 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 487f5b9812..6d914e280a 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -196,15 +196,12 @@ namespace golos { namespace plugins { namespace operation_history { for (const auto& op : ops) { if (op.size()) { - ilog("#: opt ${s}", ("s", op)); std::string ops_postfix("_operation"); std::size_t pos = op.find(ops_postfix); if (pos not_eq std::string::npos and (pos + ops_postfix.size()) == op.size()) { - ilog("#: without opt ${s}", ("s", STEEM_NAMESPACE_PREFIX + op + ops_postfix)); - pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); - } else { - ilog("#: with opt ${s}", ("s", STEEM_NAMESPACE_PREFIX + op)); pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op); + } else { + pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); } } } @@ -212,24 +209,20 @@ namespace golos { namespace plugins { namespace operation_history { }; if (options.count("history-whitelist-ops")) { - ilog("###: plugin_initialize() 1.1"); FC_ASSERT( !options.count("history-blacklist-ops"), "history-blacklist-ops and history-whitelist-ops can't be specified together"); - ilog("###: plugin_initialize() 1.2"); pimpl->filter_content = true; pimpl->blacklist = false; split_list(options.at("history-whitelist-ops").as>()); ilog("operation_history: whitelisting ops ${o}", ("o", pimpl->ops_list)); } else if (options.count("history-blacklist-ops")) { - ilog("###: plugin_initialize() 1.3"); pimpl->filter_content = true; pimpl->blacklist = true; split_list(options.at("history-blacklist-ops").as>()); ilog("operation_history: blacklisting ops ${o}", ("o", pimpl->ops_list)); } - ilog("###: plugin_initialize() 2"); if (options.count("history-start-block")) { pimpl->filter_content = true; diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index 929065677c..0eccb7352f 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -9,6 +9,7 @@ #include #include +//#include #include #include "database_fixture.hpp" @@ -17,10 +18,11 @@ namespace golos { namespace test { namespace bpo = boost::program_options; namespace bfs = boost::filesystem; +typedef golos::chain::database_fixture database_fixture; typedef golos::plugins::operation_history::plugin gpoh_plugin; typedef golos::plugins::operation_history::applied_operation applied_operation; -typedef golos::chain::database_fixture database_fixture; -//using namespace golos::protocol; +typedef golos::plugins::chain::plugin chain_plugin; +typedef golos::plugins::json_rpc::plugin json_rpc_plugin; struct key_option_whitelist { @@ -56,7 +58,6 @@ struct test_options_postfix : public key_opt_type , public opt_type { - //std::unique_ptr _plg; bpo::options_description _cfg_opts; bpo::options_description _cli_opts; bpo::variables_map _vm_opts; @@ -122,23 +123,12 @@ struct test_options_postfix .add(_cli_opts) .add(_cfg_opts) ; - const char *argv = "plugin_test"; + const char *argv = "plugin"; auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); print_options(parsed_cmd_line.options); bpo::store(parsed_cmd_line, _vm_opts); print_vmap(_vm_opts); - //bfs::path cfg_file_name = _vm_opts["config"].as(); - //bfs::path cfg_dir = _vm_opts["data-dir"].as(); - //cfg_file_name = cfg_dir / cfg_file_name; - //if (bfs::exists(cfg_file_name)) { - // bfs::remove(cfg_file_name); - //} - //std::ofstream out_cfg(bfs::path(cfg_file_name).make_preferred().string()); - //out_cfg << "history-whitelist-ops = " << opt_type::opt << "\n"; - //out_cfg << "history-blacklist-ops = " << opt_type::opt << "\n"; - //bfs::path cfg_path = cfg_file_name.make_preferred(); - std::stringstream ss_opts; ss_opts << "history-whitelist-ops = " << opt_type::opt << "\n"; ss_opts << "history-blacklist-ops = " << opt_type::opt << "\n"; @@ -147,35 +137,15 @@ struct test_options_postfix (key_opt_type::key.c_str(), bpo::value>()) ; auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); - - //auto parsed_cfg = bpo::parse_config_file(cfg_path.string().c_str(), _cfg_opts, true); - BOOST_TEST_MESSAGE("# PARSE OPTS"); print_options(parsed_cfg.options); bpo::store(parsed_cfg, _vm_opts); print_vmap(_vm_opts); - //BOOST_TEST_MESSAGE((_vm_opts.count("history-whitelist-ops") ? "TRUE":"FALSE")); - //BOOST_TEST_MESSAGE((_vm_opts.count("history-blacklist-ops") ? "TRUE":"FALSE")); - - //bpo::notify(_vm_opts); - - //if (bfs::exists(cfg_file_name)) { - // bfs::remove(cfg_file_name); - //} } - //test_options_postfix(oh_plugin *oh_plg) { test_options_postfix() { fill_default_options(); fill_testing_options(); - //BOOST_TEST_REQUIRE(oh_plg); - //BOOST_TEST_MESSAGE("# plugin: \"" + oh_plg->name() + "\""); - //oh_plg->initialize(_vm_opts); - - //std::vector opts_list = _plg->get_ops_in_block(); - //for(auto opts : opts_list) { - // BOOST_TEST_MESSAGE("# ops_in_block :" + opts); - //} } ~test_options_postfix() { @@ -193,52 +163,41 @@ typedef test_options_postfix test_white_wit typedef test_options_postfix test_white_without_postfix; typedef test_options_postfix test_black_with_postfix; typedef test_options_postfix test_black_without_postfix; -//typedef std::unique_ptr ptest_white_with_postfix; -//typedef std::unique_ptr ptest_white_without_postfix; -//typedef std::unique_ptr ptest_black_with_postfix; -//typedef std::unique_ptr ptest_black_without_postfix; -//BOOST_AUTO_TEST_SUITE(options_postfix); BOOST_FIXTURE_TEST_SUITE(options_postfix, database_fixture); - BOOST_AUTO_TEST_CASE(options_white_with_postfix) { + BOOST_AUTO_TEST_CASE(options_postfix_case) try { BOOST_TEST_MESSAGE("\n@ white options with postfix: "); - try { - test_white_with_postfix o; - //appbase::app().add_program_options(o._cli_opts, o._cfg_opts); - gpoh_plugin *plg = &appbase::app().register_plugin(); - - //initialize(); - BOOST_TEST_REQUIRE(plg); - BOOST_TEST_MESSAGE("# plugin: \"" + plg->name() + "\""); - plg->initialize(o._vm_opts); - //plg->initialize(getVmOptions()); - //ptest_white_with_postfix test_obj(new test_white_with_postfix(plg)); - //test_white_with_postfix(plg); - //open_database(); - //close_database(); - } FC_LOG_AND_RETHROW(); - } - - //BOOST_AUTO_TEST_CASE(options_white_without_postfix) { - // BOOST_TEST_MESSAGE("\n@ white options without postfix: "); - // //test_white_with_postfix(); - //} - // - //BOOST_AUTO_TEST_CASE(options_black_with_postfix) { - // BOOST_TEST_MESSAGE("\n@ black options with postfix: "); - // //test_black_without_postfix(); - //} - // - //BOOST_AUTO_TEST_CASE(options_black_without_postfix) { - // BOOST_TEST_MESSAGE("\n@ black options without postfix: "); - // //test_black_with_postfix(); - //} + int argc = boost::unit_test::framework::master_test_suite().argc; + char **argv = boost::unit_test::framework::master_test_suite().argv; + for (int i = 1; i < argc; i++) { + const std::string arg = argv[i]; + if (arg == "--record-assert-trip") { + fc::enable_record_assert_trip = true; + } + if (arg == "--show-test-names") { + std::cout << "running test " + << boost::unit_test::framework::current_test_case().p_name + << std::endl; + } + } + gpoh_plugin *plg = &appbase::app().register_plugin(); + BOOST_TEST_REQUIRE(plg); + appbase::app().initialize(argc, argv); -BOOST_AUTO_TEST_SUITE_END() + test_white_with_postfix wwo; + plg->plugin_initialize(wwo._vm_opts); + + test_white_without_postfix woo; + plg->plugin_initialize(woo._vm_opts); + test_black_with_postfix bwo; + plg->plugin_initialize(bwo._vm_opts); + + test_black_without_postfix boo; + plg->plugin_initialize(boo._vm_opts); + } + FC_LOG_AND_RETHROW(); -// - там есть настройка history-start-block - это номер блока до которого не хранить историю -// - хранить историю только за последний день, неделю, месяц это более удобно потому, -// что делегатов сейчас интересует только последняя история операций. +BOOST_AUTO_TEST_SUITE_END() From 49680126d05f3f897775ab6322b0dfcfdc635795 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 15 Jun 2018 10:10:43 +0300 Subject: [PATCH 007/250] Added the transaction creation. --- tests/plugin_tests/options_postfix.cpp | 250 ++++++++++++++++++++----- 1 file changed, 200 insertions(+), 50 deletions(-) diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index 0eccb7352f..182a147f99 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -9,20 +9,49 @@ #include #include -//#include #include +#include + #include "database_fixture.hpp" +#include "comment_reward.hpp" namespace golos { namespace test { + namespace bpo = boost::program_options; namespace bfs = boost::filesystem; -typedef golos::chain::database_fixture database_fixture; +typedef golos::chain::clean_database_fixture clean_database_fixture; +typedef golos::chain::database database; typedef golos::plugins::operation_history::plugin gpoh_plugin; typedef golos::plugins::operation_history::applied_operation applied_operation; typedef golos::plugins::chain::plugin chain_plugin; typedef golos::plugins::json_rpc::plugin json_rpc_plugin; +typedef golos::plugins::json_rpc::msg_pack msg_pack; + + +struct app_initialise { + gpoh_plugin *_plg; + + app_initialise() { + int argc = boost::unit_test::framework::master_test_suite().argc; + char **argv = boost::unit_test::framework::master_test_suite().argv; + for (int i = 1; i < argc; i++) { + const std::string arg = argv[i]; + if (arg == "--record-assert-trip") { + fc::enable_record_assert_trip = true; + } + if (arg == "--show-test-names") { + std::cout << "running test " + << boost::unit_test::framework::current_test_case().p_name + << std::endl; + } + } + _plg = &appbase::app().register_plugin(); + BOOST_TEST_REQUIRE(_plg); + appbase::app().initialize(argc, argv); + } +}; struct key_option_whitelist { @@ -38,7 +67,7 @@ struct key_option_blacklist { struct option_with_postfix { std::string opt = "account_create_operation," \ - "account_update_operation," \ + "vote_operation," \ "comment_operation," \ "delete_comment_operation"; }; @@ -47,7 +76,7 @@ struct option_with_postfix { struct option_without_postfix { std::string opt = "account_create," \ - "account_update," \ + "vote," \ "comment," \ "delete_comment"; }; @@ -62,17 +91,6 @@ struct test_options_postfix bpo::options_description _cli_opts; bpo::variables_map _vm_opts; - void print_applied_opts(const applied_operation &opts) { - std::stringstream ss; - ss << opts.trx_id << ", "; /// golos::protocol::transaction_id_type - ss << opts.block << ", "; - ss << opts.trx_in_block << ", "; - ss << opts.op_in_trx << ", "; - ss << opts.virtual_op << ", "; - ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec - //ss << opts.op << "\n"; /// golos::protocol::operation - } - void print_options(const std::vector &args) { for (auto arg : args) { for (auto val : arg.value) { @@ -127,7 +145,7 @@ struct test_options_postfix auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); print_options(parsed_cmd_line.options); bpo::store(parsed_cmd_line, _vm_opts); - print_vmap(_vm_opts); + //print_vmap(_vm_opts); std::stringstream ss_opts; ss_opts << "history-whitelist-ops = " << opt_type::opt << "\n"; @@ -139,7 +157,7 @@ struct test_options_postfix auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); print_options(parsed_cfg.options); bpo::store(parsed_cfg, _vm_opts); - print_vmap(_vm_opts); + //print_vmap(_vm_opts); } @@ -148,7 +166,144 @@ struct test_options_postfix fill_testing_options(); } - ~test_options_postfix() { + operator bpo::variables_map () const { + return _vm_opts; + } + + bool check_applied_options(const applied_operation &opts) const { + std::stringstream ss; + ss << opts.trx_id << ", "; /// golos::protocol::transaction_id_type + ss << opts.block << ", "; + ss << opts.trx_in_block << ", "; + ss << opts.op_in_trx << ", "; + ss << opts.virtual_op << ", "; + ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec + //ss << opts.op << "\n"; /// golos::protocol::operation + BOOST_TEST_MESSAGE(ss.str()); + return true; + } + +}; + + +using namespace golos::protocol; +using namespace golos::chain; + +struct transaction_fixture : clean_database_fixture { + gpoh_plugin *_plg; + + template + void check_operations(const test_type &tt) { + BOOST_TEST_MESSAGE("Check history operations."); + msg_pack msg; + msg.args = std::vector({fc::variant(1), fc::variant(false)}); + auto ops = _plg->get_ops_in_block(msg); + BOOST_TEST_MESSAGE("Operations is " + std::to_string(ops.size())); + size_t count = 0; + for (auto o : ops) { + tt.check_applied_options(o); + //if (o.which() == operation::tag::value) { + BOOST_TEST_MESSAGE("comment_operation " + std::to_string(++count) + " " + + std::to_string(operation::tag::value)); + + //auto &top = o.get(); + //top.memo = decrypt_memo(top.memo); + //} + } + } + + template + void execute(const test_type &tt) { + _plg = app_initialise()._plg; + _plg->plugin_initialize(tt); + _plg->plugin_startup(); + init_database(); + init_transactions(); + check_operations(tt); + close_database(); + } + + void init_database() { + clean_database_fixture::initialize(); + } + + void init_transactions() { + BOOST_TEST_MESSAGE("Init transactions"); + + ACTORS((alice)(bob)(sam)) + fund("alice", 10000); + vest("alice", 10000); + fund("bob", 7500); + vest("bob", 7500); + fund("sam", 8000); + vest("sam", 8000); + + db->set_clear_votes(0xFFFFFFFF); + + signed_transaction tx; + + BOOST_TEST_MESSAGE("Creating comments."); + comment_operation com; + com.author = "bob"; + com.permlink = "test"; + com.parent_author = ""; + com.parent_permlink = "test"; + com.title = "foo"; + com.body = "bar"; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(com); + tx.sign(bob_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + tx.operations.clear(); + tx.signatures.clear(); + + BOOST_TEST_MESSAGE("Voting for comments."); + vote_operation vote; + vote.voter = "alice"; + vote.author = "bob"; + vote.permlink = "test"; + vote.weight = -1; ///< Nessary for the posiblity of delet_comment_operation. + tx.operations.push_back(vote); + vote.voter = "bob"; + tx.operations.push_back(vote); + vote.voter = "sam"; + tx.operations.push_back(vote); + tx.sign(alice_private_key, db->get_chain_id()); + tx.sign(bob_private_key, db->get_chain_id()); + tx.sign(sam_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + tx.operations.clear(); + tx.signatures.clear(); + + BOOST_TEST_MESSAGE("Deleting comment."); + delete_comment_operation dco; + dco.author = "bob"; + dco.permlink = "test"; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(dco); + tx.sign(bob_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + tx.operations.clear(); + tx.signatures.clear(); + + BOOST_TEST_MESSAGE("Generate accaunt."); + account_create_operation aco; + aco.new_account_name = "dave"; + aco.creator = STEEMIT_INIT_MINER_NAME; + aco.owner = authority(1, init_account_pub_key, 1); + aco.active = aco.owner; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(aco); + tx.sign(init_account_priv_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + tx.operations.clear(); + tx.signatures.clear(); + + validate_database(); } }; }} @@ -165,39 +320,34 @@ typedef test_options_postfix test_black_wit typedef test_options_postfix test_black_without_postfix; -BOOST_FIXTURE_TEST_SUITE(options_postfix, database_fixture); +BOOST_AUTO_TEST_SUITE(options_postfix) - BOOST_AUTO_TEST_CASE(options_postfix_case) try { - BOOST_TEST_MESSAGE("\n@ white options with postfix: "); - int argc = boost::unit_test::framework::master_test_suite().argc; - char **argv = boost::unit_test::framework::master_test_suite().argv; - for (int i = 1; i < argc; i++) { - const std::string arg = argv[i]; - if (arg == "--record-assert-trip") { - fc::enable_record_assert_trip = true; - } - if (arg == "--show-test-names") { - std::cout << "running test " - << boost::unit_test::framework::current_test_case().p_name - << std::endl; - } - } - gpoh_plugin *plg = &appbase::app().register_plugin(); - BOOST_TEST_REQUIRE(plg); - appbase::app().initialize(argc, argv); - - test_white_with_postfix wwo; - plg->plugin_initialize(wwo._vm_opts); - - test_white_without_postfix woo; - plg->plugin_initialize(woo._vm_opts); + BOOST_FIXTURE_TEST_CASE(white_options_with_postfix, transaction_fixture) try { + execute(test_white_with_postfix()); + } FC_LOG_AND_RETHROW(); - test_black_with_postfix bwo; - plg->plugin_initialize(bwo._vm_opts); - - test_black_without_postfix boo; - plg->plugin_initialize(boo._vm_opts); - } - FC_LOG_AND_RETHROW(); + BOOST_FIXTURE_TEST_CASE(white_options_without_postfix, transaction_fixture) try { + _plg = app_initialise()._plg; + _plg->plugin_initialize(test_white_without_postfix()); + _plg->plugin_startup(); + init_database(); + } FC_LOG_AND_RETHROW(); + + BOOST_FIXTURE_TEST_CASE(black_options_with_postfix, transaction_fixture) try { + _plg = app_initialise()._plg; + _plg->plugin_initialize(test_black_with_postfix()); + _plg->plugin_startup(); + } FC_LOG_AND_RETHROW(); + + BOOST_FIXTURE_TEST_CASE(black_options_without_postfix, transaction_fixture) try { + _plg = app_initialise()._plg; + _plg->plugin_initialize(test_black_without_postfix()); + _plg->plugin_startup(); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() + + +// - там есть настройка history-start-block - это номер блока до которого не хранить историю +// - хранить историю только за последний день, неделю, месяц это более удобно потому, +// что делегатов сейчас интересует только последняя история операций. From 5cc79d48713de8eb94c975a20d6776e7252b19a9 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Mon, 18 Jun 2018 12:35:30 +0300 Subject: [PATCH 008/250] Try fix restart database_fixture in one test. --- tests/plugin_tests/options_postfix.cpp | 155 ++++++++++++++++--------- 1 file changed, 100 insertions(+), 55 deletions(-) diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index 182a147f99..fb047bd8a1 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -22,6 +22,7 @@ namespace bpo = boost::program_options; namespace bfs = boost::filesystem; typedef golos::chain::clean_database_fixture clean_database_fixture; +typedef golos::chain::database_fixture database_fixture; typedef golos::chain::database database; typedef golos::plugins::operation_history::plugin gpoh_plugin; typedef golos::plugins::operation_history::applied_operation applied_operation; @@ -170,6 +171,15 @@ struct test_options_postfix return _vm_opts; } + struct operation_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + return std::string(fc::get_typename::name()); + } + } ovisit; + + bool check_applied_options(const applied_operation &opts) const { std::stringstream ss; ss << opts.trx_id << ", "; /// golos::protocol::transaction_id_type @@ -178,7 +188,7 @@ struct test_options_postfix ss << opts.op_in_trx << ", "; ss << opts.virtual_op << ", "; ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec - //ss << opts.op << "\n"; /// golos::protocol::operation + ss << "which is [" << opts.op.visit(ovisit) << "]"; /// golos::protocol::operation BOOST_TEST_MESSAGE(ss.str()); return true; } @@ -189,45 +199,32 @@ struct test_options_postfix using namespace golos::protocol; using namespace golos::chain; -struct transaction_fixture : clean_database_fixture { + +//struct transaction_fixture { +template +//struct transaction_fixture : clean_database_fixture { +struct transaction_fixture : database_fixture { + test_type _tt; gpoh_plugin *_plg; - template - void check_operations(const test_type &tt) { - BOOST_TEST_MESSAGE("Check history operations."); - msg_pack msg; - msg.args = std::vector({fc::variant(1), fc::variant(false)}); - auto ops = _plg->get_ops_in_block(msg); - BOOST_TEST_MESSAGE("Operations is " + std::to_string(ops.size())); - size_t count = 0; - for (auto o : ops) { - tt.check_applied_options(o); - //if (o.which() == operation::tag::value) { - BOOST_TEST_MESSAGE("comment_operation " + std::to_string(++count) + " " - + std::to_string(operation::tag::value)); - - //auto &top = o.get(); - //top.memo = decrypt_memo(top.memo); - //} - } - } - - template - void execute(const test_type &tt) { - _plg = app_initialise()._plg; - _plg->plugin_initialize(tt); - _plg->plugin_startup(); - init_database(); - init_transactions(); - check_operations(tt); - close_database(); + transaction_fixture(const test_type &tt) + : _tt(tt) { + BOOST_TEST_MESSAGE("Create transactions"); + try { + database_fixture::initialize(); + database_fixture::open_database(); + database_fixture::startup(); + + _plg = app_initialise()._plg; + _plg->plugin_initialize(_tt); + _plg->plugin_startup(); + + add_operations(); + check_operations(); + } FC_LOG_AND_RETHROW(); } - void init_database() { - clean_database_fixture::initialize(); - } - - void init_transactions() { + void add_operations() { BOOST_TEST_MESSAGE("Init transactions"); ACTORS((alice)(bob)(sam)) @@ -305,6 +302,67 @@ struct transaction_fixture : clean_database_fixture { validate_database(); } + + void check_operations() { + BOOST_TEST_MESSAGE("Check history operations."); + //msg_pack mt; + //mt.args = std::vector({fc::variant(1)}); + //auto trans = _plg->get_transaction(mt); + //const auto& idx = database.get_index().indices().get(); + + msg_pack mo; + //mo.args = std::vector({fc::variant(trans.block_num), fc::variant(true)}); + mo.args = std::vector({fc::variant(1), fc::variant(true)}); + auto ops = _plg->get_ops_in_block(mo); + BOOST_TEST_MESSAGE("Checked perations is " + std::to_string(ops.size()) + " {"); + BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + + "] account_create_operation"); + BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + + "] vote_operation"); + BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + + "] comment_operation"); + BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + + "] delete_comment_operation"); + BOOST_TEST_MESSAGE("}"); + + //size_t count = 0; + for (auto o : ops) { + _tt.check_applied_options(o); + + //fc::variant v(o.op); + //fc::variant v; + //fc::to_variant(o.op, v); + + //BOOST_TEST_MESSAGE("type name[" + std::to_string(++count) + "]: " + o.op.visit(ovisit)); + //BOOST_TEST_MESSAGE("type name[" + std::to_string(++count) + "]: " + v.get_type().name_from_type); + + //BOOST_TEST_MESSAGE(std::string("is marcet: ") + (o.is_market_operation() ? "TRUE":"FALSE")); + //fc::variant v; + //fc::to_variant(o.op, v); + //BOOST_TEST_MESSAGE("witch = " + std::to_string(v.which())); + //fc::get_operation_name on; + //std::string op_name = on(o).name; + //BOOST_TEST_MESSAGE("validate: " + (is_market_operation(o) ? "TRUE":"FALSE")); + //if (o.op.which() == operation::tag::value) {} + // + // BOOST_TEST_MESSAGE("comment_operation " + std::to_string(++count) + " " + // + std::to_string(operation::tag::value)); + + //auto &top = o.get(); + //top.memo = decrypt_memo(top.memo); + //} + } + } +}; + + +template +struct execute_fixture { + execute_fixture() { + BOOST_TEST_MESSAGE("Execute"); + typedef transaction_fixture transaction; + std::unique_ptr trans(new transaction(test_type())); + } }; }} @@ -322,28 +380,13 @@ typedef test_options_postfix test_black_ BOOST_AUTO_TEST_SUITE(options_postfix) - BOOST_FIXTURE_TEST_CASE(white_options_with_postfix, transaction_fixture) try { - execute(test_white_with_postfix()); - } FC_LOG_AND_RETHROW(); + BOOST_FIXTURE_TEST_CASE(white_options_with_postfix, execute_fixture) {} - BOOST_FIXTURE_TEST_CASE(white_options_without_postfix, transaction_fixture) try { - _plg = app_initialise()._plg; - _plg->plugin_initialize(test_white_without_postfix()); - _plg->plugin_startup(); - init_database(); - } FC_LOG_AND_RETHROW(); + BOOST_FIXTURE_TEST_CASE(white_options_without_postfix, execute_fixture) {} - BOOST_FIXTURE_TEST_CASE(black_options_with_postfix, transaction_fixture) try { - _plg = app_initialise()._plg; - _plg->plugin_initialize(test_black_with_postfix()); - _plg->plugin_startup(); - } FC_LOG_AND_RETHROW(); + BOOST_FIXTURE_TEST_CASE(black_options_with_postfix, execute_fixture) {} - BOOST_FIXTURE_TEST_CASE(black_options_without_postfix, transaction_fixture) try { - _plg = app_initialise()._plg; - _plg->plugin_initialize(test_black_without_postfix()); - _plg->plugin_startup(); - } FC_LOG_AND_RETHROW(); + BOOST_FIXTURE_TEST_CASE(black_options_without_postfix, execute_fixture) {} BOOST_AUTO_TEST_SUITE_END() @@ -351,3 +394,5 @@ BOOST_AUTO_TEST_SUITE_END() // - там есть настройка history-start-block - это номер блока до которого не хранить историю // - хранить историю только за последний день, неделю, месяц это более удобно потому, // что делегатов сейчас интересует только последняя история операций. + + From 55f7182e8b27bd303e4de2a12424358cc1c3bc7b Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Tue, 19 Jun 2018 16:42:20 +0300 Subject: [PATCH 009/250] Added check returned operations test. --- tests/plugin_tests/options_postfix.cpp | 109 ++++++++++++------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index fb047bd8a1..17fff03cbd 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,8 @@ #include "database_fixture.hpp" #include "comment_reward.hpp" +#define STEEM_NAMESPACE_PREFIX std::string("golos::protocol::") + namespace golos { namespace test { @@ -24,12 +27,21 @@ namespace bfs = boost::filesystem; typedef golos::chain::clean_database_fixture clean_database_fixture; typedef golos::chain::database_fixture database_fixture; typedef golos::chain::database database; -typedef golos::plugins::operation_history::plugin gpoh_plugin; -typedef golos::plugins::operation_history::applied_operation applied_operation; + typedef golos::plugins::chain::plugin chain_plugin; typedef golos::plugins::json_rpc::plugin json_rpc_plugin; typedef golos::plugins::json_rpc::msg_pack msg_pack; +typedef golos::plugins::operation_history::plugin gpoh_plugin; +typedef golos::plugins::operation_history::applied_operation applied_operation; +typedef golos::plugins::operation_history::operation_index operation_index; +typedef golos::plugins::operation_history::operation_index by_location; +typedef golos::plugins::operation_history::annotated_signed_transaction annotated_signed_transaction; +typedef golos::plugins::operation_history::by_transaction_id by_transaction_id; + +typedef std::pair chacked_operation; ///< [itx_id], [operation name] +typedef std::map chacked_operation_map; ///< pair { [itx_id], [operation name] } + struct app_initialise { gpoh_plugin *_plg; @@ -180,19 +192,19 @@ struct test_options_postfix } ovisit; - bool check_applied_options(const applied_operation &opts) const { + chacked_operation print_applied_options(const applied_operation &opts) const { std::stringstream ss; - ss << opts.trx_id << ", "; /// golos::protocol::transaction_id_type + ss << opts.trx_id.str() << ", "; /// golos::protocol::transaction_id_type ss << opts.block << ", "; ss << opts.trx_in_block << ", "; ss << opts.op_in_trx << ", "; ss << opts.virtual_op << ", "; ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec - ss << "which is [" << opts.op.visit(ovisit) << "]"; /// golos::protocol::operation + std::string op_name = opts.op.visit(ovisit); + ss << "which is [" << op_name << "]"; /// golos::protocol::operation BOOST_TEST_MESSAGE(ss.str()); - return true; + return chacked_operation(opts.trx_id.str(), op_name); } - }; @@ -200,12 +212,12 @@ using namespace golos::protocol; using namespace golos::chain; -//struct transaction_fixture { template -//struct transaction_fixture : clean_database_fixture { struct transaction_fixture : database_fixture { test_type _tt; gpoh_plugin *_plg; + chacked_operation_map _finded_ops; + chacked_operation_map _chacked_ops; transaction_fixture(const test_type &tt) : _tt(tt) { @@ -252,6 +264,7 @@ struct transaction_fixture : database_fixture { tx.sign(bob_private_key, db->get_chain_id()); db->push_transaction(tx, 0); generate_block(); + _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "comment_operation")); tx.operations.clear(); tx.signatures.clear(); @@ -271,6 +284,7 @@ struct transaction_fixture : database_fixture { tx.sign(sam_private_key, db->get_chain_id()); db->push_transaction(tx, 0); generate_block(); + _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "vote_operation")); tx.operations.clear(); tx.signatures.clear(); @@ -283,6 +297,7 @@ struct transaction_fixture : database_fixture { tx.sign(bob_private_key, db->get_chain_id()); db->push_transaction(tx, 0); generate_block(); + _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "delete_comment_operation")); tx.operations.clear(); tx.signatures.clear(); @@ -297,61 +312,44 @@ struct transaction_fixture : database_fixture { tx.sign(init_account_priv_key, db->get_chain_id()); db->push_transaction(tx, 0); generate_block(); + _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "account_create_operation")); tx.operations.clear(); tx.signatures.clear(); validate_database(); } + void check_operations() { BOOST_TEST_MESSAGE("Check history operations."); - //msg_pack mt; - //mt.args = std::vector({fc::variant(1)}); - //auto trans = _plg->get_transaction(mt); - //const auto& idx = database.get_index().indices().get(); - - msg_pack mo; - //mo.args = std::vector({fc::variant(trans.block_num), fc::variant(true)}); - mo.args = std::vector({fc::variant(1), fc::variant(true)}); - auto ops = _plg->get_ops_in_block(mo); - BOOST_TEST_MESSAGE("Checked perations is " + std::to_string(ops.size()) + " {"); - BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + - "] account_create_operation"); - BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + - "] vote_operation"); - BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + - "] comment_operation"); - BOOST_TEST_MESSAGE("\t[" + std::to_string(operation::tag::value) + - "] delete_comment_operation"); - BOOST_TEST_MESSAGE("}"); - - //size_t count = 0; - for (auto o : ops) { - _tt.check_applied_options(o); - - //fc::variant v(o.op); - //fc::variant v; - //fc::to_variant(o.op, v); - - //BOOST_TEST_MESSAGE("type name[" + std::to_string(++count) + "]: " + o.op.visit(ovisit)); - //BOOST_TEST_MESSAGE("type name[" + std::to_string(++count) + "]: " + v.get_type().name_from_type); - - //BOOST_TEST_MESSAGE(std::string("is marcet: ") + (o.is_market_operation() ? "TRUE":"FALSE")); - //fc::variant v; - //fc::to_variant(o.op, v); - //BOOST_TEST_MESSAGE("witch = " + std::to_string(v.which())); - //fc::get_operation_name on; - //std::string op_name = on(o).name; - //BOOST_TEST_MESSAGE("validate: " + (is_market_operation(o) ? "TRUE":"FALSE")); - //if (o.op.which() == operation::tag::value) {} - // - // BOOST_TEST_MESSAGE("comment_operation " + std::to_string(++count) + " " - // + std::to_string(operation::tag::value)); - - //auto &top = o.get(); - //top.memo = decrypt_memo(top.memo); - //} + uint32_t head_block_num = db->head_block_num(); + BOOST_TEST_MESSAGE("Head block num is " + std::to_string(head_block_num)); + for (uint32_t i = 0; i < head_block_num; ++i) { + msg_pack mo; + mo.args = std::vector({fc::variant(i), fc::variant(false)}); + auto ops = _plg->get_ops_in_block(mo); + BOOST_TEST_MESSAGE("Checked operations is " + std::to_string(ops.size())); + for (auto o : ops) { + auto ch_op = _tt.print_applied_options(o); + auto iter = _finded_ops.find(ch_op.first); + if (iter == _finded_ops.end()) { + _finded_ops.insert(ch_op); + } + } } + size_t _chacked_ops_count = 0; + for (const auto &co : _chacked_ops) { + auto iter = _finded_ops.find(co.first); + bool is_finded = (iter not_eq _finded_ops.end()); + BOOST_CHECK(is_finded); + if (is_finded) { + BOOST_CHECK_EQUAL(iter->second, co.second); + if (iter->second == co.second) { + ++_chacked_ops_count; + } + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, _chacked_ops.size()); } }; @@ -366,6 +364,7 @@ struct execute_fixture { }; }} + using namespace golos::test; typedef option_with_postfix opt_with_postfix; From 9ec264f45ee6e8570600ae191049baa29c7d15a4 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 20 Jun 2018 08:55:20 +0300 Subject: [PATCH 010/250] Check operation test is complete. --- tests/plugin_tests/options_postfix.cpp | 33 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp index 17fff03cbd..9ba33ca333 100644 --- a/tests/plugin_tests/options_postfix.cpp +++ b/tests/plugin_tests/options_postfix.cpp @@ -34,9 +34,10 @@ typedef golos::plugins::json_rpc::msg_pack msg_pack; typedef golos::plugins::operation_history::plugin gpoh_plugin; typedef golos::plugins::operation_history::applied_operation applied_operation; -typedef golos::plugins::operation_history::operation_index operation_index; -typedef golos::plugins::operation_history::operation_index by_location; typedef golos::plugins::operation_history::annotated_signed_transaction annotated_signed_transaction; +typedef golos::plugins::operation_history::operation_index operation_index; +typedef golos::plugins::operation_history::by_location by_location; +typedef golos::plugins::operation_history::operation_object operation_object; typedef golos::plugins::operation_history::by_transaction_id by_transaction_id; typedef std::pair chacked_operation; ///< [itx_id], [operation name] @@ -225,12 +226,13 @@ struct transaction_fixture : database_fixture { try { database_fixture::initialize(); database_fixture::open_database(); - database_fixture::startup(); _plg = app_initialise()._plg; _plg->plugin_initialize(_tt); _plg->plugin_startup(); - + + database_fixture::startup(); + add_operations(); check_operations(); } FC_LOG_AND_RETHROW(); @@ -251,7 +253,6 @@ struct transaction_fixture : database_fixture { signed_transaction tx; - BOOST_TEST_MESSAGE("Creating comments."); comment_operation com; com.author = "bob"; com.permlink = "test"; @@ -265,10 +266,10 @@ struct transaction_fixture : database_fixture { db->push_transaction(tx, 0); generate_block(); _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "comment_operation")); + BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " comment_operation"); tx.operations.clear(); tx.signatures.clear(); - BOOST_TEST_MESSAGE("Voting for comments."); vote_operation vote; vote.voter = "alice"; vote.author = "bob"; @@ -285,10 +286,10 @@ struct transaction_fixture : database_fixture { db->push_transaction(tx, 0); generate_block(); _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "vote_operation")); + BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " vote_operation"); tx.operations.clear(); tx.signatures.clear(); - BOOST_TEST_MESSAGE("Deleting comment."); delete_comment_operation dco; dco.author = "bob"; dco.permlink = "test"; @@ -298,10 +299,10 @@ struct transaction_fixture : database_fixture { db->push_transaction(tx, 0); generate_block(); _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "delete_comment_operation")); + BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " delete_comment_operation"); tx.operations.clear(); tx.signatures.clear(); - BOOST_TEST_MESSAGE("Generate accaunt."); account_create_operation aco; aco.new_account_name = "dave"; aco.creator = STEEMIT_INIT_MINER_NAME; @@ -313,18 +314,21 @@ struct transaction_fixture : database_fixture { db->push_transaction(tx, 0); generate_block(); _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "account_create_operation")); + BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " account_create_operation"); tx.operations.clear(); tx.signatures.clear(); validate_database(); } - void check_operations() { BOOST_TEST_MESSAGE("Check history operations."); + + //const auto& idx = db->get_index().indices().get(); + uint32_t head_block_num = db->head_block_num(); BOOST_TEST_MESSAGE("Head block num is " + std::to_string(head_block_num)); - for (uint32_t i = 0; i < head_block_num; ++i) { + for (uint32_t i = 0; i <= head_block_num; ++i) { msg_pack mo; mo.args = std::vector({fc::variant(i), fc::variant(false)}); auto ops = _plg->get_ops_in_block(mo); @@ -347,6 +351,8 @@ struct transaction_fixture : database_fixture { if (iter->second == co.second) { ++_chacked_ops_count; } + } else { + BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); } } BOOST_CHECK_EQUAL(_chacked_ops_count, _chacked_ops.size()); @@ -357,12 +363,17 @@ struct transaction_fixture : database_fixture { template struct execute_fixture { execute_fixture() { - BOOST_TEST_MESSAGE("Execute"); + BOOST_TEST_MESSAGE("Execute begin"); typedef transaction_fixture transaction; std::unique_ptr trans(new transaction(test_type())); } + + ~execute_fixture() { + BOOST_TEST_MESSAGE("Execute end"); + } }; }} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// using namespace golos::test; From 50ed0cf81bff33365d33240bdeb4241376663378 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 22 Jun 2018 12:07:42 +0300 Subject: [PATCH 011/250] Aded different tests for checking postfixes of operations. --- tests/CMakeLists.txt | 4 +- tests/common/database_fixture.cpp | 120 ++++++ tests/common/database_fixture.hpp | 13 +- tests/common/options_postfix.cpp | 53 +++ tests/common/options_postfix.hpp | 114 ++++++ tests/plugin_tests/black_options_postfix.cpp | 35 ++ tests/plugin_tests/options_postfix.cpp | 408 ------------------- tests/plugin_tests/white_options_postfix.cpp | 38 ++ 8 files changed, 375 insertions(+), 410 deletions(-) create mode 100644 tests/common/options_postfix.cpp create mode 100644 tests/common/options_postfix.hpp create mode 100644 tests/plugin_tests/black_options_postfix.cpp delete mode 100644 tests/plugin_tests/options_postfix.cpp create mode 100644 tests/plugin_tests/white_options_postfix.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9f89f682db..a5b550448e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,9 @@ file(GLOB COMMON_SOURCES common/database_fixture.cpp common/database_fixture.hpp - common/comment_reward.hpp) + common/comment_reward.hpp + common/options_postfix.hpp + common/options_postfix.cpp) find_package(Gperftools QUIET) if(GPERFTOOLS_FOUND) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 9f07df2a38..819cc96ad1 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -14,6 +14,8 @@ //using namespace golos::chain::test; +#define STEEM_NAMESPACE_PREFIX std::string("golos::protocol::") + uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP = 1431700000; namespace golos { namespace chain { @@ -97,6 +99,124 @@ namespace golos { namespace chain { FC_LOG_AND_RETHROW() } + struct app_initialise { + golos::plugins::operation_history::plugin* _plg; + + app_initialise() { + int argc = boost::unit_test::framework::master_test_suite().argc; + char **argv = boost::unit_test::framework::master_test_suite().argv; + for (int i = 1; i < argc; i++) { + const std::string arg = argv[i]; + if (arg == "--record-assert-trip") { + fc::enable_record_assert_trip = true; + } + if (arg == "--show-test-names") { + std::cout << "running test " + << boost::unit_test::framework::current_test_case().p_name + << std::endl; + } + } + _plg = &appbase::app().register_plugin(); + BOOST_REQUIRE(_plg); + appbase::app().initialize(argc, argv); + } + }; + + add_operations_database_fixture::add_operations_database_fixture() try { + ilog("add_operations_database_fixture: begin"); + _plg = app_initialise()._plg; + initialize(); + open_database(); + } catch (const fc::exception &e) { + edump((e.to_detail_string())); + throw; + } + + add_operations_database_fixture::~add_operations_database_fixture() try { + ilog("add_operations_database_fixture: end"); + } FC_LOG_AND_RETHROW(); + + void add_operations_database_fixture::add_operations() try { + ACTORS((alice)(bob)(sam)) + fund("alice", 10000); + vest("alice", 10000); + fund("bob", 7500); + vest("bob", 7500); + fund("sam", 8000); + vest("sam", 8000); + + db->set_clear_votes(0xFFFFFFFF); + + signed_transaction tx; + + comment_operation com; + com.author = "bob"; + com.permlink = "test"; + com.parent_author = ""; + com.parent_permlink = "test"; + com.title = "foo"; + com.body = "bar"; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(com); + tx.sign(bob_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "comment_operation")); + ilog("Generate: " + tx.id().str() + " comment_operation"); + tx.operations.clear(); + tx.signatures.clear(); + + vote_operation vote; + vote.voter = "alice"; + vote.author = "bob"; + vote.permlink = "test"; + vote.weight = -1; ///< Nessary for the posiblity of delet_comment_operation. + tx.operations.push_back(vote); + vote.voter = "bob"; + tx.operations.push_back(vote); + vote.voter = "sam"; + tx.operations.push_back(vote); + tx.sign(alice_private_key, db->get_chain_id()); + tx.sign(bob_private_key, db->get_chain_id()); + tx.sign(sam_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "vote_operation")); + ilog("Generate: " + tx.id().str() + " vote_operation"); + tx.operations.clear(); + tx.signatures.clear(); + + delete_comment_operation dco; + dco.author = "bob"; + dco.permlink = "test"; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(dco); + tx.sign(bob_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "delete_comment_operation")); + ilog("Generate: " + tx.id().str() + " delete_comment_operation"); + tx.operations.clear(); + tx.signatures.clear(); + + account_create_operation aco; + aco.new_account_name = "dave"; + aco.creator = STEEMIT_INIT_MINER_NAME; + aco.owner = authority(1, init_account_pub_key, 1); + aco.active = aco.owner; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(aco); + tx.sign(init_account_priv_key, db->get_chain_id()); + db->push_transaction(tx, 0); + generate_block(); + _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "account_create_operation")); + ilog("Generate: " + tx.id().str() + " account_create_operation"); + tx.operations.clear(); + tx.signatures.clear(); + + validate_database(); + } FC_LOG_AND_RETHROW(); + fc::ecc::private_key database_fixture::generate_private_key(string seed) { return fc::ecc::private_key::regenerate(fc::sha256::hash(seed)); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 20c8890563..0075989a58 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -305,6 +305,17 @@ namespace golos { namespace chain { fc::path _chain_dir; }; + struct add_operations_database_fixture : public database_fixture { + add_operations_database_fixture(); + + ~add_operations_database_fixture() override; + + void add_operations(); + + golos::plugins::operation_history::plugin* _plg; + std::map _added_ops; + }; + namespace test { bool _push_block(database &db, const signed_block &b, uint32_t skip_flags = 0); @@ -312,4 +323,4 @@ namespace golos { namespace chain { } } } // golos:chain -#endif \ No newline at end of file +#endif diff --git a/tests/common/options_postfix.cpp b/tests/common/options_postfix.cpp new file mode 100644 index 0000000000..4d04da3fe1 --- /dev/null +++ b/tests/common/options_postfix.cpp @@ -0,0 +1,53 @@ +#include + +#include + +#include "options_postfix.hpp" + + +using namespace golos::test; + +namespace bpo = boost::program_options; + +typedef golos::chain::add_operations_database_fixture add_operations_database_fixture; +typedef golos::plugins::json_rpc::msg_pack msg_pack; + +using namespace golos::protocol; +using namespace golos::chain; + + +struct operation_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + return std::string(fc::get_typename::name()); + } +} ovisit; + + +void options_fixture::log_applied_options(const applied_operation &opts) const { + std::stringstream ss; + ss << "[" << opts.block << "] "; + ss << opts.trx_id.str() << " : "; /// golos::protocol::transaction_id_type + std::string op_name = opts.op.visit(ovisit); + ss << "\"" << op_name << "\""; /// golos::protocol::operation + ilog(ss.str()); +} + + +void options_fixture::check_operations() { + uint32_t head_block_num = _db_init.db->head_block_num(); + ilog("Check history operations, block num is " + std::to_string(head_block_num)); + for (uint32_t i = 0; i <= head_block_num; ++i) { + msg_pack mo; + mo.args = std::vector({fc::variant(i), fc::variant(false)}); + auto ops = _db_init._plg->get_ops_in_block(mo); + for (auto o : ops) { + auto iter = _finded_ops.find(o.trx_id.str()); + if (iter == _finded_ops.end()) { + _finded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); + log_applied_options(o); + } + } + } +} diff --git a/tests/common/options_postfix.hpp b/tests/common/options_postfix.hpp new file mode 100644 index 0000000000..6258ddb0cc --- /dev/null +++ b/tests/common/options_postfix.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" + + +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; + +namespace golos { namespace test { + +using namespace golos::protocol; +using namespace golos::chain; + +typedef golos::plugins::operation_history::applied_operation applied_operation; + +typedef std::map chacked_operation_map; ///< pair { [itx_id], [operation name] } + + +template +struct combine_postfix : key_type_option { + std::string opt = + "account_create_operation," \ + "delete_comment_operation," \ + "vote," \ + "comment"; +}; + + +template +struct test_options_postfix : public opt_type { + bpo::options_description _cfg_opts; + bpo::options_description _cli_opts; + bpo::variables_map _vm_opts; + + void fill_default_options() { + bpo::options_description cfg_opts("Application Config Options"); + cfg_opts.add_options() + ("plugin", bpo::value>()->composing(), + "Plugin(s) to enable, may be specified multiple times") + ; + _cfg_opts.add(cfg_opts); + bpo::options_description cli_opts("Application Command Line Options"); + cli_opts.add_options() + ("help,h", "Print this help message and exit.") + ("version,v", "Print version information.") + ("data-dir,d", bpo::value()->default_value("./"), + "Directory containing configuration file config.ini") + ("config,c", bpo::value()->default_value("config.ini"), + "Configuration file name relative to data-dir") + ; + _cli_opts.add(cli_opts); + } + + void fill_testing_options() { + bpo::options_description all_opts; + all_opts + .add(_cli_opts) + .add(_cfg_opts) + ; + const char *argv = "plugin"; + auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); + bpo::store(parsed_cmd_line, _vm_opts); + + std::stringstream ss_opts; + ss_opts << opt_type::key << " = " << opt_type::opt << "\n"; + std::istringstream iss_opts(ss_opts.str()); + _cfg_opts.add_options() + (opt_type::key.c_str(), bpo::value>()) + ; + auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); + bpo::store(parsed_cfg, _vm_opts); + } + + test_options_postfix() { + fill_default_options(); + fill_testing_options(); + } + + operator bpo::variables_map () const { + return _vm_opts; + } +}; + + +struct options_fixture { + add_operations_database_fixture _db_init; + chacked_operation_map _finded_ops; + + options_fixture() = default; + ~options_fixture() = default; + + template + void init_plugin() { + ilog(std::string("init_plugin(") + typeid(test_type).name() + ")"); + _db_init._plg->plugin_initialize(test_type()); + _db_init._plg->plugin_startup(); + _db_init.startup(); + _db_init.add_operations(); + check_operations(); + } + + void log_applied_options(const applied_operation &opts) const; + + void check_operations(); +}; +}} diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp new file mode 100644 index 0000000000..633754a41a --- /dev/null +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -0,0 +1,35 @@ +/// Runnung example: +/// ./plugin_test --log_level=test_suite --run_test=black_options_postfix + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_postfix.hpp" + + +using namespace golos::test; + + +struct blacklist_key { + std::string key = "history-blacklist-ops"; +}; + + +BOOST_FIXTURE_TEST_CASE(black_options_postfix, options_fixture) { + init_plugin>>(); + + size_t _chacked_ops_count = 0; + for (const auto &co : _db_init._added_ops) { + auto iter = _finded_ops.find(co.first); + bool is_not_finded = (iter == _finded_ops.end()); + BOOST_CHECK(is_not_finded); + if (is_not_finded) { + ++_chacked_ops_count; + } else { + BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, _db_init._added_ops.size()); +} diff --git a/tests/plugin_tests/options_postfix.cpp b/tests/plugin_tests/options_postfix.cpp deleted file mode 100644 index 9ba33ca333..0000000000 --- a/tests/plugin_tests/options_postfix.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/// Runnung example: -/// ./plugin_test --log_level=test_suite --run_test=options_postfix - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" - -#define STEEM_NAMESPACE_PREFIX std::string("golos::protocol::") - - -namespace golos { namespace test { - -namespace bpo = boost::program_options; -namespace bfs = boost::filesystem; - -typedef golos::chain::clean_database_fixture clean_database_fixture; -typedef golos::chain::database_fixture database_fixture; -typedef golos::chain::database database; - -typedef golos::plugins::chain::plugin chain_plugin; -typedef golos::plugins::json_rpc::plugin json_rpc_plugin; -typedef golos::plugins::json_rpc::msg_pack msg_pack; - -typedef golos::plugins::operation_history::plugin gpoh_plugin; -typedef golos::plugins::operation_history::applied_operation applied_operation; -typedef golos::plugins::operation_history::annotated_signed_transaction annotated_signed_transaction; -typedef golos::plugins::operation_history::operation_index operation_index; -typedef golos::plugins::operation_history::by_location by_location; -typedef golos::plugins::operation_history::operation_object operation_object; -typedef golos::plugins::operation_history::by_transaction_id by_transaction_id; - -typedef std::pair chacked_operation; ///< [itx_id], [operation name] -typedef std::map chacked_operation_map; ///< pair { [itx_id], [operation name] } - - -struct app_initialise { - gpoh_plugin *_plg; - - app_initialise() { - int argc = boost::unit_test::framework::master_test_suite().argc; - char **argv = boost::unit_test::framework::master_test_suite().argv; - for (int i = 1; i < argc; i++) { - const std::string arg = argv[i]; - if (arg == "--record-assert-trip") { - fc::enable_record_assert_trip = true; - } - if (arg == "--show-test-names") { - std::cout << "running test " - << boost::unit_test::framework::current_test_case().p_name - << std::endl; - } - } - _plg = &appbase::app().register_plugin(); - BOOST_TEST_REQUIRE(_plg); - appbase::app().initialize(argc, argv); - } -}; - - -struct key_option_whitelist { - std::string key = "history-whitelist-ops"; -}; - - -struct key_option_blacklist { - std::string key = "history-blacklist-ops"; -}; - - -struct option_with_postfix { - std::string opt = - "account_create_operation," \ - "vote_operation," \ - "comment_operation," \ - "delete_comment_operation"; -}; - - -struct option_without_postfix { - std::string opt = - "account_create," \ - "vote," \ - "comment," \ - "delete_comment"; -}; - - -template -struct test_options_postfix - : public key_opt_type - , public opt_type -{ - bpo::options_description _cfg_opts; - bpo::options_description _cli_opts; - bpo::variables_map _vm_opts; - - void print_options(const std::vector &args) { - for (auto arg : args) { - for (auto val : arg.value) { - std::string msg("op > {" + arg.string_key + " : " + val + "}"); - BOOST_TEST_MESSAGE(msg); - } - } - } - - void print_vmap(const bpo::variables_map &vm) { - for (const auto& it : vm) { - std::stringstream ss; - ss << it.first.c_str() << " : "; - auto& value = it.second.value(); - if (auto v = boost::any_cast(&value)) { - ss << *v; - } else if (auto v = boost::any_cast(&value)) { - ss << *v; - } else { - ss << "TYPE"; - } - BOOST_TEST_MESSAGE("vm > {" + ss.str() + "}"); - } - } - - void fill_default_options() { - bpo::options_description cfg_opts("Application Config Options"); - cfg_opts.add_options() - ("plugin", bpo::value>()->composing(), - "Plugin(s) to enable, may be specified multiple times") - ; - _cfg_opts.add(cfg_opts); - bpo::options_description cli_opts("Application Command Line Options"); - cli_opts.add_options() - ("help,h", "Print this help message and exit.") - ("version,v", "Print version information.") - ("data-dir,d", bpo::value()->default_value("./"), - "Directory containing configuration file config.ini") - ("config,c", bpo::value()->default_value("config.ini"), - "Configuration file name relative to data-dir") - ; - _cli_opts.add(cli_opts); - } - - void fill_testing_options() { - bpo::options_description all_opts; - all_opts - .add(_cli_opts) - .add(_cfg_opts) - ; - const char *argv = "plugin"; - auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); - print_options(parsed_cmd_line.options); - bpo::store(parsed_cmd_line, _vm_opts); - //print_vmap(_vm_opts); - - std::stringstream ss_opts; - ss_opts << "history-whitelist-ops = " << opt_type::opt << "\n"; - ss_opts << "history-blacklist-ops = " << opt_type::opt << "\n"; - std::istringstream iss_opts(ss_opts.str()); - _cfg_opts.add_options() - (key_opt_type::key.c_str(), bpo::value>()) - ; - auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); - print_options(parsed_cfg.options); - bpo::store(parsed_cfg, _vm_opts); - //print_vmap(_vm_opts); - } - - - test_options_postfix() { - fill_default_options(); - fill_testing_options(); - } - - operator bpo::variables_map () const { - return _vm_opts; - } - - struct operation_visitor { - using result_type = std::string; - template - std::string operator()(const T&) const { - return std::string(fc::get_typename::name()); - } - } ovisit; - - - chacked_operation print_applied_options(const applied_operation &opts) const { - std::stringstream ss; - ss << opts.trx_id.str() << ", "; /// golos::protocol::transaction_id_type - ss << opts.block << ", "; - ss << opts.trx_in_block << ", "; - ss << opts.op_in_trx << ", "; - ss << opts.virtual_op << ", "; - ss << opts.timestamp.to_iso_string() << ", "; /// fc::time_point_sec - std::string op_name = opts.op.visit(ovisit); - ss << "which is [" << op_name << "]"; /// golos::protocol::operation - BOOST_TEST_MESSAGE(ss.str()); - return chacked_operation(opts.trx_id.str(), op_name); - } -}; - - -using namespace golos::protocol; -using namespace golos::chain; - - -template -struct transaction_fixture : database_fixture { - test_type _tt; - gpoh_plugin *_plg; - chacked_operation_map _finded_ops; - chacked_operation_map _chacked_ops; - - transaction_fixture(const test_type &tt) - : _tt(tt) { - BOOST_TEST_MESSAGE("Create transactions"); - try { - database_fixture::initialize(); - database_fixture::open_database(); - - _plg = app_initialise()._plg; - _plg->plugin_initialize(_tt); - _plg->plugin_startup(); - - database_fixture::startup(); - - add_operations(); - check_operations(); - } FC_LOG_AND_RETHROW(); - } - - void add_operations() { - BOOST_TEST_MESSAGE("Init transactions"); - - ACTORS((alice)(bob)(sam)) - fund("alice", 10000); - vest("alice", 10000); - fund("bob", 7500); - vest("bob", 7500); - fund("sam", 8000); - vest("sam", 8000); - - db->set_clear_votes(0xFFFFFFFF); - - signed_transaction tx; - - comment_operation com; - com.author = "bob"; - com.permlink = "test"; - com.parent_author = ""; - com.parent_permlink = "test"; - com.title = "foo"; - com.body = "bar"; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(com); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - generate_block(); - _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "comment_operation")); - BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " comment_operation"); - tx.operations.clear(); - tx.signatures.clear(); - - vote_operation vote; - vote.voter = "alice"; - vote.author = "bob"; - vote.permlink = "test"; - vote.weight = -1; ///< Nessary for the posiblity of delet_comment_operation. - tx.operations.push_back(vote); - vote.voter = "bob"; - tx.operations.push_back(vote); - vote.voter = "sam"; - tx.operations.push_back(vote); - tx.sign(alice_private_key, db->get_chain_id()); - tx.sign(bob_private_key, db->get_chain_id()); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - generate_block(); - _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "vote_operation")); - BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " vote_operation"); - tx.operations.clear(); - tx.signatures.clear(); - - delete_comment_operation dco; - dco.author = "bob"; - dco.permlink = "test"; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(dco); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - generate_block(); - _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "delete_comment_operation")); - BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " delete_comment_operation"); - tx.operations.clear(); - tx.signatures.clear(); - - account_create_operation aco; - aco.new_account_name = "dave"; - aco.creator = STEEMIT_INIT_MINER_NAME; - aco.owner = authority(1, init_account_pub_key, 1); - aco.active = aco.owner; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(aco); - tx.sign(init_account_priv_key, db->get_chain_id()); - db->push_transaction(tx, 0); - generate_block(); - _chacked_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "account_create_operation")); - BOOST_TEST_MESSAGE("Generate: " + tx.id().str() + " account_create_operation"); - tx.operations.clear(); - tx.signatures.clear(); - - validate_database(); - } - - void check_operations() { - BOOST_TEST_MESSAGE("Check history operations."); - - //const auto& idx = db->get_index().indices().get(); - - uint32_t head_block_num = db->head_block_num(); - BOOST_TEST_MESSAGE("Head block num is " + std::to_string(head_block_num)); - for (uint32_t i = 0; i <= head_block_num; ++i) { - msg_pack mo; - mo.args = std::vector({fc::variant(i), fc::variant(false)}); - auto ops = _plg->get_ops_in_block(mo); - BOOST_TEST_MESSAGE("Checked operations is " + std::to_string(ops.size())); - for (auto o : ops) { - auto ch_op = _tt.print_applied_options(o); - auto iter = _finded_ops.find(ch_op.first); - if (iter == _finded_ops.end()) { - _finded_ops.insert(ch_op); - } - } - } - size_t _chacked_ops_count = 0; - for (const auto &co : _chacked_ops) { - auto iter = _finded_ops.find(co.first); - bool is_finded = (iter not_eq _finded_ops.end()); - BOOST_CHECK(is_finded); - if (is_finded) { - BOOST_CHECK_EQUAL(iter->second, co.second); - if (iter->second == co.second) { - ++_chacked_ops_count; - } - } else { - BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, _chacked_ops.size()); - } -}; - - -template -struct execute_fixture { - execute_fixture() { - BOOST_TEST_MESSAGE("Execute begin"); - typedef transaction_fixture transaction; - std::unique_ptr trans(new transaction(test_type())); - } - - ~execute_fixture() { - BOOST_TEST_MESSAGE("Execute end"); - } -}; -}} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -using namespace golos::test; - -typedef option_with_postfix opt_with_postfix; -typedef option_without_postfix opt_without_postfix; -typedef key_option_whitelist key_opt_whitelist; -typedef key_option_blacklist key_opt_blacklist; -typedef test_options_postfix test_white_with_postfix; -typedef test_options_postfix test_white_without_postfix; -typedef test_options_postfix test_black_with_postfix; -typedef test_options_postfix test_black_without_postfix; - - -BOOST_AUTO_TEST_SUITE(options_postfix) - - BOOST_FIXTURE_TEST_CASE(white_options_with_postfix, execute_fixture) {} - - BOOST_FIXTURE_TEST_CASE(white_options_without_postfix, execute_fixture) {} - - BOOST_FIXTURE_TEST_CASE(black_options_with_postfix, execute_fixture) {} - - BOOST_FIXTURE_TEST_CASE(black_options_without_postfix, execute_fixture) {} - -BOOST_AUTO_TEST_SUITE_END() - - -// - там есть настройка history-start-block - это номер блока до которого не хранить историю -// - хранить историю только за последний день, неделю, месяц это более удобно потому, -// что делегатов сейчас интересует только последняя история операций. - - diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp new file mode 100644 index 0000000000..e362219731 --- /dev/null +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -0,0 +1,38 @@ +/// Runnung example: +/// ./plugin_test --log_level=test_suite --run_test=white_options_postfix + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_postfix.hpp" + + +using namespace golos::test; + + +struct whitelist_key { + std::string key = "history-whitelist-ops"; +}; + + +BOOST_FIXTURE_TEST_CASE(white_options_postfix, options_fixture) { + init_plugin>>(); + + size_t _chacked_ops_count = 0; + for (const auto &co : _db_init._added_ops) { + auto iter = _finded_ops.find(co.first); + bool is_finded = (iter not_eq _finded_ops.end()); + BOOST_CHECK(is_finded); + if (is_finded) { + BOOST_CHECK_EQUAL(iter->second, co.second); + if (iter->second == co.second) { + ++_chacked_ops_count; + } + } else { + BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, _db_init._added_ops.size()); +} From 42369b2b445b6cbf22169948676e40ee8e0483c5 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Mon, 25 Jun 2018 15:14:39 +0300 Subject: [PATCH 012/250] A separate test file is allocated. --- plugins/operation_history/plugin.cpp | 4 ++++ tests/CMakeLists.txt | 9 +++++++++ tests/plugin_tests/time_limit_options.cpp | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 tests/plugin_tests/time_limit_options.cpp diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 6d914e280a..1ec993b5e8 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -173,6 +173,10 @@ namespace golos { namespace plugins { namespace operation_history { "history-start-block", boost::program_options::value()->composing(), "Defines starting block from which recording stats." + ) ( + "history-blocks", + boost::program_options::value()->composing(), + "Defines starting time from which recording stats." ); cfg.add(cli); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a5b550448e..ca1d6a9fde 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,15 @@ target_link_libraries(plugin_test golos_chain golos_protocol golos_account_hist target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") add_test(NAME plugin_test_run COMMAND plugin_test) +file(GLOB OPTION_TESTS + "plugin_tests/main.cpp" + "plugin_tests/black_options_postfix.cpp" + "plugin_tests/white_options_postfix.cpp") +add_executable(options_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) +target_link_libraries(options_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node fc ${PLATFORM_SPECIFIC_LIBS}) +target_include_directories(options_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") +add_test(NAME options_test_run COMMAND options_test) + if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") endif(MSVC) diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp new file mode 100644 index 0000000000..963542ddcd --- /dev/null +++ b/tests/plugin_tests/time_limit_options.cpp @@ -0,0 +1,19 @@ +/// Runnung example: +/// ./plugin_test --log_level=test_suite --run_test=black_options_postfix + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_postfix.hpp" + + +using namespace golos::test; + + + +BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { +} + +// hystory-blocks From 2204956e53237465196906a6a2ae94056f7ee8b1 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Mon, 25 Jun 2018 21:56:57 +0300 Subject: [PATCH 013/250] Fix tests compilation. --- plugins/operation_history/plugin.cpp | 22 +++++++-- tests/CMakeLists.txt | 47 +++++++++++++++---- ...ptions_postfix.cpp => options_fixture.cpp} | 2 +- ...ptions_postfix.hpp => options_fixture.hpp} | 0 tests/plugin_tests/black_options_postfix.cpp | 5 +- tests/plugin_tests/time_limit_options.cpp | 7 +-- tests/plugin_tests/white_options_postfix.cpp | 5 +- 7 files changed, 63 insertions(+), 25 deletions(-) rename tests/common/{options_postfix.cpp => options_fixture.cpp} (98%) rename tests/common/{options_postfix.hpp => options_fixture.hpp} (100%) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 1ec993b5e8..5a7113c76c 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -59,22 +59,28 @@ namespace golos { namespace plugins { namespace operation_history { golos::chain::operation_notification& note, const fc::flat_set& ops_list, bool is_blacklist, - uint32_t block) + uint32_t block, + fc::time_point_sec start_time) : operation_visitor(db, note), filter(ops_list), blacklist(is_blacklist), - start_block(block) { + start_block(block), + start_time(start_time) { } const fc::flat_set& filter; bool blacklist; uint32_t start_block; + fc::time_point_sec start_time; template void operator()(const T& op) const { if (database.head_block_num() < start_block) { return; } + if (database.head_block_time() < start_time) { + return; + } if (filter.find(fc::get_typename::name()) != filter.end()) { if (!blacklist) { operation_visitor::operator()(op); @@ -96,7 +102,7 @@ namespace golos { namespace plugins { namespace operation_history { void on_operation(golos::chain::operation_notification& note) { if (filter_content) { - note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); + note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block, start_time)); } else { note.op.visit(operation_visitor(database, note)); } @@ -136,6 +142,7 @@ namespace golos { namespace plugins { namespace operation_history { bool filter_content = false; uint32_t start_block = 0; bool blacklist = false; + fc::time_point_sec start_time; fc::flat_set ops_list; golos::chain::database& database; }; @@ -235,6 +242,15 @@ namespace golos { namespace plugins { namespace operation_history { pimpl->start_block = 0; } ilog("operation_history: start_block ${s}", ("s", pimpl->start_block)); + + if (options.count("history-blocks")) { + pimpl->filter_content = true; + std::string start_time_iso_str = options.at("history-blocks").as(); + pimpl->start_time = fc::time_point_sec::from_iso_string(start_time_iso_str); + } else { + pimpl->start_time = fc::time_point_sec(); + } + JSON_RPC_REGISTER_API(name()); ilog("operation_history plugin: plugin_initialize() end"); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ca1d6a9fde..96fe6a88de 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,8 +2,8 @@ file(GLOB COMMON_SOURCES common/database_fixture.cpp common/database_fixture.hpp common/comment_reward.hpp - common/options_postfix.hpp - common/options_postfix.cpp) + common/options_fixture.hpp + common/options_fixture.cpp) find_package(Gperftools QUIET) if(GPERFTOOLS_FOUND) @@ -30,20 +30,47 @@ target_link_libraries( add_test(NAME chain_test_run COMMAND chain_test) -file(GLOB PLUGIN_TESTS "plugin_tests/*.cpp") +file(GLOB PLUGIN_TESTS + "plugin_tests/main.cpp" + "plugin_tests/market_history.cpp" + "plugin_tests/plugin_ops.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") add_test(NAME plugin_test_run COMMAND plugin_test) -file(GLOB OPTION_TESTS +macro(add_exec_test) + set(OPTIONS) + set(ONE_VALUE_ARGS NAME) + set(MULTI_VALUE_ARGS FILES) + cmake_parse_arguments(GET "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) + string(TOUPPER "${GET_NAME}_TEST" TESTS) + MESSAGE(STATUS "\"${TESTS}\" \"${GET_NAME}\"") + file(GLOB ${TESTS} ${GET_FILES}) + add_executable("${GET_NAME}_test" ${${TESTS}} ${COMMON_SOURCES}) + target_link_libraries("${GET_NAME}_test" + golos_chain + golos_protocol + golos_account_history + golos_market_history + golos_debug_node + fc ${PLATFORM_SPECIFIC_LIBS}) + target_include_directories("${GET_NAME}_test" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") + add_test(NAME "${GET_NAME}_test_run" COMMAND "${GET_NAME}_test") +endmacro(add_exec_test) + +add_exec_test(NAME "white_options" FILES + "plugin_tests/main.cpp" + "plugin_tests/white_options_postfix.cpp" + ) + +add_exec_test(NAME "black_options" FILES + "plugin_tests/main.cpp" + "plugin_tests/black_options_postfix.cpp") + +add_exec_test(NAME "time_options" FILES "plugin_tests/main.cpp" - "plugin_tests/black_options_postfix.cpp" - "plugin_tests/white_options_postfix.cpp") -add_executable(options_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) -target_link_libraries(options_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node fc ${PLATFORM_SPECIFIC_LIBS}) -target_include_directories(options_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") -add_test(NAME options_test_run COMMAND options_test) + "plugin_tests/time_limit_options.cpp") if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") diff --git a/tests/common/options_postfix.cpp b/tests/common/options_fixture.cpp similarity index 98% rename from tests/common/options_postfix.cpp rename to tests/common/options_fixture.cpp index 4d04da3fe1..f02f006225 100644 --- a/tests/common/options_postfix.cpp +++ b/tests/common/options_fixture.cpp @@ -2,7 +2,7 @@ #include -#include "options_postfix.hpp" +#include "options_fixture.hpp" using namespace golos::test; diff --git a/tests/common/options_postfix.hpp b/tests/common/options_fixture.hpp similarity index 100% rename from tests/common/options_postfix.hpp rename to tests/common/options_fixture.hpp diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp index 633754a41a..b62d403445 100644 --- a/tests/plugin_tests/black_options_postfix.cpp +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -1,12 +1,9 @@ -/// Runnung example: -/// ./plugin_test --log_level=test_suite --run_test=black_options_postfix - #include #include #include "database_fixture.hpp" #include "comment_reward.hpp" -#include "options_postfix.hpp" +#include "options_fixture.hpp" using namespace golos::test; diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp index 963542ddcd..d6aa496b4d 100644 --- a/tests/plugin_tests/time_limit_options.cpp +++ b/tests/plugin_tests/time_limit_options.cpp @@ -1,19 +1,20 @@ /// Runnung example: -/// ./plugin_test --log_level=test_suite --run_test=black_options_postfix +/// ./plugin_test --log_level=test_suite --run_test=time_limit_options #include #include #include "database_fixture.hpp" #include "comment_reward.hpp" -#include "options_postfix.hpp" +#include "options_fixture.hpp" using namespace golos::test; - +//struct BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { + } // hystory-blocks diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index e362219731..baf0034724 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -1,12 +1,9 @@ -/// Runnung example: -/// ./plugin_test --log_level=test_suite --run_test=white_options_postfix - #include #include #include "database_fixture.hpp" #include "comment_reward.hpp" -#include "options_postfix.hpp" +#include "options_fixture.hpp" using namespace golos::test; From c8b2e4a8699a324366307cffd63aad7ec0f30606 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Tue, 26 Jun 2018 11:42:22 +0300 Subject: [PATCH 014/250] Implemented the possibility of adding custom options to the fixture options of the historical plugin. --- plugins/operation_history/plugin.cpp | 27 +++++++++-------- tests/CMakeLists.txt | 3 +- tests/common/options_fixture.hpp | 31 +++++++++++++++----- tests/plugin_tests/black_options_postfix.cpp | 2 +- tests/plugin_tests/time_limit_options.cpp | 10 +++---- tests/plugin_tests/white_options_postfix.cpp | 2 +- 6 files changed, 45 insertions(+), 30 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 5a7113c76c..a0d5aca4bc 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -60,27 +60,27 @@ namespace golos { namespace plugins { namespace operation_history { const fc::flat_set& ops_list, bool is_blacklist, uint32_t block, - fc::time_point_sec start_time) + uint32_t blocks) : operation_visitor(db, note), filter(ops_list), blacklist(is_blacklist), start_block(block), - start_time(start_time) { + history_blocks(blocks) { } const fc::flat_set& filter; bool blacklist; uint32_t start_block; - fc::time_point_sec start_time; + uint32_t history_blocks; template void operator()(const T& op) const { if (database.head_block_num() < start_block) { return; } - if (database.head_block_time() < start_time) { - return; - } + //if (database.head_block_time() < start_time) { + // return; + //} if (filter.find(fc::get_typename::name()) != filter.end()) { if (!blacklist) { operation_visitor::operator()(op); @@ -102,7 +102,7 @@ namespace golos { namespace plugins { namespace operation_history { void on_operation(golos::chain::operation_notification& note) { if (filter_content) { - note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block, start_time)); + note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block, history_blocks)); } else { note.op.visit(operation_visitor(database, note)); } @@ -141,8 +141,8 @@ namespace golos { namespace plugins { namespace operation_history { bool filter_content = false; uint32_t start_block = 0; + uint32_t history_blocks = UINT32_MAX; bool blacklist = false; - fc::time_point_sec start_time; fc::flat_set ops_list; golos::chain::database& database; }; @@ -182,8 +182,8 @@ namespace golos { namespace plugins { namespace operation_history { "Defines starting block from which recording stats." ) ( "history-blocks", - boost::program_options::value()->composing(), - "Defines starting time from which recording stats." + boost::program_options::value()->composing(), + "Defines history block num from which recording stats." ); cfg.add(cli); @@ -245,11 +245,12 @@ namespace golos { namespace plugins { namespace operation_history { if (options.count("history-blocks")) { pimpl->filter_content = true; - std::string start_time_iso_str = options.at("history-blocks").as(); - pimpl->start_time = fc::time_point_sec::from_iso_string(start_time_iso_str); + uint32_t history_blocks = options.at("history-blocks").as(); + pimpl->history_blocks = history_blocks; } else { - pimpl->start_time = fc::time_point_sec(); + pimpl->history_blocks = UINT32_MAX; } + ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); JSON_RPC_REGISTER_API(name()); ilog("operation_history plugin: plugin_initialize() end"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 96fe6a88de..2561f1cddf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -61,8 +61,7 @@ endmacro(add_exec_test) add_exec_test(NAME "white_options" FILES "plugin_tests/main.cpp" - "plugin_tests/white_options_postfix.cpp" - ) + "plugin_tests/white_options_postfix.cpp") add_exec_test(NAME "black_options" FILES "plugin_tests/main.cpp" diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp index 6258ddb0cc..94c46a5d51 100644 --- a/tests/common/options_fixture.hpp +++ b/tests/common/options_fixture.hpp @@ -4,6 +4,10 @@ #include #include + +#include +#include + #include #include @@ -26,6 +30,7 @@ typedef std::map chacked_operation_map; ///< pair { [ template struct combine_postfix : key_type_option { + typedef std::vector opt_type; std::string opt = "account_create_operation," \ "delete_comment_operation," \ @@ -35,7 +40,7 @@ struct combine_postfix : key_type_option { template -struct test_options_postfix : public opt_type { +struct test_options : public opt_type { bpo::options_description _cfg_opts; bpo::options_description _cli_opts; bpo::variables_map _vm_opts; @@ -57,9 +62,7 @@ struct test_options_postfix : public opt_type { "Configuration file name relative to data-dir") ; _cli_opts.add(cli_opts); - } - void fill_testing_options() { bpo::options_description all_opts; all_opts .add(_cli_opts) @@ -68,20 +71,34 @@ struct test_options_postfix : public opt_type { const char *argv = "plugin"; auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); bpo::store(parsed_cmd_line, _vm_opts); + } + //void fill_operations_options() { + // std::stringstream ss_opts; + // ss_opts << opt_type::key << " = " << opt_type::opt << "\n"; + // std::istringstream iss_opts(ss_opts.str()); + // _cfg_opts.add_options() + // (opt_type::key.c_str(), bpo::value()) + // ; + // auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); + // bpo::store(parsed_cfg, _vm_opts); + //} + + template + void fill_options() { std::stringstream ss_opts; - ss_opts << opt_type::key << " = " << opt_type::opt << "\n"; + ss_opts << custom_opt_type::key << " = " << custom_opt_type::opt << "\n"; std::istringstream iss_opts(ss_opts.str()); _cfg_opts.add_options() - (opt_type::key.c_str(), bpo::value>()) + (custom_opt_type::key.c_str(), bpo::value()) ; auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); bpo::store(parsed_cfg, _vm_opts); } - test_options_postfix() { + test_options() { fill_default_options(); - fill_testing_options(); + fill_options(); } operator bpo::variables_map () const { diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp index b62d403445..ffdc3f0542 100644 --- a/tests/plugin_tests/black_options_postfix.cpp +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -15,7 +15,7 @@ struct blacklist_key { BOOST_FIXTURE_TEST_CASE(black_options_postfix, options_fixture) { - init_plugin>>(); + init_plugin>>(); size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp index d6aa496b4d..71b6c583bd 100644 --- a/tests/plugin_tests/time_limit_options.cpp +++ b/tests/plugin_tests/time_limit_options.cpp @@ -1,6 +1,3 @@ -/// Runnung example: -/// ./plugin_test --log_level=test_suite --run_test=time_limit_options - #include #include @@ -11,10 +8,11 @@ using namespace golos::test; -//struct +struct time_limit_key { + std::string key = "history-bloks"; +}; + BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { } - -// hystory-blocks diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index baf0034724..9f38c71247 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -15,7 +15,7 @@ struct whitelist_key { BOOST_FIXTURE_TEST_CASE(white_options_postfix, options_fixture) { - init_plugin>>(); + init_plugin>>(); size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { From a799a1e9e80bb5ab25db93c1dc461199353b45fa Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 27 Jun 2018 20:22:27 +0300 Subject: [PATCH 015/250] Added test for history blocks. --- plugins/operation_history/plugin.cpp | 41 +++++++++++++++----- tests/common/options_fixture.hpp | 20 +++------- tests/plugin_tests/black_options_postfix.cpp | 2 +- tests/plugin_tests/time_limit_options.cpp | 35 ++++++++++++++++- tests/plugin_tests/white_options_postfix.cpp | 2 +- 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index a0d5aca4bc..3058ccdfa4 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -59,28 +59,22 @@ namespace golos { namespace plugins { namespace operation_history { golos::chain::operation_notification& note, const fc::flat_set& ops_list, bool is_blacklist, - uint32_t block, - uint32_t blocks) + uint32_t block) : operation_visitor(db, note), filter(ops_list), blacklist(is_blacklist), - start_block(block), - history_blocks(blocks) { + start_block(block) { } const fc::flat_set& filter; bool blacklist; uint32_t start_block; - uint32_t history_blocks; template void operator()(const T& op) const { if (database.head_block_num() < start_block) { return; } - //if (database.head_block_time() < start_time) { - // return; - //} if (filter.find(fc::get_typename::name()) != filter.end()) { if (!blacklist) { operation_visitor::operator()(op); @@ -100,9 +94,38 @@ namespace golos { namespace plugins { namespace operation_history { ~plugin_impl() = default; + struct operation_name_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + return std::string(fc::get_typename::name()); + } + }; + + void erase_old_blocks() { + uint32_t head_block = database.head_block_num(); + if (history_blocks <= head_block) { + uint32_t need_block = head_block - history_blocks + 1; + const auto& idx = database.get_index().indices().get(); + auto it = idx.begin(); + while (it not_eq idx.end()) { + auto next_it = it; + ++next_it; + uint32_t block = it->block; + applied_operation op(*it); + if (block <= need_block) { + ilog("remove : [" + std::to_string(block) + "] " + op.op.visit(operation_name_visitor())); + database.remove(*it); + } + it = next_it; + } + } + } + void on_operation(golos::chain::operation_notification& note) { if (filter_content) { - note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block, history_blocks)); + note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); + erase_old_blocks(); } else { note.op.visit(operation_visitor(database, note)); } diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp index 94c46a5d51..288ba2bf4c 100644 --- a/tests/common/options_fixture.hpp +++ b/tests/common/options_fixture.hpp @@ -73,24 +73,14 @@ struct test_options : public opt_type { bpo::store(parsed_cmd_line, _vm_opts); } - //void fill_operations_options() { - // std::stringstream ss_opts; - // ss_opts << opt_type::key << " = " << opt_type::opt << "\n"; - // std::istringstream iss_opts(ss_opts.str()); - // _cfg_opts.add_options() - // (opt_type::key.c_str(), bpo::value()) - // ; - // auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); - // bpo::store(parsed_cfg, _vm_opts); - //} - template void fill_options() { + custom_opt_type cot; std::stringstream ss_opts; - ss_opts << custom_opt_type::key << " = " << custom_opt_type::opt << "\n"; + ss_opts << cot.key << " = " << cot.opt << "\n"; std::istringstream iss_opts(ss_opts.str()); _cfg_opts.add_options() - (custom_opt_type::key.c_str(), bpo::value()) + (cot.key.c_str(), bpo::value()) ; auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); bpo::store(parsed_cfg, _vm_opts); @@ -115,9 +105,9 @@ struct options_fixture { ~options_fixture() = default; template - void init_plugin() { + void init_plugin(const test_type& tt) { ilog(std::string("init_plugin(") + typeid(test_type).name() + ")"); - _db_init._plg->plugin_initialize(test_type()); + _db_init._plg->plugin_initialize(tt); _db_init._plg->plugin_startup(); _db_init.startup(); _db_init.add_operations(); diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp index ffdc3f0542..3a655e2d8d 100644 --- a/tests/plugin_tests/black_options_postfix.cpp +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -15,7 +15,7 @@ struct blacklist_key { BOOST_FIXTURE_TEST_CASE(black_options_postfix, options_fixture) { - init_plugin>>(); + init_plugin(test_options>()); size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp index 71b6c583bd..963c71b893 100644 --- a/tests/plugin_tests/time_limit_options.cpp +++ b/tests/plugin_tests/time_limit_options.cpp @@ -1,3 +1,6 @@ +#include +#include + #include #include @@ -8,11 +11,41 @@ using namespace golos::test; + +struct whitelist_key { + std::string key = "history-whitelist-ops"; +}; + + +static uint32_t HISTORY_BLOCKS = 2; + + struct time_limit_key { - std::string key = "history-bloks"; + typedef uint32_t opt_type; + std::string key = "history-blocks"; + std::string opt = std::to_string(HISTORY_BLOCKS); }; BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { + auto tops = test_options>(); + tops.fill_options(); + init_plugin(tops); + + size_t _chacked_ops_count = 0; + for (auto it = _finded_ops.begin(); it not_eq _finded_ops.end(); ++it) { + auto iter = _db_init._added_ops.find(it->first); + bool is_finded = (iter not_eq _db_init._added_ops.end()); + BOOST_CHECK(is_finded); + if (is_finded) { + BOOST_CHECK_EQUAL(iter->second, it->second); + if (iter->second == it->second) { + ++_chacked_ops_count; + } + } else { + BOOST_TEST_MESSAGE("Operation \"" + it->second + "\" by \"" + it->first + "\" is not found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, HISTORY_BLOCKS); } diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index 9f38c71247..8dcc14b8d2 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -15,7 +15,7 @@ struct whitelist_key { BOOST_FIXTURE_TEST_CASE(white_options_postfix, options_fixture) { - init_plugin>>(); + init_plugin(test_options>()); size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { From b7342d9f8f00fb6446d74531312469892a0482db Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 28 Jun 2018 10:39:03 +0300 Subject: [PATCH 016/250] Delete excessive logging in history plugin. --- plugins/operation_history/plugin.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 3058ccdfa4..09793fe834 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -94,14 +94,6 @@ namespace golos { namespace plugins { namespace operation_history { ~plugin_impl() = default; - struct operation_name_visitor { - using result_type = std::string; - template - std::string operator()(const T&) const { - return std::string(fc::get_typename::name()); - } - }; - void erase_old_blocks() { uint32_t head_block = database.head_block_num(); if (history_blocks <= head_block) { @@ -114,7 +106,6 @@ namespace golos { namespace plugins { namespace operation_history { uint32_t block = it->block; applied_operation op(*it); if (block <= need_block) { - ilog("remove : [" + std::to_string(block) + "] " + op.op.visit(operation_name_visitor())); database.remove(*it); } it = next_it; From 72525ab5bcb4cbf50c7cd1c26a3e73faaf0d8379 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 28 Jun 2018 17:59:16 +0300 Subject: [PATCH 017/250] Change filter flag working. --- plugins/operation_history/plugin.cpp | 68 +++++++++----------- tests/plugin_tests/time_limit_options.cpp | 4 +- tests/plugin_tests/white_options_postfix.cpp | 2 +- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 09793fe834..89cd8bbc01 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -20,35 +20,40 @@ namespace golos { namespace plugins { namespace operation_history { struct operation_visitor { operation_visitor( golos::chain::database& db, - golos::chain::operation_notification& op_note) + golos::chain::operation_notification& op_note, + uint32_t start_block) : database(db), - note(op_note) { + note(op_note), + start_block(start_block) { } using result_type = void; golos::chain::database& database; golos::chain::operation_notification& note; + uint32_t start_block; template void operator()(Op&&) const { - note.stored_in_db = true; - - database.create([&](operation_object& obj) { - note.db_id = obj.id._id; - - obj.trx_id = note.trx_id; - obj.block = note.block; - obj.trx_in_block = note.trx_in_block; - obj.op_in_trx = note.op_in_trx; - obj.virtual_op = note.virtual_op; - obj.timestamp = database.head_block_time(); - - const auto size = fc::raw::pack_size(note.op); - obj.serialized_op.resize(size); - fc::datastream ds(obj.serialized_op.data(), size); - fc::raw::pack(ds, note.op); - }); + if (start_block <= database.head_block_num()) { + note.stored_in_db = true; + + database.create([&](operation_object& obj) { + note.db_id = obj.id._id; + + obj.trx_id = note.trx_id; + obj.block = note.block; + obj.trx_in_block = note.trx_in_block; + obj.op_in_trx = note.op_in_trx; + obj.virtual_op = note.virtual_op; + obj.timestamp = database.head_block_time(); + + const auto size = fc::raw::pack_size(note.op); + obj.serialized_op.resize(size); + fc::datastream ds(obj.serialized_op.data(), size); + fc::raw::pack(ds, note.op); + }); + } } }; @@ -60,7 +65,7 @@ namespace golos { namespace plugins { namespace operation_history { const fc::flat_set& ops_list, bool is_blacklist, uint32_t block) - : operation_visitor(db, note), + : operation_visitor(db, note, block), filter(ops_list), blacklist(is_blacklist), start_block(block) { @@ -72,9 +77,6 @@ namespace golos { namespace plugins { namespace operation_history { template void operator()(const T& op) const { - if (database.head_block_num() < start_block) { - return; - } if (filter.find(fc::get_typename::name()) != filter.end()) { if (!blacklist) { operation_visitor::operator()(op); @@ -100,26 +102,19 @@ namespace golos { namespace plugins { namespace operation_history { uint32_t need_block = head_block - history_blocks + 1; const auto& idx = database.get_index().indices().get(); auto it = idx.begin(); - while (it not_eq idx.end()) { + while (it != idx.end() && it->block <= need_block) { auto next_it = it; ++next_it; - uint32_t block = it->block; applied_operation op(*it); - if (block <= need_block) { - database.remove(*it); - } + database.remove(*it); it = next_it; } } } void on_operation(golos::chain::operation_notification& note) { - if (filter_content) { - note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); - erase_old_blocks(); - } else { - note.op.visit(operation_visitor(database, note)); - } + note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); + erase_old_blocks(); } std::vector get_ops_in_block( @@ -153,7 +148,6 @@ namespace golos { namespace plugins { namespace operation_history { FC_ASSERT(false, "Unknown Transaction ${t}", ("t", id)); } - bool filter_content = false; uint32_t start_block = 0; uint32_t history_blocks = UINT32_MAX; bool blacklist = false; @@ -238,19 +232,16 @@ namespace golos { namespace plugins { namespace operation_history { !options.count("history-blacklist-ops"), "history-blacklist-ops and history-whitelist-ops can't be specified together"); - pimpl->filter_content = true; pimpl->blacklist = false; split_list(options.at("history-whitelist-ops").as>()); ilog("operation_history: whitelisting ops ${o}", ("o", pimpl->ops_list)); } else if (options.count("history-blacklist-ops")) { - pimpl->filter_content = true; pimpl->blacklist = true; split_list(options.at("history-blacklist-ops").as>()); ilog("operation_history: blacklisting ops ${o}", ("o", pimpl->ops_list)); } if (options.count("history-start-block")) { - pimpl->filter_content = true; pimpl->start_block = options.at("history-start-block").as(); } else { pimpl->start_block = 0; @@ -258,7 +249,6 @@ namespace golos { namespace plugins { namespace operation_history { ilog("operation_history: start_block ${s}", ("s", pimpl->start_block)); if (options.count("history-blocks")) { - pimpl->filter_content = true; uint32_t history_blocks = options.at("history-blocks").as(); pimpl->history_blocks = history_blocks; } else { diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp index 963c71b893..a5addedab2 100644 --- a/tests/plugin_tests/time_limit_options.cpp +++ b/tests/plugin_tests/time_limit_options.cpp @@ -33,9 +33,9 @@ BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { init_plugin(tops); size_t _chacked_ops_count = 0; - for (auto it = _finded_ops.begin(); it not_eq _finded_ops.end(); ++it) { + for (auto it = _finded_ops.begin(); it != _finded_ops.end(); ++it) { auto iter = _db_init._added_ops.find(it->first); - bool is_finded = (iter not_eq _db_init._added_ops.end()); + bool is_finded = (iter != _db_init._added_ops.end()); BOOST_CHECK(is_finded); if (is_finded) { BOOST_CHECK_EQUAL(iter->second, it->second); diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index 8dcc14b8d2..01d09f3339 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -20,7 +20,7 @@ BOOST_FIXTURE_TEST_CASE(white_options_postfix, options_fixture) { size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { auto iter = _finded_ops.find(co.first); - bool is_finded = (iter not_eq _finded_ops.end()); + bool is_finded = (iter != _finded_ops.end()); BOOST_CHECK(is_finded); if (is_finded) { BOOST_CHECK_EQUAL(iter->second, co.second); From cfc141d80436580e8ed66a37c96a56a32d534c73 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 28 Jun 2018 18:23:19 +0300 Subject: [PATCH 018/250] Change define to static value. #668 --- .../include/golos/plugins/operation_history/plugin.hpp | 2 +- plugins/operation_history/plugin.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp b/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp index e56c001bce..a20facd76a 100644 --- a/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp +++ b/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp @@ -77,7 +77,7 @@ namespace golos { namespace plugins { namespace operation_history { * @return sequence of operations included/generated within the block */ (get_ops_in_block) - + (get_transaction) ) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 89cd8bbc01..a86005b946 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -5,11 +5,12 @@ #include -#define STEEM_NAMESPACE_PREFIX "golos::protocol::" - #define CHECK_ARG_SIZE(s) \ FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); +static const char STEEM_NAMESPACE_PREFIX[] = "golos::protocol::"; + + namespace golos { namespace plugins { namespace operation_history { struct operation_visitor_filter; @@ -191,7 +192,7 @@ namespace golos { namespace plugins { namespace operation_history { ) ( "history-blocks", boost::program_options::value()->composing(), - "Defines history block num from which recording stats." + "Defines depth of history for recording stats." ); cfg.add(cli); From c30135b599fdd63a0bcc4171c305dcf2f7749a6f Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 29 Jun 2018 11:46:02 +0300 Subject: [PATCH 019/250] Added function for removing old accaunts indices. #668 --- .../account_history/history_object.hpp | 11 +++++- plugins/account_history/plugin.cpp | 34 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index 19956a329f..b6a6b37858 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -50,12 +50,14 @@ namespace golos { namespace plugins { namespace account_history { id_type id; account_name_type account; + uint32_t block = 0; uint32_t sequence = 0; operation_id_type op; }; using account_history_id_type = object_id; + struct by_location; struct by_account; using account_history_index = multi_index_container< account_history_object, @@ -63,9 +65,16 @@ namespace golos { namespace plugins { namespace account_history { ordered_unique< tag, member>, - ordered_unique, + ordered_unique< + tag, + composite_key< + account_history_object, + member>>, + ordered_unique< + tag, composite_key, + //member, member>, composite_key_compare, std::greater>>>, allocator>; diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 4247b49f6a..7b09ac35b6 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -18,7 +18,7 @@ namespace golos { namespace plugins { namespace account_history { using namespace golos::protocol; using namespace golos::chain; -// +// template T dejsonify(const string &s) { return fc::json::from_string(s).as(); @@ -30,7 +30,7 @@ if( options.count(name) ) { \ const std::vector& ops = options[name].as>(); \ std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &dejsonify); \ } -// +// struct operation_visitor final { operation_visitor( @@ -52,13 +52,14 @@ if( options.count(name) ) { \ void operator()(Op &&) const { const auto& idx = database.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(account, uint32_t(-1))); + auto itr = idx.lower_bound(std::make_tuple(account, note.block, uint32_t(-1))); uint32_t sequence = 0; if (itr != idx.end() && itr->account == account) { sequence = itr->sequence + 1; } database.create([&](account_history_object& history) { + history.block = note.block; history.account = account; history.sequence = sequence; history.op = operation_history::operation_id_type(note.db_id); @@ -74,6 +75,22 @@ if( options.count(name) ) { \ ~plugin_impl() = default; + void erase_old_blocks() { + uint32_t head_block = database.head_block_num(); + if (history_blocks <= head_block) { + uint32_t need_block = head_block - history_blocks + 1; + const auto& idx = database.get_index().indices().get(); + auto it = idx.begin(); + while (it != idx.end() && it->block <= need_block) { + auto next_it = it; + ++next_it; + applied_operation op(*it); + database.remove(*it); + it = next_it; + } + } + } + void on_operation(const golos::chain::operation_notification& note) { if (!note.stored_in_db) { return; @@ -90,6 +107,7 @@ if( options.count(name) ) { \ note.op.visit(operation_visitor(database, note, item)); } } + erase_old_blocks(); } std::map get_account_history( @@ -115,6 +133,7 @@ if( options.count(name) ) { \ fc::flat_map tracked_accounts; golos::chain::database& database; + uint32_t history_blocks = UINT32_MAX; }; DEFINE_API(plugin, get_account_history) { @@ -375,6 +394,15 @@ if( options.count(name) ) { \ void plugin::plugin_initialize(const boost::program_options::variables_map& options) { ilog("account_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); + + if (options.count("history-blocks")) { + uint32_t history_blocks = options.at("history-blocks").as(); + pimpl->history_blocks = history_blocks; + } else { + pimpl->history_blocks = UINT32_MAX; + } + ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); + // this is worked, because the appbase initialize required plugins at first pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ pimpl->on_operation(note); From b63f366fa5377993a5380b7689afab1c59370dd1 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 29 Jun 2018 13:21:40 +0300 Subject: [PATCH 020/250] Remove exsessive code. #668 --- .../account_history/history_object.hpp | 10 ++-- plugins/account_history/plugin.cpp | 45 ++++++++-------- plugins/operation_history/plugin.cpp | 1 - tests/CMakeLists.txt | 8 ++- tests/plugin_tests/time_limit_options.cpp | 51 ------------------- 5 files changed, 33 insertions(+), 82 deletions(-) delete mode 100644 tests/plugin_tests/time_limit_options.cpp diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index b6a6b37858..2c371b3459 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -65,11 +65,11 @@ namespace golos { namespace plugins { namespace account_history { ordered_unique< tag, member>, - ordered_unique< - tag, - composite_key< - account_history_object, - member>>, +// ordered_unique< +// tag, +// composite_key< +// account_history_object, +// member>>, ordered_unique< tag, composite_key().indices().get(); - auto it = idx.begin(); - while (it != idx.end() && it->block <= need_block) { - auto next_it = it; - ++next_it; - applied_operation op(*it); - database.remove(*it); - it = next_it; - } - } - } + //void erase_old_blocks() { + // uint32_t head_block = database.head_block_num(); + // if (history_blocks <= head_block) { + // uint32_t need_block = head_block - history_blocks + 1; + // const auto& idx = database.get_index().indices().get(); + // auto it = idx.begin(); + // while (it != idx.end() && it->block <= need_block) { + // auto next_it = it; + // ++next_it; + // database.remove(*it); + // it = next_it; + // } + // } + //} void on_operation(const golos::chain::operation_notification& note) { if (!note.stored_in_db) { @@ -107,7 +106,7 @@ if( options.count(name) ) { \ note.op.visit(operation_visitor(database, note, item)); } } - erase_old_blocks(); + //erase_old_blocks(); } std::map get_account_history( @@ -395,13 +394,13 @@ if( options.count(name) ) { \ ilog("account_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); - if (options.count("history-blocks")) { - uint32_t history_blocks = options.at("history-blocks").as(); - pimpl->history_blocks = history_blocks; - } else { - pimpl->history_blocks = UINT32_MAX; - } - ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); + //if (options.count("history-blocks")) { + // uint32_t history_blocks = options.at("history-blocks").as(); + // pimpl->history_blocks = history_blocks; + //} else { + // pimpl->history_blocks = UINT32_MAX; + //} + //ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); // this is worked, because the appbase initialize required plugins at first pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index a86005b946..33a0fb998a 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -106,7 +106,6 @@ namespace golos { namespace plugins { namespace operation_history { while (it != idx.end() && it->block <= need_block) { auto next_it = it; ++next_it; - applied_operation op(*it); database.remove(*it); it = next_it; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2561f1cddf..e81951fd64 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -67,9 +67,13 @@ add_exec_test(NAME "black_options" FILES "plugin_tests/main.cpp" "plugin_tests/black_options_postfix.cpp") -add_exec_test(NAME "time_options" FILES +add_exec_test(NAME "operation_history_blocks" FILES "plugin_tests/main.cpp" - "plugin_tests/time_limit_options.cpp") + "plugin_tests/operation_history_blocks_test.cpp") + +add_exec_test(NAME "accaunt_history_blocks" FILES + "plugin_tests/main.cpp" + "plugin_tests/accaunt_history_blocks_test.cpp") if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") diff --git a/tests/plugin_tests/time_limit_options.cpp b/tests/plugin_tests/time_limit_options.cpp deleted file mode 100644 index a5addedab2..0000000000 --- a/tests/plugin_tests/time_limit_options.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -struct whitelist_key { - std::string key = "history-whitelist-ops"; -}; - - -static uint32_t HISTORY_BLOCKS = 2; - - -struct time_limit_key { - typedef uint32_t opt_type; - std::string key = "history-blocks"; - std::string opt = std::to_string(HISTORY_BLOCKS); -}; - - -BOOST_FIXTURE_TEST_CASE(time_limit_options, options_fixture) { - auto tops = test_options>(); - tops.fill_options(); - init_plugin(tops); - - size_t _chacked_ops_count = 0; - for (auto it = _finded_ops.begin(); it != _finded_ops.end(); ++it) { - auto iter = _db_init._added_ops.find(it->first); - bool is_finded = (iter != _db_init._added_ops.end()); - BOOST_CHECK(is_finded); - if (is_finded) { - BOOST_CHECK_EQUAL(iter->second, it->second); - if (iter->second == it->second) { - ++_chacked_ops_count; - } - } else { - BOOST_TEST_MESSAGE("Operation \"" + it->second + "\" by \"" + it->first + "\" is not found"); - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, HISTORY_BLOCKS); - -} From 0e5b69a7919a2e91b5f5edcb9476cae2e0f99c24 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 29 Jun 2018 13:30:30 +0300 Subject: [PATCH 021/250] Changed names for history blocks test cases. #668 --- .../account_history/history_object.hpp | 11 ++-- plugins/account_history/plugin.cpp | 44 ++++++++-------- .../accaunt_history_blocks_test.cpp | 15 ++++++ .../operation_history_blocks_test.cpp | 51 +++++++++++++++++++ 4 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 tests/plugin_tests/accaunt_history_blocks_test.cpp create mode 100644 tests/plugin_tests/operation_history_blocks_test.cpp diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index 2c371b3459..3a0c28a0c6 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -65,16 +65,15 @@ namespace golos { namespace plugins { namespace account_history { ordered_unique< tag, member>, -// ordered_unique< -// tag, -// composite_key< -// account_history_object, -// member>>, + ordered_unique< + tag, + composite_key< + account_history_object, + member>>, ordered_unique< tag, composite_key, - //member, member>, composite_key_compare, std::greater>>>, allocator>; diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index b1d9fda957..74cbb35f23 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -75,20 +75,20 @@ if( options.count(name) ) { \ ~plugin_impl() = default; - //void erase_old_blocks() { - // uint32_t head_block = database.head_block_num(); - // if (history_blocks <= head_block) { - // uint32_t need_block = head_block - history_blocks + 1; - // const auto& idx = database.get_index().indices().get(); - // auto it = idx.begin(); - // while (it != idx.end() && it->block <= need_block) { - // auto next_it = it; - // ++next_it; - // database.remove(*it); - // it = next_it; - // } - // } - //} + void erase_old_blocks() { + uint32_t head_block = database.head_block_num(); + if (history_blocks <= head_block) { + uint32_t need_block = head_block - history_blocks + 1; + const auto& idx = database.get_index().indices().get(); + auto it = idx.begin(); + while (it != idx.end() && it->block <= need_block) { + auto next_it = it; + ++next_it; + database.remove(*it); + it = next_it; + } + } + } void on_operation(const golos::chain::operation_notification& note) { if (!note.stored_in_db) { @@ -106,7 +106,7 @@ if( options.count(name) ) { \ note.op.visit(operation_visitor(database, note, item)); } } - //erase_old_blocks(); + erase_old_blocks(); } std::map get_account_history( @@ -394,13 +394,13 @@ if( options.count(name) ) { \ ilog("account_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); - //if (options.count("history-blocks")) { - // uint32_t history_blocks = options.at("history-blocks").as(); - // pimpl->history_blocks = history_blocks; - //} else { - // pimpl->history_blocks = UINT32_MAX; - //} - //ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); + if (options.count("history-blocks")) { + uint32_t history_blocks = options.at("history-blocks").as(); + pimpl->history_blocks = history_blocks; + } else { + pimpl->history_blocks = UINT32_MAX; + } + ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); // this is worked, because the appbase initialize required plugins at first pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ diff --git a/tests/plugin_tests/accaunt_history_blocks_test.cpp b/tests/plugin_tests/accaunt_history_blocks_test.cpp new file mode 100644 index 0000000000..8c87ee0f9d --- /dev/null +++ b/tests/plugin_tests/accaunt_history_blocks_test.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" + + +//using namespace golos::test; + + +//BOOST_FIXTURE_TEST_CASE(accaunt_history_blocks, options_fixture) { +//} diff --git a/tests/plugin_tests/operation_history_blocks_test.cpp b/tests/plugin_tests/operation_history_blocks_test.cpp new file mode 100644 index 0000000000..4251b78e1f --- /dev/null +++ b/tests/plugin_tests/operation_history_blocks_test.cpp @@ -0,0 +1,51 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_fixture.hpp" + + +using namespace golos::test; + + +struct whitelist_key { + std::string key = "history-whitelist-ops"; +}; + + +static uint32_t HISTORY_BLOCKS = 2; + + +struct time_limit_key { + typedef uint32_t opt_type; + std::string key = "history-blocks"; + std::string opt = std::to_string(HISTORY_BLOCKS); +}; + + +BOOST_FIXTURE_TEST_CASE(operation_history_blocks, options_fixture) { + auto tops = test_options>(); + tops.fill_options(); + init_plugin(tops); + + size_t _chacked_ops_count = 0; + for (auto it = _finded_ops.begin(); it != _finded_ops.end(); ++it) { + auto iter = _db_init._added_ops.find(it->first); + bool is_finded = (iter != _db_init._added_ops.end()); + BOOST_CHECK(is_finded); + if (is_finded) { + BOOST_CHECK_EQUAL(iter->second, it->second); + if (iter->second == it->second) { + ++_chacked_ops_count; + } + } else { + BOOST_TEST_MESSAGE("Operation \"" + it->second + "\" by \"" + it->first + "\" is not found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, HISTORY_BLOCKS); + +} From f89530f5dbbb45f88102565a39f7666991f0f960 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 29 Jun 2018 13:37:35 +0300 Subject: [PATCH 022/250] Added running options tests in Dockerfile-test. #668 --- share/golosd/docker/Dockerfile-test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 909c98ecf5..9cb7acdf39 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -46,7 +46,10 @@ RUN \ .. && \ make -j$(nproc) chain_test plugin_test && \ ./tests/chain_test --log_level=message --report_level=detailed && \ - ./tests/plugin_test --log_level=message --report_level=detailed + ./tests/plugin_test --log_level=message --report_level=detailed && \ + ./tests/white_options_test --log_level=message --report_level=detailed && \ + ./tests/black_options_test --log_level=message --report_level=detailed && \ + ./tests/operation_history_blocks_test --log_level=message --report_level=detailed # isn't used now, but can be used later ... # From 26f7bf662fdc45fa8a98236a211b8f05d4a2a3bd Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Fri, 29 Jun 2018 14:07:02 +0300 Subject: [PATCH 023/250] Change value string to static definition. #668 --- plugins/operation_history/plugin.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 33a0fb998a..cfb2b1981a 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -5,10 +5,12 @@ #include +#define STEEM_NAMESPACE_PREFIX "golos::protocol::" +#define OPERATION_POSTFIX "_operation" + #define CHECK_ARG_SIZE(s) \ FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); -static const char STEEM_NAMESPACE_PREFIX[] = "golos::protocol::"; namespace golos { namespace plugins { namespace operation_history { @@ -215,12 +217,11 @@ namespace golos { namespace plugins { namespace operation_history { for (const auto& op : ops) { if (op.size()) { - std::string ops_postfix("_operation"); - std::size_t pos = op.find(ops_postfix); - if (pos not_eq std::string::npos and (pos + ops_postfix.size()) == op.size()) { + std::size_t pos = op.find(OPERATION_POSTFIX); + if (pos not_eq std::string::npos and (pos + strlen(OPERATION_POSTFIX)) == op.size()) { pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op); } else { - pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + ops_postfix); + pimpl->ops_list.insert(STEEM_NAMESPACE_PREFIX + op + OPERATION_POSTFIX); } } } From e87b82262eb3b9396e21813a661d186fddeae60d Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Mon, 2 Jul 2018 11:56:03 +0300 Subject: [PATCH 024/250] The background of the account history test has been added. #668 --- libraries/chain/database.cpp | 1 + tests/CMakeLists.txt | 4 +- tests/common/database_fixture.cpp | 43 ++++++++++++++----- tests/common/database_fixture.hpp | 10 +++++ tests/common/options_fixture.cpp | 9 +++- tests/common/options_fixture.hpp | 26 +++++++++-- .../accaunt_history_blocks_test.cpp | 15 ------- .../account_history_blocks_test.cpp | 29 +++++++++++++ tests/plugin_tests/black_options_postfix.cpp | 2 +- .../operation_history_blocks_test.cpp | 6 +-- tests/plugin_tests/white_options_postfix.cpp | 2 +- 11 files changed, 109 insertions(+), 38 deletions(-) delete mode 100644 tests/plugin_tests/accaunt_history_blocks_test.cpp create mode 100644 tests/plugin_tests/account_history_blocks_test.cpp diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 2b7301e576..5ea09559d1 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1080,6 +1080,7 @@ namespace golos { namespace chain { if (!is_producing() || _enable_plugins_on_push_transaction) { STEEMIT_TRY_NOTIFY(pre_apply_operation, note); + pre_apply_operation(note); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e81951fd64..6971c121d3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -71,9 +71,9 @@ add_exec_test(NAME "operation_history_blocks" FILES "plugin_tests/main.cpp" "plugin_tests/operation_history_blocks_test.cpp") -add_exec_test(NAME "accaunt_history_blocks" FILES +add_exec_test(NAME "account_history_blocks" FILES "plugin_tests/main.cpp" - "plugin_tests/accaunt_history_blocks_test.cpp") + "plugin_tests/account_history_blocks_test.cpp") if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 819cc96ad1..9f1aab9bdd 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -99,8 +99,9 @@ namespace golos { namespace chain { FC_LOG_AND_RETHROW() } + template struct app_initialise { - golos::plugins::operation_history::plugin* _plg; + plugin_type* _plg; app_initialise() { int argc = boost::unit_test::framework::master_test_suite().argc; @@ -116,20 +117,22 @@ namespace golos { namespace chain { << std::endl; } } - _plg = &appbase::app().register_plugin(); + _plg = &appbase::app().register_plugin(); BOOST_REQUIRE(_plg); - appbase::app().initialize(argc, argv); + appbase::app().initialize(argc, argv); } }; - add_operations_database_fixture::add_operations_database_fixture() try { - ilog("add_operations_database_fixture: begin"); - _plg = app_initialise()._plg; - initialize(); - open_database(); - } catch (const fc::exception &e) { - edump((e.to_detail_string())); - throw; + add_operations_database_fixture::add_operations_database_fixture() : _plg(nullptr) { + try { + ilog("add_operations_database_fixture: begin"); + _plg = app_initialise()._plg; + initialize(); + open_database(); + } catch (const fc::exception &e) { + edump((e.to_detail_string())); + throw; + } } add_operations_database_fixture::~add_operations_database_fixture() try { @@ -217,6 +220,24 @@ namespace golos { namespace chain { validate_database(); } FC_LOG_AND_RETHROW(); + add_account_database_fixture::add_account_database_fixture() : _plg(nullptr) { + try { + ilog("add_operations_database_fixture: begin"); + _plg = app_initialise()._plg; + } catch (const fc::exception &e) { + edump((e.to_detail_string())); + throw; + } + } + + add_account_database_fixture::~add_account_database_fixture() try { + + } FC_LOG_AND_RETHROW(); + + void add_account_database_fixture::add_accounts() try { + + } FC_LOG_AND_RETHROW(); + fc::ecc::private_key database_fixture::generate_private_key(string seed) { return fc::ecc::private_key::regenerate(fc::sha256::hash(seed)); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 0075989a58..92585a0aea 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -316,6 +316,16 @@ namespace golos { namespace chain { std::map _added_ops; }; + struct add_account_database_fixture : public database_fixture { + add_account_database_fixture(); + + ~add_account_database_fixture() override; + + void add_accounts(); + + golos::plugins::account_history::plugin* _plg; + }; + namespace test { bool _push_block(database &db, const signed_block &b, uint32_t skip_flags = 0); diff --git a/tests/common/options_fixture.cpp b/tests/common/options_fixture.cpp index f02f006225..ec9be1e704 100644 --- a/tests/common/options_fixture.cpp +++ b/tests/common/options_fixture.cpp @@ -25,7 +25,7 @@ struct operation_visitor { } ovisit; -void options_fixture::log_applied_options(const applied_operation &opts) const { +void operation_options_fixture::log_applied_options(const applied_operation &opts) const { std::stringstream ss; ss << "[" << opts.block << "] "; ss << opts.trx_id.str() << " : "; /// golos::protocol::transaction_id_type @@ -35,7 +35,7 @@ void options_fixture::log_applied_options(const applied_operation &opts) const { } -void options_fixture::check_operations() { +void operation_options_fixture::check_operations() { uint32_t head_block_num = _db_init.db->head_block_num(); ilog("Check history operations, block num is " + std::to_string(head_block_num)); for (uint32_t i = 0; i <= head_block_num; ++i) { @@ -51,3 +51,8 @@ void options_fixture::check_operations() { } } } + + +void account_options_fixture::check() { + +} diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp index 288ba2bf4c..c8cd283ca1 100644 --- a/tests/common/options_fixture.hpp +++ b/tests/common/options_fixture.hpp @@ -97,12 +97,12 @@ struct test_options : public opt_type { }; -struct options_fixture { +struct operation_options_fixture { add_operations_database_fixture _db_init; chacked_operation_map _finded_ops; - options_fixture() = default; - ~options_fixture() = default; + operation_options_fixture() = default; + ~operation_options_fixture() = default; template void init_plugin(const test_type& tt) { @@ -118,4 +118,24 @@ struct options_fixture { void check_operations(); }; + + +struct account_options_fixture { + add_account_database_fixture _db_init; + + account_options_fixture() = default; + ~account_options_fixture() = default; + + template + void init_plugin(const test_type& tt) { + ilog(std::string("init_plugin(") + typeid(test_type).name() + ")"); + _db_init._plg->plugin_initialize(tt); + _db_init._plg->plugin_startup(); + _db_init.startup(); + _db_init.add_accounts(); + check(); + } + + void check(); +}; }} diff --git a/tests/plugin_tests/accaunt_history_blocks_test.cpp b/tests/plugin_tests/accaunt_history_blocks_test.cpp deleted file mode 100644 index 8c87ee0f9d..0000000000 --- a/tests/plugin_tests/accaunt_history_blocks_test.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" - - -//using namespace golos::test; - - -//BOOST_FIXTURE_TEST_CASE(accaunt_history_blocks, options_fixture) { -//} diff --git a/tests/plugin_tests/account_history_blocks_test.cpp b/tests/plugin_tests/account_history_blocks_test.cpp new file mode 100644 index 0000000000..85ebca5a6a --- /dev/null +++ b/tests/plugin_tests/account_history_blocks_test.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_fixture.hpp" + + +using namespace golos::test; + + +static uint32_t HISTORY_BLOCKS = 2; + + +struct account_options { + typedef uint32_t opt_type; + std::string key = "history-blocks"; + std::string opt = std::to_string(HISTORY_BLOCKS); + +}; + + +BOOST_FIXTURE_TEST_CASE(account_history_blocks, account_options_fixture) { + auto tops = test_options(); + init_plugin(tops); +} diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp index 3a655e2d8d..81ba5c67c9 100644 --- a/tests/plugin_tests/black_options_postfix.cpp +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -14,7 +14,7 @@ struct blacklist_key { }; -BOOST_FIXTURE_TEST_CASE(black_options_postfix, options_fixture) { +BOOST_FIXTURE_TEST_CASE(black_options_postfix, operation_options_fixture) { init_plugin(test_options>()); size_t _chacked_ops_count = 0; diff --git a/tests/plugin_tests/operation_history_blocks_test.cpp b/tests/plugin_tests/operation_history_blocks_test.cpp index 4251b78e1f..6ca1318cf5 100644 --- a/tests/plugin_tests/operation_history_blocks_test.cpp +++ b/tests/plugin_tests/operation_history_blocks_test.cpp @@ -20,16 +20,16 @@ struct whitelist_key { static uint32_t HISTORY_BLOCKS = 2; -struct time_limit_key { +struct blocks_limit_key { typedef uint32_t opt_type; std::string key = "history-blocks"; std::string opt = std::to_string(HISTORY_BLOCKS); }; -BOOST_FIXTURE_TEST_CASE(operation_history_blocks, options_fixture) { +BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { auto tops = test_options>(); - tops.fill_options(); + tops.fill_options(); init_plugin(tops); size_t _chacked_ops_count = 0; diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index 01d09f3339..75cd170fc7 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -14,7 +14,7 @@ struct whitelist_key { }; -BOOST_FIXTURE_TEST_CASE(white_options_postfix, options_fixture) { +BOOST_FIXTURE_TEST_CASE(white_options_postfix, operation_options_fixture) { init_plugin(test_options>()); size_t _chacked_ops_count = 0; From db70682998b8fc47872d08022b939ff73bbe30f8 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Mon, 2 Jul 2018 22:00:27 +0300 Subject: [PATCH 025/250] Fix database exceptions. #668 --- libraries/chain/database.cpp | 1 - .../account_history/history_object.hpp | 2 +- plugins/account_history/plugin.cpp | 2 +- plugins/operation_history/plugin.cpp | 15 +++++-- tests/common/database_fixture.cpp | 29 +++++++------ tests/common/database_fixture.hpp | 13 +++--- tests/common/options_fixture.cpp | 41 +++++++++++++++---- tests/common/options_fixture.hpp | 4 +- tests/plugin_tests/black_options_postfix.cpp | 8 ++-- .../operation_history_blocks_test.cpp | 8 ++-- tests/plugin_tests/white_options_postfix.cpp | 8 ++-- 11 files changed, 84 insertions(+), 47 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 5ea09559d1..2b7301e576 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1080,7 +1080,6 @@ namespace golos { namespace chain { if (!is_producing() || _enable_plugins_on_push_transaction) { STEEMIT_TRY_NOTIFY(pre_apply_operation, note); - pre_apply_operation(note); } } diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index 3a0c28a0c6..bce7aa4d82 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -65,7 +65,7 @@ namespace golos { namespace plugins { namespace account_history { ordered_unique< tag, member>, - ordered_unique< + ordered_non_unique< tag, composite_key< account_history_object, diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 74cbb35f23..be98c5b6c0 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -52,7 +52,7 @@ if( options.count(name) ) { \ void operator()(Op &&) const { const auto& idx = database.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(account, note.block, uint32_t(-1))); + auto itr = idx.lower_bound(std::make_tuple(account, uint32_t(-1))); uint32_t sequence = 0; if (itr != idx.end() && itr->account == account) { sequence = itr->sequence + 1; diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index cfb2b1981a..319d2702d1 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -115,8 +115,12 @@ namespace golos { namespace plugins { namespace operation_history { } void on_operation(golos::chain::operation_notification& note) { - note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); - erase_old_blocks(); + if (filter_content) { + note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); + erase_old_blocks(); + } else { + note.op.visit(operation_visitor(database, note, start_block)); + } } std::vector get_ops_in_block( @@ -150,9 +154,10 @@ namespace golos { namespace plugins { namespace operation_history { FC_ASSERT(false, "Unknown Transaction ${t}", ("t", id)); } + bool filter_content = false; uint32_t start_block = 0; uint32_t history_blocks = UINT32_MAX; - bool blacklist = false; + bool blacklist = true; fc::flat_set ops_list; golos::chain::database& database; }; @@ -233,16 +238,19 @@ namespace golos { namespace plugins { namespace operation_history { !options.count("history-blacklist-ops"), "history-blacklist-ops and history-whitelist-ops can't be specified together"); + pimpl->filter_content = true; pimpl->blacklist = false; split_list(options.at("history-whitelist-ops").as>()); ilog("operation_history: whitelisting ops ${o}", ("o", pimpl->ops_list)); } else if (options.count("history-blacklist-ops")) { + pimpl->filter_content = true; pimpl->blacklist = true; split_list(options.at("history-blacklist-ops").as>()); ilog("operation_history: blacklisting ops ${o}", ("o", pimpl->ops_list)); } if (options.count("history-start-block")) { + pimpl->filter_content = true; pimpl->start_block = options.at("history-start-block").as(); } else { pimpl->start_block = 0; @@ -250,6 +258,7 @@ namespace golos { namespace plugins { namespace operation_history { ilog("operation_history: start_block ${s}", ("s", pimpl->start_block)); if (options.count("history-blocks")) { + pimpl->filter_content = true; uint32_t history_blocks = options.at("history-blocks").as(); pimpl->history_blocks = history_blocks; } else { diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 9f1aab9bdd..9f2b52e244 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -99,11 +99,12 @@ namespace golos { namespace chain { FC_LOG_AND_RETHROW() } - template struct app_initialise { - plugin_type* _plg; + app_initialise() = default; + ~app_initialise() = default; - app_initialise() { + template + plugin_type* get_plugin() { int argc = boost::unit_test::framework::master_test_suite().argc; char **argv = boost::unit_test::framework::master_test_suite().argv; for (int i = 1; i < argc; i++) { @@ -117,16 +118,16 @@ namespace golos { namespace chain { << std::endl; } } - _plg = &appbase::app().register_plugin(); - BOOST_REQUIRE(_plg); + auto plg = &appbase::app().register_plugin(); appbase::app().initialize(argc, argv); + return plg; } }; add_operations_database_fixture::add_operations_database_fixture() : _plg(nullptr) { try { ilog("add_operations_database_fixture: begin"); - _plg = app_initialise()._plg; + _plg = app_initialise().get_plugin(); initialize(); open_database(); } catch (const fc::exception &e) { @@ -220,21 +221,23 @@ namespace golos { namespace chain { validate_database(); } FC_LOG_AND_RETHROW(); - add_account_database_fixture::add_account_database_fixture() : _plg(nullptr) { + add_accounts_database_fixture::add_accounts_database_fixture() : _plg(nullptr) { try { - ilog("add_operations_database_fixture: begin"); - _plg = app_initialise()._plg; + ilog("add_accounts_database_fixture: begin"); + _plg = app_initialise().get_plugin(); + initialize(); + open_database(); } catch (const fc::exception &e) { edump((e.to_detail_string())); throw; } } - add_account_database_fixture::~add_account_database_fixture() try { - - } FC_LOG_AND_RETHROW(); + add_accounts_database_fixture::~add_accounts_database_fixture() { + ilog("add_accounts_database_fixture: end"); + } - void add_account_database_fixture::add_accounts() try { + void add_accounts_database_fixture::add_accounts() try { } FC_LOG_AND_RETHROW(); diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 92585a0aea..6c6899d5f5 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -306,24 +306,27 @@ namespace golos { namespace chain { }; struct add_operations_database_fixture : public database_fixture { + typedef golos::plugins::operation_history::plugin plugin_type; add_operations_database_fixture(); ~add_operations_database_fixture() override; void add_operations(); - golos::plugins::operation_history::plugin* _plg; + plugin_type* _plg; std::map _added_ops; }; - struct add_account_database_fixture : public database_fixture { - add_account_database_fixture(); + struct add_accounts_database_fixture : public database_fixture { + typedef golos::plugins::account_history::plugin plugin_type; + add_accounts_database_fixture(); - ~add_account_database_fixture() override; + ~add_accounts_database_fixture() override; void add_accounts(); - golos::plugins::account_history::plugin* _plg; + plugin_type* _plg; + std::list _added_accs; }; namespace test { diff --git a/tests/common/options_fixture.cpp b/tests/common/options_fixture.cpp index ec9be1e704..451bda5a69 100644 --- a/tests/common/options_fixture.cpp +++ b/tests/common/options_fixture.cpp @@ -38,21 +38,44 @@ void operation_options_fixture::log_applied_options(const applied_operation &opt void operation_options_fixture::check_operations() { uint32_t head_block_num = _db_init.db->head_block_num(); ilog("Check history operations, block num is " + std::to_string(head_block_num)); - for (uint32_t i = 0; i <= head_block_num; ++i) { - msg_pack mo; - mo.args = std::vector({fc::variant(i), fc::variant(false)}); - auto ops = _db_init._plg->get_ops_in_block(mo); - for (auto o : ops) { - auto iter = _finded_ops.find(o.trx_id.str()); - if (iter == _finded_ops.end()) { - _finded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); - log_applied_options(o); + auto plg = _db_init._plg; + if (plg) { + for (uint32_t i = 0; i <= head_block_num; ++i) { + msg_pack mo; + mo.args = std::vector({fc::variant(i), fc::variant(false)}); + auto ops = plg->get_ops_in_block(mo); + for (auto o : ops) { + auto iter = _founded_ops.find(o.trx_id.str()); + if (iter == _founded_ops.end()) { + _founded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); + log_applied_options(o); + } } } + } else { + ilog("Operation history plugin is not inited."); } } void account_options_fixture::check() { + uint32_t head_block_num = _db_init.db->head_block_num(); + ilog("Check history accounts, block num is " + std::to_string(head_block_num)); + auto plg = _db_init._plg; + if (plg) { + fc::flat_map accs = plg->tracked_accounts(); + for (auto a : accs) { + ilog("{\"" + a.first + "\":\"" + a.second + "\"}"); + } + } else { + ilog("Account history plugin is not inited."); + } + //for (uint32_t i = 0; i <= head_block_num; ++i) { + // msg_pack mp; + // std::string account = ""; + // uint64_t from = 0; + // uint32_t limit = 0; + // mp.args = std::vector({fc::variant(account), fc::variant(from), fc::variant(limit)}); + //} } diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp index c8cd283ca1..7debe5d170 100644 --- a/tests/common/options_fixture.hpp +++ b/tests/common/options_fixture.hpp @@ -99,7 +99,7 @@ struct test_options : public opt_type { struct operation_options_fixture { add_operations_database_fixture _db_init; - chacked_operation_map _finded_ops; + chacked_operation_map _founded_ops; operation_options_fixture() = default; ~operation_options_fixture() = default; @@ -121,7 +121,7 @@ struct operation_options_fixture { struct account_options_fixture { - add_account_database_fixture _db_init; + add_accounts_database_fixture _db_init; account_options_fixture() = default; ~account_options_fixture() = default; diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp index 81ba5c67c9..ea76ea01c2 100644 --- a/tests/plugin_tests/black_options_postfix.cpp +++ b/tests/plugin_tests/black_options_postfix.cpp @@ -19,10 +19,10 @@ BOOST_FIXTURE_TEST_CASE(black_options_postfix, operation_options_fixture) { size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { - auto iter = _finded_ops.find(co.first); - bool is_not_finded = (iter == _finded_ops.end()); - BOOST_CHECK(is_not_finded); - if (is_not_finded) { + auto iter = _founded_ops.find(co.first); + bool is_not_found = (iter == _founded_ops.end()); + BOOST_CHECK(is_not_found); + if (is_not_found) { ++_chacked_ops_count; } else { BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is found"); diff --git a/tests/plugin_tests/operation_history_blocks_test.cpp b/tests/plugin_tests/operation_history_blocks_test.cpp index 6ca1318cf5..b06c94fdb1 100644 --- a/tests/plugin_tests/operation_history_blocks_test.cpp +++ b/tests/plugin_tests/operation_history_blocks_test.cpp @@ -33,11 +33,11 @@ BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { init_plugin(tops); size_t _chacked_ops_count = 0; - for (auto it = _finded_ops.begin(); it != _finded_ops.end(); ++it) { + for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { auto iter = _db_init._added_ops.find(it->first); - bool is_finded = (iter != _db_init._added_ops.end()); - BOOST_CHECK(is_finded); - if (is_finded) { + bool is_found= (iter != _db_init._added_ops.end()); + BOOST_CHECK(is_found); + if (is_found) { BOOST_CHECK_EQUAL(iter->second, it->second); if (iter->second == it->second) { ++_chacked_ops_count; diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp index 75cd170fc7..8d8b1d89e0 100644 --- a/tests/plugin_tests/white_options_postfix.cpp +++ b/tests/plugin_tests/white_options_postfix.cpp @@ -19,10 +19,10 @@ BOOST_FIXTURE_TEST_CASE(white_options_postfix, operation_options_fixture) { size_t _chacked_ops_count = 0; for (const auto &co : _db_init._added_ops) { - auto iter = _finded_ops.find(co.first); - bool is_finded = (iter != _finded_ops.end()); - BOOST_CHECK(is_finded); - if (is_finded) { + auto iter = _founded_ops.find(co.first); + bool is_found = (iter != _founded_ops.end()); + BOOST_CHECK(is_found); + if (is_found) { BOOST_CHECK_EQUAL(iter->second, co.second); if (iter->second == co.second) { ++_chacked_ops_count; From 184fe0e4f304a45500629aea61ea57458a5e0e2c Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Tue, 3 Jul 2018 10:33:37 +0300 Subject: [PATCH 026/250] Added executing for test targets. #668 --- share/golosd/docker/Dockerfile-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 9cb7acdf39..0817ef812a 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,7 +44,7 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test && \ + make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test && \ ./tests/chain_test --log_level=message --report_level=detailed && \ ./tests/plugin_test --log_level=message --report_level=detailed && \ ./tests/white_options_test --log_level=message --report_level=detailed && \ From 0e713519f9c738158f70acb3e38a82519eaa0419 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Tue, 3 Jul 2018 14:31:16 +0300 Subject: [PATCH 027/250] Added account history blocks test. #668 --- plugins/account_history/plugin.cpp | 2 +- share/golosd/docker/Dockerfile-test | 6 +++-- tests/common/database_fixture.cpp | 9 ++++++- tests/common/database_fixture.hpp | 9 ++++--- tests/common/options_fixture.cpp | 25 +++++++++++-------- tests/common/options_fixture.hpp | 6 +++-- .../account_history_blocks_test.cpp | 19 ++++++++++++-- .../operation_history_blocks_test.cpp | 3 +-- 8 files changed, 54 insertions(+), 25 deletions(-) diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index be98c5b6c0..b105d2fe5a 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -400,7 +400,7 @@ if( options.count(name) ) { \ } else { pimpl->history_blocks = UINT32_MAX; } - ilog("operation_history: history-blocks ${s}", ("s", pimpl->history_blocks)); + ilog("account_history: history-blocks ${s}", ("s", pimpl->history_blocks)); // this is worked, because the appbase initialize required plugins at first pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 0817ef812a..89a3c32617 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,12 +44,14 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test && \ + make -j$(nproc) chain_test plugin_test \ + black_options_test white_options_test operation_history_blocks_test account_history_blocks && \ ./tests/chain_test --log_level=message --report_level=detailed && \ ./tests/plugin_test --log_level=message --report_level=detailed && \ ./tests/white_options_test --log_level=message --report_level=detailed && \ ./tests/black_options_test --log_level=message --report_level=detailed && \ - ./tests/operation_history_blocks_test --log_level=message --report_level=detailed + ./tests/operation_history_blocks_test --log_level=message --report_level=detailed \ + ./tests/account_history_blocks --log_level=message --report_level=detailed \ # isn't used now, but can be used later ... # diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 9f2b52e244..b449a60313 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -127,6 +127,7 @@ namespace golos { namespace chain { add_operations_database_fixture::add_operations_database_fixture() : _plg(nullptr) { try { ilog("add_operations_database_fixture: begin"); + _plg = app_initialise().get_plugin(); initialize(); open_database(); @@ -224,6 +225,12 @@ namespace golos { namespace chain { add_accounts_database_fixture::add_accounts_database_fixture() : _plg(nullptr) { try { ilog("add_accounts_database_fixture: begin"); + + _account_names.insert("alice"); + _account_names.insert("bob"); + _account_names.insert("sam"); + _account_names.insert("dave"); + _plg = app_initialise().get_plugin(); initialize(); open_database(); @@ -238,7 +245,7 @@ namespace golos { namespace chain { } void add_accounts_database_fixture::add_accounts() try { - + add_operations_database_fixture::add_operations(); } FC_LOG_AND_RETHROW(); fc::ecc::private_key database_fixture::generate_private_key(string seed) { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 6c6899d5f5..63250babf5 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -307,8 +307,8 @@ namespace golos { namespace chain { struct add_operations_database_fixture : public database_fixture { typedef golos::plugins::operation_history::plugin plugin_type; - add_operations_database_fixture(); + add_operations_database_fixture(); ~add_operations_database_fixture() override; void add_operations(); @@ -317,16 +317,17 @@ namespace golos { namespace chain { std::map _added_ops; }; - struct add_accounts_database_fixture : public database_fixture { + struct add_accounts_database_fixture : public add_operations_database_fixture { typedef golos::plugins::account_history::plugin plugin_type; - add_accounts_database_fixture(); + add_accounts_database_fixture(); ~add_accounts_database_fixture() override; void add_accounts(); plugin_type* _plg; - std::list _added_accs; + fc::flat_set _account_names; + //fc::flat_map _added_accounts; }; namespace test { diff --git a/tests/common/options_fixture.cpp b/tests/common/options_fixture.cpp index 451bda5a69..1f48c7089e 100644 --- a/tests/common/options_fixture.cpp +++ b/tests/common/options_fixture.cpp @@ -63,19 +63,22 @@ void account_options_fixture::check() { ilog("Check history accounts, block num is " + std::to_string(head_block_num)); auto plg = _db_init._plg; if (plg) { - fc::flat_map accs = plg->tracked_accounts(); - for (auto a : accs) { - ilog("{\"" + a.first + "\":\"" + a.second + "\"}"); + for (auto n : _db_init._account_names) { + msg_pack mp; + mp.args = std::vector({fc::variant(n), fc::variant(100), fc::variant(100)}); + auto accs = plg->get_account_history(mp); + for (auto a : accs) { + auto it = _founded_accs.find(a.second.block); + if (it == _founded_accs.end()) { + std::set set; + set.insert(n); + _founded_accs.insert(std::make_pair(a.second.block, set)); + } else { + it->second.insert(n); + } + } } } else { ilog("Account history plugin is not inited."); } - - //for (uint32_t i = 0; i <= head_block_num; ++i) { - // msg_pack mp; - // std::string account = ""; - // uint64_t from = 0; - // uint32_t limit = 0; - // mp.args = std::vector({fc::variant(account), fc::variant(from), fc::variant(limit)}); - //} } diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp index 7debe5d170..24d825c44f 100644 --- a/tests/common/options_fixture.hpp +++ b/tests/common/options_fixture.hpp @@ -25,7 +25,8 @@ using namespace golos::chain; typedef golos::plugins::operation_history::applied_operation applied_operation; -typedef std::map chacked_operation_map; ///< pair { [itx_id], [operation name] } +typedef std::map chacked_operations_map; ///< pair { [itx_id], [operation name] } +typedef std::map> chacked_accounts_map; ///< pair { [block], [accaunt names] } template @@ -99,7 +100,7 @@ struct test_options : public opt_type { struct operation_options_fixture { add_operations_database_fixture _db_init; - chacked_operation_map _founded_ops; + chacked_operations_map _founded_ops; operation_options_fixture() = default; ~operation_options_fixture() = default; @@ -122,6 +123,7 @@ struct operation_options_fixture { struct account_options_fixture { add_accounts_database_fixture _db_init; + chacked_accounts_map _founded_accs; account_options_fixture() = default; ~account_options_fixture() = default; diff --git a/tests/plugin_tests/account_history_blocks_test.cpp b/tests/plugin_tests/account_history_blocks_test.cpp index 85ebca5a6a..d844f3cd0f 100644 --- a/tests/plugin_tests/account_history_blocks_test.cpp +++ b/tests/plugin_tests/account_history_blocks_test.cpp @@ -12,18 +12,33 @@ using namespace golos::test; -static uint32_t HISTORY_BLOCKS = 2; +static uint32_t HISTORY_BLOCKS = 3; struct account_options { typedef uint32_t opt_type; std::string key = "history-blocks"; std::string opt = std::to_string(HISTORY_BLOCKS); - }; BOOST_FIXTURE_TEST_CASE(account_history_blocks, account_options_fixture) { auto tops = test_options(); init_plugin(tops); + + std::set blocks; + for (auto a : _founded_accs) { + for (auto n : a.second) { + ilog("block:" + std::to_string(a.first) + ", \"" + n + "\""); + auto iter = _db_init._account_names.find(n); + bool is_found = (iter != _db_init._account_names.end()); + BOOST_CHECK(is_found); + if (is_found) { + blocks.insert(a.first); + } else { + BOOST_TEST_MESSAGE("Account [" + std::to_string(a.first) + "]: \"" + n + "\" is not found"); + } + } + } + BOOST_CHECK_EQUAL(blocks.size(), HISTORY_BLOCKS); } diff --git a/tests/plugin_tests/operation_history_blocks_test.cpp b/tests/plugin_tests/operation_history_blocks_test.cpp index b06c94fdb1..6c1787e256 100644 --- a/tests/plugin_tests/operation_history_blocks_test.cpp +++ b/tests/plugin_tests/operation_history_blocks_test.cpp @@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { size_t _chacked_ops_count = 0; for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { auto iter = _db_init._added_ops.find(it->first); - bool is_found= (iter != _db_init._added_ops.end()); + bool is_found = (iter != _db_init._added_ops.end()); BOOST_CHECK(is_found); if (is_found) { BOOST_CHECK_EQUAL(iter->second, it->second); @@ -47,5 +47,4 @@ BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { } } BOOST_CHECK_EQUAL(_chacked_ops_count, HISTORY_BLOCKS); - } From 9e2719e3b47545a4bfe389137248df2229873bb1 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 4 Jul 2018 11:13:17 +0300 Subject: [PATCH 028/250] Fix compile commands in docker test. #668 --- share/golosd/docker/Dockerfile-test | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 89a3c32617..85a2ef1760 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,14 +44,13 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test \ - black_options_test white_options_test operation_history_blocks_test account_history_blocks && \ + make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test account_history_blocks && \ ./tests/chain_test --log_level=message --report_level=detailed && \ ./tests/plugin_test --log_level=message --report_level=detailed && \ ./tests/white_options_test --log_level=message --report_level=detailed && \ ./tests/black_options_test --log_level=message --report_level=detailed && \ - ./tests/operation_history_blocks_test --log_level=message --report_level=detailed \ - ./tests/account_history_blocks --log_level=message --report_level=detailed \ + ./tests/operation_history_blocks_test --log_level=message --report_level=detailed && \ + ./tests/account_history_blocks --log_level=message --report_level=detailed # isn't used now, but can be used later ... # From ee56cb381fe02625c58f71565168aae66ea7e412 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 4 Jul 2018 13:26:20 +0300 Subject: [PATCH 029/250] Fix target name in make command. #668 --- share/golosd/docker/Dockerfile-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 85a2ef1760..bb50a9a3c2 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,7 +44,7 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test account_history_blocks && \ + make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test account_history_blocks_test && \ ./tests/chain_test --log_level=message --report_level=detailed && \ ./tests/plugin_test --log_level=message --report_level=detailed && \ ./tests/white_options_test --log_level=message --report_level=detailed && \ From 21d874678f9fc4d54b966b8ade1950d06ba4c887 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Wed, 4 Jul 2018 13:48:58 +0300 Subject: [PATCH 030/250] Fix runin name in docker test. #668 --- share/golosd/docker/Dockerfile-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index bb50a9a3c2..78de08a0ae 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -50,7 +50,7 @@ RUN \ ./tests/white_options_test --log_level=message --report_level=detailed && \ ./tests/black_options_test --log_level=message --report_level=detailed && \ ./tests/operation_history_blocks_test --log_level=message --report_level=detailed && \ - ./tests/account_history_blocks --log_level=message --report_level=detailed + ./tests/account_history_blocks_test --log_level=message --report_level=detailed # isn't used now, but can be used later ... # From 3811acee7630d883073552c8443dbf791782ee5c Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Mon, 2 Jul 2018 15:51:18 +0300 Subject: [PATCH 031/250] Add config flag to store/not account metadata in db, mongo #794 --- libraries/api/account_api_object.cpp | 8 +- libraries/chain/database.cpp | 78 ++++++---- .../chain/include/golos/chain/database.hpp | 11 ++ libraries/chain/steem_evaluator.cpp | 10 +- plugins/chain/plugin.cpp | 30 ++++ plugins/mongo_db/mongo_db_state.cpp | 9 +- tests/CMakeLists.txt | 1 + tests/tests/operation_tests.cpp | 140 ++++++++++++++++-- 8 files changed, 240 insertions(+), 47 deletions(-) diff --git a/libraries/api/account_api_object.cpp b/libraries/api/account_api_object.cpp index 8558ae8490..b5bfe56591 100644 --- a/libraries/api/account_api_object.cpp +++ b/libraries/api/account_api_object.cpp @@ -44,10 +44,10 @@ account_api_object::account_api_object(const account_object& a, const golos::cha posting = authority(auth.posting); last_owner_update = auth.last_owner_update; -#ifndef IS_LOW_MEM - const auto& meta = db.get(name); - json_metadata = golos::chain::to_string(meta.json_metadata); -#endif + auto meta = db.find(name); + if (meta != nullptr) { + json_metadata = golos::chain::to_string(meta->json_metadata); + } auto post = db.find(std::make_tuple(name, bandwidth_type::post)); if (post != nullptr) { diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index a3c72171a4..e8f5f35f77 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -352,6 +352,22 @@ namespace golos { namespace chain { return _clear_votes_block > head_block_num(); } + void database::set_store_account_metadata(store_metadata_modes store_account_metadata) { + _store_account_metadata = store_account_metadata; + } + + void database::set_accounts_to_store_metadata(const std::vector& accounts_to_store_metadata) { + _accounts_to_store_metadata = accounts_to_store_metadata; + } + + bool database::store_metadata_for_account(const std::string& name) const { + if (_store_account_metadata != store_metadata_for_listed) { + return _store_account_metadata == store_metadata_for_all; + } + auto& v = _accounts_to_store_metadata; + return std::find(v.begin(), v.end(), name) != v.end(); + } + void database::set_skip_virtual_ops() { _skip_virtual_ops = true; } @@ -3011,11 +3027,13 @@ namespace golos { namespace chain { create([&](account_object &a) { a.name = STEEMIT_MINER_ACCOUNT; }); -#ifndef IS_LOW_MEM - create([&](account_metadata_object& m) { - m.account = STEEMIT_MINER_ACCOUNT; - }); -#endif + + if (store_metadata_for_account(STEEMIT_MINER_ACCOUNT)) { + create([&](account_metadata_object& m) { + m.account = STEEMIT_MINER_ACCOUNT; + }); + } + create([&](account_authority_object &auth) { auth.account = STEEMIT_MINER_ACCOUNT; auth.owner.weight_threshold = 1; @@ -3025,11 +3043,13 @@ namespace golos { namespace chain { create([&](account_object &a) { a.name = STEEMIT_NULL_ACCOUNT; }); -#ifndef IS_LOW_MEM - create([&](account_metadata_object& m) { - m.account = STEEMIT_NULL_ACCOUNT; - }); -#endif + + if (store_metadata_for_account(STEEMIT_NULL_ACCOUNT)) { + create([&](account_metadata_object& m) { + m.account = STEEMIT_NULL_ACCOUNT; + }); + } + create([&](account_authority_object &auth) { auth.account = STEEMIT_NULL_ACCOUNT; auth.owner.weight_threshold = 1; @@ -3039,11 +3059,13 @@ namespace golos { namespace chain { create([&](account_object &a) { a.name = STEEMIT_TEMP_ACCOUNT; }); -#ifndef IS_LOW_MEM - create([&](account_metadata_object& m) { - m.account = STEEMIT_TEMP_ACCOUNT; - }); -#endif + + if (store_metadata_for_account(STEEMIT_TEMP_ACCOUNT)) { + create([&](account_metadata_object& m) { + m.account = STEEMIT_TEMP_ACCOUNT; + }); + } + create([&](account_authority_object &auth) { auth.account = STEEMIT_TEMP_ACCOUNT; auth.owner.weight_threshold = 0; @@ -3057,11 +3079,13 @@ namespace golos { namespace chain { a.memo_key = init_public_key; a.balance = asset(i ? 0 : init_supply, STEEM_SYMBOL); }); -#ifndef IS_LOW_MEM - create([&](account_metadata_object& m) { - m.account = name; - }); -#endif + + if (store_metadata_for_account(name)) { + create([&](account_metadata_object& m) { + m.account = name; + }); + } + create([&](account_authority_object &auth) { auth.account = name; auth.owner.add_authority(init_public_key, 1); @@ -3120,12 +3144,14 @@ namespace golos { namespace chain { a.memo_key = account.keys.memo_key; a.recovery_account = STEEMIT_INIT_MINER_NAME; }); -#ifndef IS_LOW_MEM - create([&](account_metadata_object& m) { - m.account = account.name; - m.json_metadata = "{created_at: 'GENESIS'}"; - }); -#endif + + if (store_metadata_for_account(account.name)) { + create([&](account_metadata_object& m) { + m.account = account.name; + m.json_metadata = "{created_at: 'GENESIS'}"; + }); + } + create([&](account_authority_object& auth) { auth.account = account.name; auth.owner.weight_threshold = 1; diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index bee9b10fa9..b64d6075ed 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -72,6 +72,12 @@ namespace golos { namespace chain { skip_database_locking = 1 << 15 ///< used to skip locking of database }; + enum store_metadata_modes { + store_metadata_for_all, + store_metadata_for_listed, + store_metadata_for_nobody + }; + /** * @brief Open a database, creating a new one if necessary * @@ -99,6 +105,9 @@ namespace golos { namespace chain { void set_clear_votes(uint32_t clear_votes_block); void set_skip_virtual_ops(); bool clear_votes(); + void set_store_account_metadata(store_metadata_modes store_account_metadata); + void set_accounts_to_store_metadata(const std::vector& accounts_to_store_metadata); + bool store_metadata_for_account(const std::string& name) const; /** * @brief wipe Delete database from disk, and potentially the raw chain as well. @@ -618,6 +627,8 @@ namespace golos { namespace chain { uint32_t _clear_votes_block = 0; bool _skip_virtual_ops = false; bool _enable_plugins_on_push_transaction = true; + store_metadata_modes _store_account_metadata = store_metadata_for_all; + std::vector _accounts_to_store_metadata; flat_map> _custom_operation_interpreters; std::string _json_schema; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 2016d98eda..7b46405150 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -87,7 +87,14 @@ namespace golos { namespace chain { void store_account_json_metadata( database& db, const account_name_type& account, const string& json_metadata, bool skip_empty = false ) { -#ifndef IS_LOW_MEM + if (!db.store_metadata_for_account(account)) { + auto meta = db.find(account); + if (meta != nullptr) { + db.remove(*meta); + } + return; + } + if (skip_empty && json_metadata.size() == 0) return; @@ -104,7 +111,6 @@ namespace golos { namespace chain { from_string(a.json_metadata, json_metadata); }); } -#endif } void account_create_evaluator::do_apply(const account_create_operation &o) { diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 35abd8c294..b25ea08ecf 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -55,6 +55,10 @@ namespace chain { bool single_write_thread = false; + golos::chain::database::store_metadata_modes store_account_metadata; + + std::vector accounts_to_store_metadata; + plugin_impl() { // get default settings read_wait_micro = db.read_wait_micro(); @@ -232,6 +236,12 @@ namespace chain { ) ( "replay-if-corrupted", boost::program_options::bool_switch()->default_value(true), "replay all blocks if shared memory is corrupted" + ) ( + "store-account-metadata", boost::program_options::value(), + "store account metadata for all accounts if true, for no one if else, otherwise for specified in store-account-metadata-list" + ) ( + "store-account-metadata-list", boost::program_options::value(), + "names of accounts to store metadata" ); cli.add_options() ( @@ -313,6 +323,22 @@ namespace chain { my->loaded_checkpoints[item.first] = item.second; } } + + if (options.count("store-account-metadata")) { + if (options.at("store-account-metadata").as()) { + my->store_account_metadata = golos::chain::database::store_metadata_for_all; + } else { + my->store_account_metadata = golos::chain::database::store_metadata_for_nobody; + wlog("Account metadata will be not stored for any item of store-account-metadata-list because store-account-metadata is false"); + } + } else { + my->store_account_metadata = golos::chain::database::store_metadata_for_listed; + } + + if (options.count("store-account-metadata-list")) { + std::string str_accs = options["store-account-metadata-list"].as(); + my->accounts_to_store_metadata = fc::json::from_string(str_accs).as>(); + } } void plugin::plugin_startup() { @@ -339,6 +365,10 @@ namespace chain { my->db.set_clear_votes(my->clear_votes_before_block); + my->db.set_store_account_metadata(my->store_account_metadata); + + my->db.set_accounts_to_store_metadata(my->accounts_to_store_metadata); + if(my->skip_virtual_ops) { my->db.set_skip_virtual_ops(); } diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 7578bb5242..a6429dcb0f 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -239,11 +239,10 @@ namespace mongo_db { format_value(body, "last_post", account.last_post); -#ifndef IS_LOW_MEM - auto& account_metadata = db_.get(account.name); - - format_value(body, "json_metadata", account_metadata.json_metadata); -#endif + auto account_metadata = db_.find(account.name); + if (account_metadata != nullptr) { + format_value(body, "json_metadata", account_metadata->json_metadata); + } body << close_document; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9f89f682db..0d1c062f96 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,6 +24,7 @@ target_link_libraries( golos_account_history golos_market_history golos_debug_node + golos::api fc ${PLATFORM_SPECIFIC_LIBS}) add_test(NAME chain_test_run COMMAND chain_test) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 7dfce6c315..1e3bc48225 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include "database_fixture.hpp" @@ -18,6 +20,7 @@ #include using namespace golos; +using namespace golos::api; using namespace golos::chain; using namespace golos::protocol; using std::string; @@ -6669,9 +6672,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE(account_metadata_apply) { + // WARNING: it should be before another metadata apply tests + BOOST_AUTO_TEST_CASE(account_metadata_apply_store_for_all) { try { - BOOST_TEST_MESSAGE("Testing: account_metadata_apply"); + BOOST_TEST_MESSAGE("Testing: account_metadata_apply_store_for_all"); + + // Do not set any settings related to storing of account metadata + // and it should store for all. + signed_transaction tx; ACTOR(alice); @@ -6685,18 +6693,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) push_tx_with_ops(tx, alice_private_key, op); generate_blocks(10); - auto acc = db->get_account("alice"); -#ifndef IS_LOW_MEM + auto alice_acc = db->get_account("alice"); auto meta = db->get("alice"); BOOST_REQUIRE(meta.account == "alice"); BOOST_REQUIRE(meta.json_metadata == json); -#endif - BOOST_REQUIRE(acc.last_account_update == now); + BOOST_REQUIRE(alice_acc.last_account_update == now); + + BOOST_TEST_MESSAGE("----- Test API"); + account_api_object alice_api(alice_acc, *db); + BOOST_REQUIRE(alice_api.json_metadata == json); -#ifndef IS_LOW_MEM BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create"); + // bob is created before all metadata storing settings + // therefore it should have account_metadata_object ACTOR(bob); // create_account with json_metadata = "" - meta = db->get("bob"); + meta = db->get("bob"); // just checks presence, throws on fail BOOST_REQUIRE(meta.account == "bob"); BOOST_REQUIRE(meta.json_metadata == ""); @@ -6712,13 +6723,122 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) cr.owner = authority(1, priv_key.get_public_key(), 1); cr.active = authority(1, priv_key.get_public_key(), 1); cr.memo_key = priv_key.get_public_key(); - // cr.json_metadata = ""; // don't set push_tx_with_ops(tx, bob_private_key, cr); meta = db->get("sam"); BOOST_REQUIRE(meta.account == "sam"); BOOST_REQUIRE(meta.json_metadata == ""); -#endif + validate_database(); + } + FC_LOG_AND_RETHROW() + } + + BOOST_AUTO_TEST_CASE(account_metadata_apply_store_for_nobody) { + try { + BOOST_TEST_MESSAGE("Testing: account_metadata_apply_store_for_nobody"); + + db->set_store_account_metadata(database::store_metadata_for_nobody); + // Add account to list to check restriction works + std::vector accs_v; + accs_v.push_back("alice"); + accs_v.push_back("sam"); + db->set_accounts_to_store_metadata(accs_v); + + signed_transaction tx; + ACTOR(alice); + + BOOST_TEST_MESSAGE("--- Test success under normal conditions"); + generate_blocks(10); + const auto json = "{\"test\":1}"; + auto now = db->head_block_time(); + account_metadata_operation op; + op.account = "alice"; + op.json_metadata = json; + push_tx_with_ops(tx, alice_private_key, op); + generate_blocks(10); + + auto alice_acc = db->get_account("alice"); + auto meta = db->find("alice"); + BOOST_REQUIRE(meta == nullptr); + BOOST_REQUIRE(alice_acc.last_account_update == now); + + BOOST_TEST_MESSAGE("----- Test API"); + account_api_object alice_api(alice_acc, *db); + BOOST_REQUIRE(alice_api.json_metadata == ""); + + ACTOR(bob); // create_account with json_metadata = "" + + BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create_with_delegation"); + generate_blocks(1); + fund("bob", ASSET_GOLOS(1000)); + private_key_type priv_key = generate_private_key("temp_key"); + account_create_with_delegation_operation cr; + cr.fee = ASSET_GOLOS(1000); + cr.delegation = ASSET_GESTS(0); + cr.creator = "bob"; + cr.new_account_name = "sam"; + cr.owner = authority(1, priv_key.get_public_key(), 1); + cr.active = authority(1, priv_key.get_public_key(), 1); + cr.memo_key = priv_key.get_public_key(); + push_tx_with_ops(tx, bob_private_key, cr); + + meta = db->find("sam"); + BOOST_REQUIRE(meta == nullptr); + validate_database(); + } + FC_LOG_AND_RETHROW() + } + + BOOST_AUTO_TEST_CASE(account_metadata_apply_store_for_listed) { + try { + BOOST_TEST_MESSAGE("Testing: account_metadata_apply_store_for_listed"); + + db->set_store_account_metadata(database::store_metadata_for_listed); + // Add account to list to check restriction works + std::vector accs_v; + accs_v.push_back("sam"); + db->set_accounts_to_store_metadata(accs_v); + + signed_transaction tx; + ACTOR(alice); + + BOOST_TEST_MESSAGE("--- Test success under normal conditions"); + generate_blocks(10); + const auto json = "{\"test\":1}"; + auto now = db->head_block_time(); + account_metadata_operation op; + op.account = "alice"; + op.json_metadata = json; + push_tx_with_ops(tx, alice_private_key, op); + generate_blocks(10); + + auto alice_acc = db->get_account("alice"); + auto meta = db->find("alice"); + BOOST_REQUIRE(meta == nullptr); + BOOST_REQUIRE(alice_acc.last_account_update == now); + + BOOST_TEST_MESSAGE("----- Test API"); + account_api_object alice_api(alice_acc, *db); + BOOST_REQUIRE(alice_api.json_metadata == ""); + + ACTOR(bob); // create_account with json_metadata = "" + + BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create_with_delegation"); + generate_blocks(1); + fund("bob", ASSET_GOLOS(1000)); + private_key_type priv_key = generate_private_key("temp_key"); + account_create_with_delegation_operation cr; + cr.fee = ASSET_GOLOS(1000); + cr.delegation = ASSET_GESTS(0); + cr.creator = "bob"; + cr.new_account_name = "sam"; + cr.owner = authority(1, priv_key.get_public_key(), 1); + cr.active = authority(1, priv_key.get_public_key(), 1); + cr.memo_key = priv_key.get_public_key(); + push_tx_with_ops(tx, bob_private_key, cr); + + meta = db->find("sam"); + BOOST_REQUIRE(meta != nullptr); validate_database(); } FC_LOG_AND_RETHROW() From d12da12918bbc596f348bf16ba06fc32bf9452d7 Mon Sep 17 00:00:00 2001 From: Rostislav Velichko Date: Thu, 5 Jul 2018 13:27:51 +0300 Subject: [PATCH 032/250] Fix erase functions and add short list operations test. #668 --- plugins/account_history/plugin.cpp | 6 ++- plugins/operation_history/plugin.cpp | 7 +-- share/golosd/docker/Dockerfile-test | 6 ++- tests/CMakeLists.txt | 4 ++ .../short_list_operation_postfix_test.cpp | 45 +++++++++++++++++++ 5 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 tests/plugin_tests/short_list_operation_postfix_test.cpp diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index b105d2fe5a..05fba3494c 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -78,7 +78,7 @@ if( options.count(name) ) { \ void erase_old_blocks() { uint32_t head_block = database.head_block_num(); if (history_blocks <= head_block) { - uint32_t need_block = head_block - history_blocks + 1; + uint32_t need_block = head_block - history_blocks; const auto& idx = database.get_index().indices().get(); auto it = idx.begin(); while (it != idx.end() && it->block <= need_block) { @@ -106,7 +106,6 @@ if( options.count(name) ) { \ note.op.visit(operation_visitor(database, note, item)); } } - erase_old_blocks(); } std::map get_account_history( @@ -397,6 +396,9 @@ if( options.count(name) ) { \ if (options.count("history-blocks")) { uint32_t history_blocks = options.at("history-blocks").as(); pimpl->history_blocks = history_blocks; + pimpl->database.applied_block.connect([&](const signed_block& block){ + pimpl->erase_old_blocks(); + }); } else { pimpl->history_blocks = UINT32_MAX; } diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 319d2702d1..1839c9be22 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -102,7 +102,7 @@ namespace golos { namespace plugins { namespace operation_history { void erase_old_blocks() { uint32_t head_block = database.head_block_num(); if (history_blocks <= head_block) { - uint32_t need_block = head_block - history_blocks + 1; + uint32_t need_block = head_block - history_blocks; const auto& idx = database.get_index().indices().get(); auto it = idx.begin(); while (it != idx.end() && it->block <= need_block) { @@ -117,7 +117,6 @@ namespace golos { namespace plugins { namespace operation_history { void on_operation(golos::chain::operation_notification& note) { if (filter_content) { note.op.visit(operation_visitor_filter(database, note, ops_list, blacklist, start_block)); - erase_old_blocks(); } else { note.op.visit(operation_visitor(database, note, start_block)); } @@ -258,9 +257,11 @@ namespace golos { namespace plugins { namespace operation_history { ilog("operation_history: start_block ${s}", ("s", pimpl->start_block)); if (options.count("history-blocks")) { - pimpl->filter_content = true; uint32_t history_blocks = options.at("history-blocks").as(); pimpl->history_blocks = history_blocks; + pimpl->database.applied_block.connect([&](const signed_block& block){ + pimpl->erase_old_blocks(); + }); } else { pimpl->history_blocks = UINT32_MAX; } diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 78de08a0ae..fba28a7376 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,12 +44,16 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test black_options_test white_options_test operation_history_blocks_test account_history_blocks_test && \ + make -j$(nproc) chain_test plugin_test \ + black_options_test white_options_test short_list_operation_postfix_test \ + operation_history_blocks_test \ + account_history_blocks_test && \ ./tests/chain_test --log_level=message --report_level=detailed && \ ./tests/plugin_test --log_level=message --report_level=detailed && \ ./tests/white_options_test --log_level=message --report_level=detailed && \ ./tests/black_options_test --log_level=message --report_level=detailed && \ ./tests/operation_history_blocks_test --log_level=message --report_level=detailed && \ + ./tests/short_list_operation_postfix_test --log_level=message --report_level=detailed && \ ./tests/account_history_blocks_test --log_level=message --report_level=detailed # isn't used now, but can be used later ... diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6971c121d3..bf3ac0a98d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -71,6 +71,10 @@ add_exec_test(NAME "operation_history_blocks" FILES "plugin_tests/main.cpp" "plugin_tests/operation_history_blocks_test.cpp") +add_exec_test(NAME "short_list_operation_postfix" FILES + "plugin_tests/main.cpp" + "plugin_tests/short_list_operation_postfix_test.cpp") + add_exec_test(NAME "account_history_blocks" FILES "plugin_tests/main.cpp" "plugin_tests/account_history_blocks_test.cpp") diff --git a/tests/plugin_tests/short_list_operation_postfix_test.cpp b/tests/plugin_tests/short_list_operation_postfix_test.cpp new file mode 100644 index 0000000000..aedf1f478d --- /dev/null +++ b/tests/plugin_tests/short_list_operation_postfix_test.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" +#include "options_fixture.hpp" + + +using namespace golos::test; + + +struct short_list_options_postfix { + typedef std::vector opt_type; + std::string key = "history-whitelist-ops"; + std::string opt = + "account_create_operation," \ + "delete_comment," \ + "comment"; +}; + + +static const int SHORT_LIST_LEN = 3; + + +BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { + auto tops = test_options(); + init_plugin(tops); + + size_t _chacked_ops_count = 0; + for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { + auto iter = _db_init._added_ops.find(it->first); + bool is_found = (iter != _db_init._added_ops.end()); + if (is_found) { + BOOST_TEST_MESSAGE("Found operation \"" + it->second + "\" by \"" + it->first + "\""); + BOOST_CHECK_EQUAL(iter->second, it->second); + if (iter->second == it->second) { + ++_chacked_ops_count; + } + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, SHORT_LIST_LEN); +} From e138059cd31b9d5ef8e91bdef472364ed0f0bb3d Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 5 Jul 2018 20:54:29 +0700 Subject: [PATCH 033/250] Minimize load on travis. --- .travis.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aace6349b6..cc1009773e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,12 +26,16 @@ script: elif [ -n "$TRAVIS_TAG" ]; then export DOCKERNAME="$TRAVIS_TAG""$DOCKERNAME"; export EXPORTNAME="$DOCKERNAME"; - else + elif [ "$DOCKERNAME" == "-testnet" ] || [ "$DOCKERNAME" == "-test" ]; then export DOCKERNAME=develop"$DOCKERNAME"; + else + export DOCKERNAME=""; fi - echo "$DOCKERFILE" - echo "$DOCKERNAME" - - docker build -t goloschain/golos:"$DOCKERNAME" -f "$DOCKERFILE" . + - if [ -n "$DOCKERNAME" ]; then + docker build -t goloschain/golos:"$DOCKERNAME" -f "$DOCKERFILE" .; + fi after_success: - echo "$EXPORTNAME" From 901502240fa7815799f23f168d97b28e2a25bda4 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Thu, 5 Jul 2018 19:11:34 +0300 Subject: [PATCH 034/250] Refactored api::discussion helper. Replaced content index to social_network plugin. #796 --- libraries/api/CMakeLists.txt | 1 - libraries/api/comment_api_object.cpp | 59 ------ libraries/api/discussion_helper.cpp | 81 ++++++++- .../include/golos/api/comment_api_object.hpp | 41 ++++- .../api/include/golos/api/discussion.hpp | 5 +- .../include/golos/api/discussion_helper.hpp | 18 ++ libraries/chain/database.cpp | 18 +- .../include/golos/chain/comment_object.hpp | 48 ++--- .../chain/include/golos/chain/database.hpp | 4 +- .../golos/chain/steem_object_types.hpp | 4 +- libraries/chain/steem_evaluator.cpp | 116 ++++++------ .../include/golos/plugins/follow/plugin.hpp | 1 + plugins/follow/plugin.cpp | 8 +- .../plugins/social_network/social_network.hpp | 57 +++++- plugins/social_network/social_network.cpp | 172 +++++++++++++++++- 15 files changed, 465 insertions(+), 168 deletions(-) delete mode 100644 libraries/api/comment_api_object.cpp diff --git a/libraries/api/CMakeLists.txt b/libraries/api/CMakeLists.txt index 8c38c3a064..b7efed09ef 100644 --- a/libraries/api/CMakeLists.txt +++ b/libraries/api/CMakeLists.txt @@ -14,7 +14,6 @@ list(APPEND CURRENT_TARGET_HEADERS list(APPEND CURRENT_TARGET_SOURCES account_api_object.cpp discussion_helper.cpp - comment_api_object.cpp chain_api_properties.cpp witness_api_object.cpp ) diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp deleted file mode 100644 index 68fdb27ee1..0000000000 --- a/libraries/api/comment_api_object.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -namespace golos { namespace api { - - using namespace golos::chain; - - comment_api_object::comment_api_object(const golos::chain::comment_object &o, const golos::chain::database &db) - : id(o.id), - parent_author(o.parent_author), - parent_permlink(to_string(o.parent_permlink)), - author(o.author), - permlink(to_string(o.permlink)), - last_update(o.last_update), - created(o.created), - active(o.active), - last_payout(o.last_payout), - depth(o.depth), - children(o.children), - children_rshares2(o.children_rshares2), - net_rshares(o.net_rshares), - abs_rshares(o.abs_rshares), - vote_rshares(o.vote_rshares), - children_abs_rshares(o.children_abs_rshares), - cashout_time(o.cashout_time), - max_cashout_time(o.max_cashout_time), - total_vote_weight(o.total_vote_weight), - reward_weight(o.reward_weight), - total_payout_value(o.total_payout_value), - curator_payout_value(o.curator_payout_value), - author_rewards(o.author_rewards), - net_votes(o.net_votes), - mode(o.mode), - root_comment(o.root_comment), - max_accepted_payout(o.max_accepted_payout), - percent_steem_dollars(o.percent_steem_dollars), - allow_replies(o.allow_replies), - allow_votes(o.allow_votes), - allow_curation_rewards(o.allow_curation_rewards) { - - for (auto& route : o.beneficiaries) { - beneficiaries.push_back(route); - } -#ifndef IS_LOW_MEM - auto& content = db.get_comment_content(o.id); - - title = to_string(content.title); - body = to_string(content.body); - json_metadata = to_string(content.json_metadata); -#endif - if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { - category = to_string(o.parent_permlink); - } else { - category = to_string(db.get(o.root_comment).parent_permlink); - } - } - - comment_api_object::comment_api_object() = default; - -} } // golos::api \ No newline at end of file diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 6e71939570..fc7caf48f0 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -1,6 +1,6 @@ #include +#include #include -// #include #include #include #include @@ -85,14 +85,86 @@ namespace golos { namespace api { return database_; } + comment_api_object create_comment_api_object(const comment_object & o) const; + discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; + get_comment_content_res get_comment_content(const golos::chain::database & db, const comment_object & o); + private: golos::chain::database& database_; std::function&)> fill_reputation_; std::function fill_promoted_; + std::function get_comment_content_callback; }; +// create_comment_api_object + comment_api_object discussion_helper::create_comment_api_object(const comment_object & o) const { + return pimpl->create_comment_api_object(o); + } + + comment_api_object discussion_helper::impl::create_comment_api_object(const comment_object & o) const { + comment_api_object result; + auto & db = database_; + + result.id = o.id; + result.parent_author = o.parent_author; + result.parent_permlink = to_string(o.parent_permlink); + result.author = o.author; + result.permlink = to_string(o.permlink); + result.last_update = o.last_update; + result.created = o.created; + result.active = o.active; + result.last_payout = o.last_payout; + result.depth = o.depth; + result.children = o.children; + result.children_rshares2 = o.children_rshares2; + result.net_rshares = o.net_rshares; + result.abs_rshares = o.abs_rshares; + result.vote_rshares = o.vote_rshares; + result.children_abs_rshares = o.children_abs_rshares; + result.cashout_time = o.cashout_time; + result.max_cashout_time = o.max_cashout_time; + result.total_vote_weight = o.total_vote_weight; + result.reward_weight = o.reward_weight; + result.total_payout_value = o.total_payout_value; + result.curator_payout_value = o.curator_payout_value; + result.author_rewards = o.author_rewards; + result.net_votes = o.net_votes; + result.mode = o.mode; + result.root_comment = o.root_comment; + result.max_accepted_payout = o.max_accepted_payout; + result.percent_steem_dollars = o.percent_steem_dollars; + result.allow_replies = o.allow_replies; + result.allow_votes = o.allow_votes; + result.allow_curation_rewards = o.allow_curation_rewards; + + for (auto& route : o.beneficiaries) { + result.beneficiaries.push_back(route); + } + + if ( get_comment_content_callback ) { + auto content = get_comment_content_callback(database(), o); + + result.title = content.title; + result.body = content.body; + result.json_metadata = content.json_metadata; + } + + if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { + result.category = to_string(o.parent_permlink); + } else { + result.category = to_string(db.get(o.root_comment).parent_permlink); + } + + return result; + } + + +// get_comment_content + get_comment_content_res discussion_helper::impl::get_comment_content(const golos::chain::database & db, const comment_object & o) { + return get_comment_content_callback(db, o); + } // get_discussion discussion discussion_helper::impl::get_discussion(const comment_object& c, uint32_t vote_limit) const { discussion d = create_discussion(c); @@ -191,7 +263,9 @@ namespace golos { namespace api { // // set_url void discussion_helper::impl::set_url(discussion& d) const { - const comment_api_object root(database().get(d.root_comment), database()); + comment_object cm = database().get(d.root_comment); + + comment_api_object root = create_comment_api_object( cm ); d.root_title = root.title; d.url = "/" + root.category + "/@" + root.author + "/" + root.permlink; @@ -213,7 +287,8 @@ namespace golos { namespace api { } discussion discussion_helper::impl::create_discussion(const comment_object& o) const { - return discussion(o, database_); + auto x = create_comment_api_object(o); + return discussion(x); } discussion discussion_helper::create_discussion(const std::string& author) const { diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index bafe4e68cb..20124b4d59 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -10,8 +10,45 @@ namespace golos { namespace api { using namespace golos::chain; struct comment_api_object { - comment_api_object(const comment_object &o, const database &db); - comment_api_object(); + comment_api_object() = default; + comment_api_object(const comment_api_object& o ) { + id = o.id; + parent_author = o.parent_author; + parent_permlink = o.parent_permlink; + author = o.author; + permlink = o.permlink; + last_update = o.last_update; + created = o.created; + active = o.active; + last_payout = o.last_payout; + depth = o.depth; + children = o.children; + children_rshares2 = o.children_rshares2; + net_rshares = o.net_rshares; + abs_rshares = o.abs_rshares; + vote_rshares = o.vote_rshares; + children_abs_rshares = o.children_abs_rshares; + cashout_time = o.cashout_time; + max_cashout_time = o.max_cashout_time; + total_vote_weight = o.total_vote_weight; + reward_weight = o.reward_weight; + total_payout_value = o.total_payout_value; + curator_payout_value = o.curator_payout_value; + author_rewards = o.author_rewards; + net_votes = o.net_votes; + mode = o.mode; + root_comment = o.root_comment; + max_accepted_payout = o.max_accepted_payout; + percent_steem_dollars = o.percent_steem_dollars; + allow_replies = o.allow_replies; + allow_votes = o.allow_votes; + allow_curation_rewards = o.allow_curation_rewards; + beneficiaries = o.beneficiaries; + title = o.title; + body = o.body; + json_metadata = o.json_metadata; + category = o.category; + } comment_object::id_type id; diff --git a/libraries/api/include/golos/api/discussion.hpp b/libraries/api/include/golos/api/discussion.hpp index ae43ded569..691d92016a 100644 --- a/libraries/api/include/golos/api/discussion.hpp +++ b/libraries/api/include/golos/api/discussion.hpp @@ -7,8 +7,9 @@ namespace golos { namespace api { struct discussion : public comment_api_object { - discussion(const comment_object& o, const golos::chain::database &db) - : comment_api_object(o, db) { + discussion(const comment_api_object& o) + : comment_api_object(o) { + } discussion() { diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index de42a47e17..e4b3d1b096 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace golos { namespace api { struct comment_metadata { @@ -11,6 +12,12 @@ namespace golos { namespace api { comment_metadata get_metadata(const comment_api_object &c); + struct get_comment_content_res { + std::string title; + std::string body; + std::string json_metadata; + }; + class discussion_helper { public: discussion_helper() = delete; @@ -18,6 +25,10 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted); + discussion_helper( + golos::chain::database& db, + std::function get_comment_content_callback + ); ~discussion_helper(); @@ -36,6 +47,9 @@ namespace golos { namespace api { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; + comment_api_object create_comment_api_object(const comment_object & o) const; + + private: struct impl; std::unique_ptr pimpl; @@ -44,3 +58,7 @@ namespace golos { namespace api { } } // golos::api FC_REFLECT((golos::api::comment_metadata), (tags)(language)) + +FC_REFLECT((golos::api::get_comment_content_res), + (title)(body)(json_metadata) + ) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index a3c72171a4..04a520a9d2 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -615,15 +615,15 @@ namespace golos { namespace chain { } - const comment_content_object &database::get_comment_content(const comment_id_type &comment) const { - try { - return get(comment); - } FC_CAPTURE_AND_RETHROW((comment)) - } + // const comment_content_object &database::get_comment_content(const comment_id_type &comment) const { + // try { + // return get(comment); + // } FC_CAPTURE_AND_RETHROW((comment)) + // } - const comment_content_object *database::find_comment_content(const comment_id_type &comment) const { - return find(comment); - } + // const comment_content_object *database::find_comment_content(const comment_id_type &comment) const { + // return find(comment); + // } const escrow_object &database::get_escrow(const account_name_type &name, uint32_t escrow_id) const { try { @@ -2915,7 +2915,7 @@ namespace golos { namespace chain { add_core_index(*this); add_core_index(*this); add_core_index(*this); - add_core_index(*this); + // add_core_index(*this); add_core_index(*this); add_core_index(*this); add_core_index(*this); diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index c3171709a2..ed0dfc8e8d 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -40,25 +40,25 @@ namespace golos { archived }; - class comment_content_object - : public object { - public: - comment_content_object() = delete; + // class comment_content_object + // : public object { + // public: + // comment_content_object() = delete; - template - comment_content_object(Constructor &&c, allocator a) - :title(a), body(a), json_metadata(a) { - c(*this); - } + // template + // comment_content_object(Constructor &&c, allocator a) + // :title(a), body(a), json_metadata(a) { + // c(*this); + // } - id_type id; + // id_type id; - comment_id_type comment; + // comment_id_type comment; - shared_string title; - shared_string body; - shared_string json_metadata; - }; + // shared_string title; + // shared_string body; + // shared_string json_metadata; + // }; class comment_object : public object { @@ -263,15 +263,15 @@ namespace golos { comment_index; - struct by_comment; + // struct by_comment; - typedef multi_index_container< - comment_content_object, - indexed_by< - ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id > >, - ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment > > >, - allocator< comment_content_object > - > comment_content_index; + // typedef multi_index_container< + // comment_content_object, + // indexed_by< + // ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id > >, + // ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment > > >, + // allocator< comment_content_object > + // > comment_content_index; } } // golos::chain @@ -280,7 +280,7 @@ FC_REFLECT_ENUM(golos::chain::comment_mode, (not_set)(first_payout)(second_payou CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_object, golos::chain::comment_index) -CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_content_object, golos::chain::comment_content_index) +// CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_content_object, golos::chain::comment_content_index) CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_vote_object, golos::chain::comment_vote_index) diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index bee9b10fa9..a679fa1915 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -159,9 +159,9 @@ namespace golos { namespace chain { const comment_object *find_comment(const account_name_type &author, const string &permlink) const; - const comment_content_object &get_comment_content(const comment_id_type &comment) const; + // const comment_content_object &get_comment_content(const comment_id_type &comment) const; - const comment_content_object *find_comment_content(const comment_id_type &comment) const; + // const comment_content_object *find_comment_content(const comment_id_type &comment) const; const escrow_object &get_escrow(const account_name_type &name, uint32_t escrow_id) const; diff --git a/libraries/chain/include/golos/chain/steem_object_types.hpp b/libraries/chain/include/golos/chain/steem_object_types.hpp index 350625a480..0eab794b90 100644 --- a/libraries/chain/include/golos/chain/steem_object_types.hpp +++ b/libraries/chain/include/golos/chain/steem_object_types.hpp @@ -51,7 +51,7 @@ namespace golos { namespace chain { block_summary_object_type, witness_schedule_object_type, comment_object_type, - comment_content_object_type, + // comment_content_object_type, comment_vote_object_type, witness_vote_object_type, limit_order_object_type, @@ -216,7 +216,7 @@ FC_REFLECT_ENUM(golos::chain::object_type, (block_summary_object_type) (witness_schedule_object_type) (comment_object_type) - (comment_content_object_type) + // (comment_content_object_type) (comment_vote_object_type) (witness_vote_object_type) (limit_order_object_type) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 2016d98eda..7d181cbaed 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -371,20 +371,20 @@ namespace golos { namespace chain { p.children--; p.active = now; }); -#ifndef IS_LOW_MEM +// #ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -#endif +// #endif { parent = nullptr; } } } -#ifndef IS_LOW_MEM - auto& content = _db.get_comment_content(comment.id); - _db.remove(content); -#endif +// #ifndef IS_LOW_MEM + // auto& content = _db.get_comment_content(comment.id); + // _db.remove(content); +// #endif _db.remove(comment); } @@ -599,22 +599,22 @@ namespace golos { namespace chain { } }); - id = new_comment.id; -#ifndef IS_LOW_MEM - _db.create([&](comment_content_object& con) { - con.comment = id; - from_string(con.title, o.title); - if (o.body.size() < 1024*1024*128) { - from_string(con.body, o.body); - } - if (fc::is_utf8(o.json_metadata)) { - from_string(con.json_metadata, o.json_metadata); - } else { - wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", - ("a", o.author)("p", o.permlink)); - } - }); -#endif + // id = new_comment.id; +// #ifndef IS_LOW_MEM +// _db.create([&](comment_content_object& con) { +// con.comment = id; +// from_string(con.title, o.title); +// if (o.body.size() < 1024*1024*128) { +// from_string(con.body, o.body); +// } +// if (fc::is_utf8(o.json_metadata)) { +// from_string(con.json_metadata, o.json_metadata); +// } else { +// wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", +// ("a", o.author)("p", o.permlink)); +// } +// }); +// #endif /// this loop can be skiped for validate-only nodes as it is merely gathering stats for indicies auto now = _db.head_block_time(); while (parent) { @@ -622,11 +622,11 @@ namespace golos { namespace chain { p.children++; p.active = now; }); -#ifndef IS_LOW_MEM +// #ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -#endif +// #endif { parent = nullptr; } @@ -661,40 +661,40 @@ namespace golos { namespace chain { } }); -#ifndef IS_LOW_MEM - _db.modify(_db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { - if (o.title.size()) - from_string(con.title, o.title); - if (o.json_metadata.size()) { - if (fc::is_utf8(o.json_metadata)) - from_string(con.json_metadata, o.json_metadata ); - else - wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); - } - if (o.body.size()) { - try { - diff_match_patch dmp; - auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); - if (patch.size()) { - auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); - auto patched_body = wstring_to_utf8(result.first); - if(!fc::is_utf8(patched_body)) { - idump(("invalid utf8")(patched_body)); - from_string(con.body, fc::prune_invalid_utf8(patched_body)); - } - else { - from_string(con.body, patched_body); - } - } - else { // replace - from_string(con.body, o.body); - } - } catch ( ... ) { - from_string(con.body, o.body); - } - } - }); -#endif +// #ifndef IS_LOW_MEM +// _db.modify(_db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { +// if (o.title.size()) +// from_string(con.title, o.title); +// if (o.json_metadata.size()) { +// if (fc::is_utf8(o.json_metadata)) +// from_string(con.json_metadata, o.json_metadata ); +// else +// wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); +// } +// if (o.body.size()) { +// try { +// diff_match_patch dmp; +// auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); +// if (patch.size()) { +// auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); +// auto patched_body = wstring_to_utf8(result.first); +// if(!fc::is_utf8(patched_body)) { +// idump(("invalid utf8")(patched_body)); +// from_string(con.body, fc::prune_invalid_utf8(patched_body)); +// } +// else { +// from_string(con.body, patched_body); +// } +// } +// else { // replace +// from_string(con.body, o.body); +// } +// } catch ( ... ) { +// from_string(con.body, o.body); +// } +// } +// }); +// #endif } // end EDIT case diff --git a/plugins/follow/include/golos/plugins/follow/plugin.hpp b/plugins/follow/include/golos/plugins/follow/plugin.hpp index 44a0bbb813..736b536fdf 100644 --- a/plugins/follow/include/golos/plugins/follow/plugin.hpp +++ b/plugins/follow/include/golos/plugins/follow/plugin.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "follow_api_object.hpp" namespace golos { namespace plugins { namespace follow { diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index 4fccc3379d..d01a343e2f 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -286,6 +286,10 @@ namespace golos { struct plugin::impl final { public: impl() : database_(appbase::app().get_plugin().db()) { + helper = std::make_unique( + database_, + golos::social_network::plugins::get_comment_content_callback; + ); } ~impl() { @@ -378,6 +382,8 @@ namespace golos { std::shared_ptr> _custom_operation_interpreter; + + std::unique_ptr helper; }; plugin::plugin() { @@ -556,7 +562,7 @@ namespace golos { while (itr != feed_idx.end() && itr->account == account && result.size() < limit) { const auto &comment = db.get(itr->comment); comment_feed_entry entry; - entry.comment = comment_api_object(comment, db); + entry.comment = helper->create_comment_api_object(comment); entry.entry_id = itr->account_feed_id; if (itr->first_reblogged_by != account_name_type()) { //entry.reblog_by = itr->first_reblogged_by; diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 5e81c944c7..a0e68005ac 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -6,13 +6,15 @@ #include #include #include +#include + namespace golos { namespace plugins { namespace social_network { using plugins::json_rpc::msg_pack; using golos::api::discussion; using golos::api::account_vote; using golos::api::vote_state; - using golos::api::comment_api_object; + using golos::api::get_comment_content_res; using namespace golos::chain; DEFINE_API_ARGS(get_content, msg_pack, discussion) @@ -42,7 +44,7 @@ namespace golos { namespace plugins { namespace social_network { ~social_network(); void set_program_options( - boost::program_options::options_description&, + boost::program_options::options_description& cfg, boost::program_options::options_description& config_file_options ) override; @@ -57,4 +59,53 @@ namespace golos { namespace plugins { namespace social_network { struct impl; std::unique_ptr pimpl; }; -} } } // golos::plugins::social_network \ No newline at end of file + + get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) const; + + using comment_content_object_type = 4223; + + + class comment_content_object + : public object { + public: + comment_content_object() = delete; + + template + comment_content_object(Constructor &&c, allocator a) + :title(a), body(a), json_metadata(a) { + c(*this); + } + + id_type id; + + comment_id_type comment; + + shared_string title; + shared_string body; + shared_string json_metadata; + }; + + struct by_comment; + + typedef multi_index_container< + comment_content_object, + indexed_by< + ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id > >, + ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment > > >, + allocator< comment_content_object > + > comment_content_index; + +// Callback which is needed for correct work of discussion_helper + get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) { + if (!db.has_index()) { + return; + } + return db.get(comment); + } + +} } } // golos::plugins::social_network + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::social_network::comment_content_object, + golos::plugins::social_network::comment_content_index +) \ No newline at end of file diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 5b010cba9e..79762966b6 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -3,9 +3,11 @@ #include #include #include -#include // These visitors creates additional tables, we don't really need them in LOW_MEM mode #include +#include +#include +#include #define CHECK_ARG_SIZE(_S) \ FC_ASSERT( \ @@ -73,9 +75,29 @@ namespace golos { namespace plugins { namespace social_network { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const ; + void set_comment_title_depth(const uint32_t & value); + void set_comment_body_depth(const uint32_t & value); + void set_comment_json_metadata_depth(const uint32_t & value); + + // Removes comment_content data which is not needed anymore + void clear_comment_content_info(); + + // Looks for a comment_operation, fills the comment_content state objects. + void post_operation(const operation_notification &o); + private: golos::chain::database& database_; std::unique_ptr helper; + + // Depth of comment_content information storage history. + uint32_t comment_title_depth; + uint32_t comment_body_depth; + uint32_t comment_json_metadata_depth; + + // #TODO delete + // bool has_comment_title_depth; + // bool has_comment_body_depth; + // bool has_comment_json_metadata_depth; }; @@ -90,6 +112,120 @@ namespace golos { namespace plugins { namespace social_network { helper->select_active_votes(result, total_count, author, permlink, limit); } + void social_network::impl::set_comment_title_depth(const uint32_t & value) { + comment_title_depth = value; + } + void social_network::impl::set_comment_body_depth(const uint32_t & value) { + comment_body_depth = value; + } + void social_network::impl::set_comment_json_metadata_depth(const uint32_t & value) { + comment_json_metadata_depth = value; + } + + struct operation_visitor { + using result_type = void; + + template + void operator()(const T& o) const { + } + + void operator()(const delete_comment_operation& o) const { + auto & db = database(); + + const auto &comment = _db.get_comment(o.author, o.permlink); + auto& content = db.get_comment_content(comment.id); + db.remove(content); + } + + void operator()(const golos::protocol::comment_operation& o) const { + auto & db = database(); + + const auto& comment = db.get_comment(o.author, o.permlink); + + if (comment.created != db.head_block_time()) { + // Edit case + db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { + if (o.title.size()) { + from_string(con.title, o.title); + } + if (o.json_metadata.size()) { + if (fc::is_utf8(o.json_metadata)) { + from_string(con.json_metadata, o.json_metadata ); + } + else { + wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); + } + } + if (o.body.size()) { + try { + diff_match_patch dmp; + auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); + if (patch.size()) { + auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); + auto patched_body = wstring_to_utf8(result.first); + if(!fc::is_utf8(patched_body)) { + idump(("invalid utf8")(patched_body)); + from_string(con.body, fc::prune_invalid_utf8(patched_body)); + } + else { + from_string(con.body, patched_body); + } + } + else { // replace + from_string(con.body, o.body); + } + } catch ( ... ) { + from_string(con.body, o.body); + } + } + }); + + } + else { + // Creation case + const comment_object *parent = nullptr; + + if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { + parent = &db.get_comment(o.parent_author, o.parent_permlink); + } + + db.create([&](comment_content_object& con) { + con.comment = id; + from_string(con.title, o.title); + if (o.body.size() < 1024*1024*128) { + from_string(con.body, o.body); + } + if (fc::is_utf8(o.json_metadata)) { + from_string(con.json_metadata, o.json_metadata); + } else { + wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", + ("a", o.author)("p", o.permlink)); + } + }); + } + } + }; + + void social_network::impl::clear_comment_content_info() { + } + + void social_network::impl::post_operation(const operation_notification &o) { + operation_visitor ovisit; + auto x = o.op.visit(ovisit); + + auto& db = pimpl->database(); + + if (!x.valid) { + return; + } + // else work with comment_operation and upd content + + // std::cout << "\t\to.op.visit(ovisit) :\n\t\t" << "x.title = [" << x.title << "]\n\t\t" << + // "x.body = [" << x.body << "]\n\t\t" << + // "x.json_metadata = [" << x.json_metadata << "]" << std::endl; + } + + void social_network::plugin_startup() { wlog("social_network plugin: plugin_startup()"); } @@ -106,14 +242,46 @@ namespace golos { namespace plugins { namespace social_network { social_network::social_network() = default; void social_network::set_program_options( - boost::program_options::options_description&, + boost::program_options::options_description& cfg, boost::program_options::options_description& config_file_options ) { + cfg.add_options() + ( // Depth of comment_content information storage history. + "comment-title-depth", boost::program_options::value(), + "max count of storing records of comment.title" + ) ( + "comment-body-depth", boost::program_options::value(), + "max count of storing records of comment.body" + ) ( + "comment-json-metadata-depth", boost::program_options::value(), + "max count of storing records of comment.json_metadata" + ); } void social_network::plugin_initialize(const boost::program_options::variables_map& options) { pimpl = std::make_unique(); JSON_RPC_REGISTER_API(name()); + + auto& db = pimpl->database(); + + // add_plugin_index(db); + + db.post_apply_operation.connect([&](const operation_notification &o) { + pimpl->post_operation(o); + }); + + + if (options.count("comment-title-depth")) { + pimpl->set_comment_title_depth( options.at("comment-title-depth").as() ); + } + + if (options.count("comment-body-depth")) { + pimpl->set_comment_body_depth( options.at("comment-body-depth").as() ); + } + + if (options.count("comment-json-metadata-depth")) { + pimpl->set_comment_json_metadata_depth( options.at("comment-json-metadata-depth").as() ); + } } social_network::~social_network() = default; From 12c02a74643a00f23202074a72148c9bd9262dc6 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 6 Jul 2018 11:22:27 +0700 Subject: [PATCH 035/250] Fix filling of discussion fields in get_discussions_XXX. #816 --- .../golos/plugins/tags/tag_visitor.hpp | 4 +-- plugins/tags/plugin.cpp | 36 ++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 0a889f9fcc..492aef4520 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -46,9 +46,9 @@ namespace golos { namespace plugins { namespace tags { return sign * order + double(created.sec_since_epoch()) / double(T); } - inline double calculate_hot(const share_type& score, const time_point_sec& created) const; + double calculate_hot(const share_type& score, const time_point_sec& created) const; - inline double calculate_trending(const share_type& score, const time_point_sec& created) const; + double calculate_trending(const share_type& score, const time_point_sec& created) const; /** finds tags that have been added or removed or updated */ void create_update_tags(const account_name_type& author, const std::string& permlink) const; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 15bdff3f24..6adafd5ffc 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -79,8 +79,8 @@ namespace golos { namespace plugins { namespace tags { bool filter_query(discussion_query& query) const; - template - std::vector select_unordered_discussions(discussion_query& query) const; + template + std::vector select_unordered_discussions(discussion_query&, Fill&&) const; template void select_discussions( @@ -282,7 +282,13 @@ namespace golos { namespace plugins { namespace tags { if (!comment) { return false; } + query.start_comment = create_discussion(*comment, query); + auto& d = query.start_comment; + operation_visitor v(database_); + + d.hot = v.calculate_hot(d.net_rshares, d.created); + d.trending = v.calculate_trending(d.net_rshares, d.created); } return true; } @@ -314,8 +320,12 @@ namespace golos { namespace plugins { namespace tags { template< typename DatabaseIndex, - typename DiscussionIndex> - std::vector tags_plugin::impl::select_unordered_discussions(discussion_query& query) const { + typename DiscussionIndex, + typename Fill> + std::vector tags_plugin::impl::select_unordered_discussions( + discussion_query& query, + Fill&& fill + ) const { std::vector result; if (!filter_start_comment(query) || !filter_query(query)) { @@ -367,7 +377,8 @@ namespace golos { namespace plugins { namespace tags { } fill_discussion(d, query); - result.push_back(d); + fill(d, *itr); + result.push_back(std::move(d)); } } return result; @@ -495,7 +506,6 @@ namespace golos { namespace plugins { namespace tags { } query.reset_start_comment(); itr = idx.iterator_to(*citr); - ++itr; } unordered.reserve(query.limit); @@ -550,7 +560,11 @@ namespace golos { namespace plugins { namespace tags { FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { - return pimpl->select_unordered_discussions(query); + return pimpl->select_unordered_discussions( + query, + [&](discussion& d, const follow::blog_object& b) { + d.first_reblogged_on = b.reblogged_on; + }); }); #endif return result; @@ -570,7 +584,13 @@ namespace golos { namespace plugins { namespace tags { FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { - return pimpl->select_unordered_discussions(query); + return pimpl->select_unordered_discussions( + query, + [&](discussion& d, const follow::feed_object& f) { + d.reblogged_by.assign(f.reblogged_by.begin(), f.reblogged_by.end()); + d.first_reblogged_by = f.first_reblogged_by; + d.first_reblogged_on = f.first_reblogged_on; + }); }); #endif return result; From 82aee8af5fcdcd832090c49588850913aa476ff3 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Fri, 6 Jul 2018 10:34:52 +0300 Subject: [PATCH 036/250] Made space_id for social_plugin. Added needed changed for comment_content_object. #796 --- .../chain/include/golos/chain/steem_object_types.hpp | 2 +- plugins/follow/CMakeLists.txt | 1 + .../golos/plugins/social_network/social_network.hpp | 11 +++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/chain/include/golos/chain/steem_object_types.hpp b/libraries/chain/include/golos/chain/steem_object_types.hpp index 0eab794b90..faa9276a98 100644 --- a/libraries/chain/include/golos/chain/steem_object_types.hpp +++ b/libraries/chain/include/golos/chain/steem_object_types.hpp @@ -115,7 +115,7 @@ namespace golos { namespace chain { typedef object_id block_summary_id_type; typedef object_id witness_schedule_id_type; typedef object_id comment_id_type; - typedef object_id comment_content_id_type; + // typedef object_id comment_content_id_type; typedef object_id comment_vote_id_type; typedef object_id witness_vote_id_type; typedef object_id limit_order_id_type; diff --git a/plugins/follow/CMakeLists.txt b/plugins/follow/CMakeLists.txt index 24aec52fce..8ca06fbfd3 100644 --- a/plugins/follow/CMakeLists.txt +++ b/plugins/follow/CMakeLists.txt @@ -37,6 +37,7 @@ target_link_libraries( golos::chain_plugin golos::protocol golos::api + golos::social_network appbase fc ) diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index a0e68005ac..12f67938ce 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -60,10 +60,17 @@ namespace golos { namespace plugins { namespace social_network { std::unique_ptr pimpl; }; - get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) const; + get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o); - using comment_content_object_type = 4223; +#ifndef SOCIAL_NETWORK_SPACE_ID +#define SOCIAL_NETWORK_SPACE_ID 23 +#endif + enum social_network_types { + comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 + }; + + using comment_content_id_type = object_id; class comment_content_object : public object { From 79ffdfb8623c5e111cdd256767677ce0d951b662 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Fri, 6 Jul 2018 12:48:47 +0300 Subject: [PATCH 037/250] Remove LOW_MEM from tags plugin #798 --- plugins/social_network/social_network.cpp | 1 - plugins/tags/plugin.cpp | 52 ----------------------- 2 files changed, 53 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 5b010cba9e..f939b40e51 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -4,7 +4,6 @@ #include #include #include -// These visitors creates additional tables, we don't really need them in LOW_MEM mode #include #define CHECK_ARG_SIZE(_S) \ diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 15bdff3f24..cdfcb8927e 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -7,7 +7,6 @@ #include #include #include -// These visitors creates additional tables, we don't really need them in LOW_MEM mode #include #include @@ -44,7 +43,6 @@ namespace golos { namespace plugins { namespace tags { ~impl() {} void on_operation(const operation_notification& note) { -#ifndef IS_LOW_MEM try { /// plugins shouldn't ever throw note.op.visit(tags::operation_visitor(database())); @@ -53,7 +51,6 @@ namespace golos { namespace plugins { namespace tags { } catch (...) { elog("unhandled exception"); } -#endif } golos::chain::database& database() { @@ -208,8 +205,6 @@ namespace golos { namespace plugins { namespace tags { void tags_plugin::plugin_initialize(const boost::program_options::variables_map& options) { pimpl.reset(new impl()); -// Disable index creation for tag visitor -#ifndef IS_LOW_MEM auto& db = pimpl->database(); db.post_apply_operation.connect([&](const operation_notification& note) { pimpl->on_operation(note); @@ -218,7 +213,6 @@ namespace golos { namespace plugins { namespace tags { add_plugin_index(db); add_plugin_index(db); add_plugin_index(db); -#endif JSON_RPC_REGISTER_API (name()); } @@ -537,49 +531,39 @@ namespace golos { namespace plugins { namespace tags { DEFINE_API(tags_plugin, get_discussions_by_blog) { CHECK_ARG_SIZE(1) - std::vector result; auto query = args.args->at(0).as(); query.prepare(); query.validate(); FC_ASSERT(query.select_authors.size(), "Must get blogs for specific authors"); - -#ifndef IS_LOW_MEM auto& db = pimpl->database(); FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { return pimpl->select_unordered_discussions(query); }); -#endif - return result; } DEFINE_API(tags_plugin, get_discussions_by_feed) { CHECK_ARG_SIZE(1) - std::vector result; auto query = args.args->at(0).as(); query.prepare(); query.validate(); FC_ASSERT(query.select_authors.size(), "Must get feeds for specific authors"); -#ifndef IS_LOW_MEM auto& db = pimpl->database(); FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { return pimpl->select_unordered_discussions(query); }); -#endif - return result; } DEFINE_API(tags_plugin, get_discussions_by_comments) { CHECK_ARG_SIZE(1) std::vector result; -#ifndef IS_LOW_MEM auto query = args.args->at(0).as(); query.prepare(); query.validate(); @@ -620,8 +604,6 @@ namespace golos { namespace plugins { namespace tags { } return result; }); -#endif - return result; } DEFINE_API(tags_plugin, get_discussions_by_trending) { @@ -629,15 +611,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return d.net_rshares > 0; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_promoted) { @@ -645,15 +624,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return !!d.promoted && d.promoted->amount > 0; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_created) { @@ -661,15 +637,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return true; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_active) { @@ -677,15 +650,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return true; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_cashout) { @@ -693,15 +663,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return d.net_rshares > 0; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_payout) { @@ -709,15 +676,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return d.net_rshares > 0; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_votes) { @@ -725,15 +689,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return true; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_children) { @@ -741,15 +702,12 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return true; } ); -#endif - return std::vector(); } DEFINE_API(tags_plugin, get_discussions_by_hot) { @@ -757,22 +715,18 @@ namespace golos { namespace plugins { namespace tags { auto query = args.args->at(0).as(); query.prepare(); query.validate(); -#ifndef IS_LOW_MEM return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { return d.net_rshares > 0; } ); -#endif - return std::vector(); } std::vector tags_plugin::impl::get_trending_tags(const std::string& after, uint32_t limit) const { limit = std::min(limit, uint32_t(1000)); std::vector result; -#ifndef IS_LOW_MEM result.reserve(limit); const auto& nidx = database().get_index().indices().get(); @@ -800,7 +754,6 @@ namespace golos { namespace plugins { namespace tags { result.emplace_back(push_object); } -#endif return result; } @@ -818,7 +771,6 @@ namespace golos { namespace plugins { namespace tags { const std::string& author ) const { std::vector> result; -#ifndef IS_LOW_MEM auto& db = database(); const auto* acnt = db.find_account(author); if (acnt == nullptr) { @@ -835,7 +787,6 @@ namespace golos { namespace plugins { namespace tags { } } } -#endif return result; } @@ -851,7 +802,6 @@ namespace golos { namespace plugins { namespace tags { std::vector result; CHECK_ARG_MIN_SIZE(4, 5) -#ifndef IS_LOW_MEM auto author = args.args->at(0).as(); auto start_permlink = args.args->at(1).as(); auto before_date = args.args->at(2).as(); @@ -892,8 +842,6 @@ namespace golos { namespace plugins { namespace tags { return result; } FC_CAPTURE_AND_RETHROW((author)(start_permlink)(before_date)(limit)) }); -#endif - return result; } // Needed for correct work of golos::api::discussion_helper::set_pending_payout and etc api methods From 0a09b77042fc5bf4fe4cd35eef355b7183f9becd Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 6 Jul 2018 19:04:13 +0700 Subject: [PATCH 038/250] Fix default settings fro store account metadata. #794 --- plugins/chain/plugin.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index b25ea08ecf..2a9f6a92d3 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -324,18 +324,18 @@ namespace chain { } } + my->store_account_metadata = golos::chain::database::store_metadata_for_all; if (options.count("store-account-metadata")) { - if (options.at("store-account-metadata").as()) { - my->store_account_metadata = golos::chain::database::store_metadata_for_all; - } else { + if (!options.at("store-account-metadata").as()) { my->store_account_metadata = golos::chain::database::store_metadata_for_nobody; - wlog("Account metadata will be not stored for any item of store-account-metadata-list because store-account-metadata is false"); + wlog( + "Account metadata will be not stored for any item of store-account-metadata-list" + " because store-account-metadata is false"); } - } else { - my->store_account_metadata = golos::chain::database::store_metadata_for_listed; } if (options.count("store-account-metadata-list")) { + my->store_account_metadata = golos::chain::database::store_metadata_for_listed; std::string str_accs = options["store-account-metadata-list"].as(); my->accounts_to_store_metadata = fc::json::from_string(str_accs).as>(); } From c33b7f807297e6db1e89351b5865517d6e4c2229 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 6 Jul 2018 19:45:09 +0700 Subject: [PATCH 039/250] Fix default settings for store account metadata. #794 --- plugins/chain/plugin.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 2a9f6a92d3..8b15f1f6d7 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -325,6 +325,13 @@ namespace chain { } my->store_account_metadata = golos::chain::database::store_metadata_for_all; + + if (options.count("store-account-metadata-list")) { + my->store_account_metadata = golos::chain::database::store_metadata_for_listed; + std::string str_accs = options["store-account-metadata-list"].as(); + my->accounts_to_store_metadata = fc::json::from_string(str_accs).as>(); + } + if (options.count("store-account-metadata")) { if (!options.at("store-account-metadata").as()) { my->store_account_metadata = golos::chain::database::store_metadata_for_nobody; @@ -333,12 +340,6 @@ namespace chain { " because store-account-metadata is false"); } } - - if (options.count("store-account-metadata-list")) { - my->store_account_metadata = golos::chain::database::store_metadata_for_listed; - std::string str_accs = options["store-account-metadata-list"].as(); - my->accounts_to_store_metadata = fc::json::from_string(str_accs).as>(); - } } void plugin::plugin_startup() { From 8a7eabe7261d184f21a2eae37e1b95e0b0ae17a4 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sat, 7 Jul 2018 19:07:23 +0300 Subject: [PATCH 040/250] Changed discussion initialization way in social_network and tags. #796 --- .../golos/chain/steem_object_types.hpp | 2 +- .../plugins/social_network/social_network.hpp | 20 ++++++++++++++----- plugins/tags/plugin.cpp | 10 ++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/golos/chain/steem_object_types.hpp b/libraries/chain/include/golos/chain/steem_object_types.hpp index faa9276a98..734f09312c 100644 --- a/libraries/chain/include/golos/chain/steem_object_types.hpp +++ b/libraries/chain/include/golos/chain/steem_object_types.hpp @@ -85,7 +85,7 @@ namespace golos { namespace chain { class proposal_object; class required_approval_object; class comment_object; - class comment_content_object; + // class comment_content_object; class comment_vote_object; class witness_vote_object; class limit_order_object; diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 12f67938ce..cc7b68ca9d 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -70,7 +70,6 @@ namespace golos { namespace plugins { namespace social_network { comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 }; - using comment_content_id_type = object_id; class comment_content_object : public object { @@ -92,22 +91,33 @@ namespace golos { namespace plugins { namespace social_network { shared_string json_metadata; }; + + using comment_content_id_type = object_id; + struct by_comment; typedef multi_index_container< comment_content_object, indexed_by< - ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id > >, - ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment > > >, + ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id>>, + ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment>>>, allocator< comment_content_object > > comment_content_index; // Callback which is needed for correct work of discussion_helper get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) { if (!db.has_index()) { - return; + return get_comment_content_res(); } - return db.get(comment); + auto & content = db.get(o); + + get_comment_content_res result; + + result.title = std::string(content.title.begin(), content.title.end()); + result.body = std::string(content.body.begin(), content.body.end()); + result.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); + + return result; } } } } // golos::plugins::social_network diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 15bdff3f24..f353895e89 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -115,6 +115,8 @@ namespace golos { namespace plugins { namespace tags { discussion create_discussion(const comment_object& o, const discussion_query& query) const; void fill_discussion(discussion& d, const discussion_query& query) const; + comment_api_object create_comment_api_object(const comment_object & o) const; + get_languages_result get_languages(); private: @@ -178,6 +180,10 @@ namespace golos { namespace plugins { namespace tags { return d; } + comment_api_object tags_plugin::impl::create_comment_api_object(const comment_object & o) const { + return helper->create_comment_api_object( o ); + } + DEFINE_API(tags_plugin, get_languages) { return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_languages(); @@ -610,11 +616,11 @@ namespace golos { namespace plugins { namespace tags { for (; itr != idx.end() && itr->author == *query.start_author && result.size() < query.limit; ++itr) { if (itr->parent_author.size() > 0) { - discussion p(db.get(itr->root_comment), db); + discussion p( pimpl->create_comment_api_object(db.get(itr->root_comment) ) ); if (!query.is_good_tags(p) || !query.is_good_author(p.author)) { continue; } - result.emplace_back(discussion(*itr, db)); + result.emplace_back(pimpl->create_comment_api_object(*itr)); pimpl->fill_discussion(result.back(), query); } } From c3f68b9db97a87e96e58d6be01f622f076ff3dcb Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Fri, 6 Jul 2018 20:52:42 +0300 Subject: [PATCH 041/250] Add config flag to storing memo for transfers #797 --- libraries/chain/database.cpp | 8 +++ .../chain/include/golos/chain/database.hpp | 7 +++ .../golos/chain/steem_object_types.hpp | 2 +- libraries/chain/steem_evaluator.cpp | 7 ++- plugins/chain/plugin.cpp | 9 +++ plugins/mongo_db/mongo_db_state.cpp | 6 +- tests/tests/operation_tests.cpp | 63 +++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 7d97b13f44..76ba212e48 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -368,6 +368,14 @@ namespace golos { namespace chain { return std::find(v.begin(), v.end(), name) != v.end(); } + void database::set_store_memo_in_savings_withdraws(bool store_memo_in_savings_withdraws) { + _store_memo_in_savings_withdraws = store_memo_in_savings_withdraws; + } + + bool database::store_memo_in_savings_withdraws() const { + return _store_memo_in_savings_withdraws; + } + void database::set_skip_virtual_ops() { _skip_virtual_ops = true; } diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index b64d6075ed..e463db5eb6 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -105,10 +105,14 @@ namespace golos { namespace chain { void set_clear_votes(uint32_t clear_votes_block); void set_skip_virtual_ops(); bool clear_votes(); + void set_store_account_metadata(store_metadata_modes store_account_metadata); void set_accounts_to_store_metadata(const std::vector& accounts_to_store_metadata); bool store_metadata_for_account(const std::string& name) const; + void set_store_memo_in_savings_withdraws(bool store_memo_in_savings_withdraws); + bool store_memo_in_savings_withdraws() const; + /** * @brief wipe Delete database from disk, and potentially the raw chain as well. * @param include_blocks If true, delete the raw chain as well as the database. @@ -627,9 +631,12 @@ namespace golos { namespace chain { uint32_t _clear_votes_block = 0; bool _skip_virtual_ops = false; bool _enable_plugins_on_push_transaction = true; + store_metadata_modes _store_account_metadata = store_metadata_for_all; std::vector _accounts_to_store_metadata; + bool _store_memo_in_savings_withdraws = true; + flat_map> _custom_operation_interpreters; std::string _json_schema; }; diff --git a/libraries/chain/include/golos/chain/steem_object_types.hpp b/libraries/chain/include/golos/chain/steem_object_types.hpp index 350625a480..c937546cde 100644 --- a/libraries/chain/include/golos/chain/steem_object_types.hpp +++ b/libraries/chain/include/golos/chain/steem_object_types.hpp @@ -33,7 +33,7 @@ namespace golos { namespace chain { return std::string(str.begin(), str.end()); } - inline void from_string(shared_string &out, const string &in) { + inline void from_string(shared_string &out, const std::string &in) { out.assign(in.begin(), in.end()); } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 7b46405150..721931df58 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2110,13 +2110,14 @@ namespace golos { namespace chain { FC_ASSERT(_db.get_savings_balance(from, op.amount.symbol) >= op.amount); _db.adjust_savings_balance(from, -op.amount); + _db.create([&](savings_withdraw_object &s) { s.from = op.from; s.to = op.to; s.amount = op.amount; -#ifndef IS_LOW_MEM - from_string(s.memo, op.memo); -#endif + if (_db.store_memo_in_savings_withdraws()) { + from_string(s.memo, op.memo); + } s.request_id = op.request_id; s.complete = _db.head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME; diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 8b15f1f6d7..1caf0971f1 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -59,6 +59,8 @@ namespace chain { std::vector accounts_to_store_metadata; + bool store_memo_in_savings_withdraws = true; + plugin_impl() { // get default settings read_wait_micro = db.read_wait_micro(); @@ -242,6 +244,9 @@ namespace chain { ) ( "store-account-metadata-list", boost::program_options::value(), "names of accounts to store metadata" + ) ( + "store-memo-in-savings-withdraws", boost::program_options::bool_switch()->default_value(true), + "store memo for all savings withdraws" ); cli.add_options() ( @@ -340,6 +345,8 @@ namespace chain { " because store-account-metadata is false"); } } + + my->store_memo_in_savings_withdraws = options.at("store-memo-in-savings-withdraws").as(); } void plugin::plugin_startup() { @@ -370,6 +377,8 @@ namespace chain { my->db.set_accounts_to_store_metadata(my->accounts_to_store_metadata); + my->db.set_store_memo_in_savings_withdraws(my->store_memo_in_savings_withdraws); + if(my->skip_virtual_ops) { my->db.set_skip_virtual_ops(); } diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index a6429dcb0f..62980abb9e 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -1168,9 +1168,9 @@ namespace mongo_db { format_value(body, "removed", false); format_value(body, "from", op.from); format_value(body, "to", op.to); -#ifndef IS_LOW_MEM - format_value(body, "memo", op.memo); -#endif + if (db_.store_memo_in_savings_withdraws()) { + format_value(body, "memo", op.memo); + } format_value(body, "request_id", swo.request_id); format_value(body, "amount", op.amount); format_value(body, "complete", swo.complete); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 1e3bc48225..3612ab4afc 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -5712,6 +5712,69 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(transfer_from_savings_memo_storing_flag) { + try { + BOOST_TEST_MESSAGE("Testing: transfer_from_savings_memo_storing_flag"); + + ACTORS((alice)(bob)); + generate_block(); + + fund("alice", ASSET("10.000 GOLOS")); + + transfer_to_savings_operation save; + save.from = "alice"; + save.to = "alice"; + save.amount = ASSET("10.000 GOLOS"); + + signed_transaction tx; + tx.operations.push_back(save); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.sign(alice_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + + // Default is true + + transfer_from_savings_operation op; + op.from = "alice"; + op.to = "alice"; + op.amount = ASSET("1.000 GOLOS"); + op.request_id = 1; + op.memo = "{\"test\":123}"; + + tx.clear(); + tx.operations.push_back(op); + tx.sign(alice_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + + BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); + + db->set_store_memo_in_savings_withdraws(true); + + op.request_id = 2; + + tx.clear(); + tx.operations.push_back(op); + tx.sign(alice_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + + BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); + + db->set_store_memo_in_savings_withdraws(false); + + op.request_id = 3; + + tx.clear(); + tx.operations.push_back(op); + tx.sign(alice_private_key, db->get_chain_id()); + db->push_transaction(tx, 0); + + BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == ""); + + validate_database(); + } + FC_LOG_AND_RETHROW() + } + BOOST_AUTO_TEST_CASE(cancel_transfer_from_savings_validate) { try { BOOST_TEST_MESSAGE("Testing: cancel_transfer_from_savings_validate"); From 1dd0776c59795a4478e8c11db04e3419e01ccf20 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 9 Jul 2018 18:09:52 +0300 Subject: [PATCH 042/250] Fixed some build errors. #796 --- libraries/api/discussion_helper.cpp | 13 +++++ libraries/chain/steem_evaluator.cpp | 2 +- plugins/follow/plugin.cpp | 6 +- .../plugins/social_network/social_network.hpp | 8 +-- plugins/social_network/social_network.cpp | 55 ++++++++++++++----- .../golos/plugins/tags/tag_visitor.hpp | 6 +- plugins/tags/plugin.cpp | 6 +- plugins/tags/tag_visitor.cpp | 8 +-- 8 files changed, 76 insertions(+), 28 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index fc7caf48f0..bc55a4f7d0 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -62,6 +62,12 @@ namespace golos { namespace api { fill_reputation_(fill_reputation), fill_promoted_(fill_promoted) { } + impl( + golos::chain::database& db, + std::function get_comment_content_callback) + : database_(db), + get_comment_content_callback(get_comment_content_callback) { + } ~impl() = default; discussion create_discussion(const std::string& author) const ; @@ -307,6 +313,13 @@ namespace golos { namespace api { pimpl = std::make_unique(db, fill_reputation, fill_promoted); } + discussion_helper::discussion_helper( + golos::chain::database& db, + std::function get_comment_content_callback + ) { + pimpl = std::make_unique(db, get_comment_content_callback); + } + discussion_helper::~discussion_helper() = default; // diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 7d181cbaed..42010902c2 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -6,7 +6,7 @@ #ifndef IS_LOW_MEM -#include +// #include #include using boost::locale::conv::utf_to_utf; diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index d01a343e2f..1efdcd09c4 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #define CHECK_ARG_SIZE(s) \ FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); @@ -24,6 +25,7 @@ namespace golos { using golos::chain::to_string; using golos::chain::account_index; using golos::chain::by_name; + using golos::api::discussion_helper; void fill_account_reputation( const golos::chain::database& db, @@ -288,7 +290,7 @@ namespace golos { impl() : database_(appbase::app().get_plugin().db()) { helper = std::make_unique( database_, - golos::social_network::plugins::get_comment_content_callback; + golos::plugins::social_network::get_comment_content_callback ); } @@ -634,7 +636,7 @@ namespace golos { while (itr != blog_idx.end() && itr->account == account && result.size() < limit) { const auto &comment = db.get(itr->comment); comment_blog_entry entry; - entry.comment = comment_api_object(comment, db); + entry.comment = helper->create_comment_api_object(comment); entry.blog = account; entry.reblog_on = itr->reblogged_on; entry.entry_id = itr->blog_feed_id; diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index cc7b68ca9d..8d7ad3128c 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -99,9 +99,9 @@ namespace golos { namespace plugins { namespace social_network { typedef multi_index_container< comment_content_object, indexed_by< - ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id>>, - ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment>>>, - allocator< comment_content_object > + ordered_unique, member>, + ordered_unique, member>>, + allocator > comment_content_index; // Callback which is needed for correct work of discussion_helper @@ -109,7 +109,7 @@ namespace golos { namespace plugins { namespace social_network { if (!db.has_index()) { return get_comment_content_res(); } - auto & content = db.get(o); + auto & content = db.get(o.id); get_comment_content_res result; diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 79762966b6..451eca5023 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -9,6 +9,10 @@ #include #include +#include +// #include +#include + #define CHECK_ARG_SIZE(_S) \ FC_ASSERT( \ args.args->size() == _S, \ @@ -34,6 +38,8 @@ namespace golos { namespace plugins { namespace social_network { using golos::plugins::tags::fill_promoted; using golos::api::discussion_helper; + using boost::locale::conv::utf_to_utf; + struct social_network::impl final { impl(): database_(appbase::app().get_plugin().db()) { helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted); @@ -123,6 +129,31 @@ namespace golos { namespace plugins { namespace social_network { } struct operation_visitor { + golos::chain::database &db; + + operation_visitor(golos::chain::database &db) : db(db) { + } + + // using boost::locale::conv::utf_to_utf; + + std::wstring utf8_to_wstring(const std::string &str) const { + return utf_to_utf(str.c_str(), str.c_str() + str.size()); + } + + std::string wstring_to_utf8(const std::wstring &str) const { + return utf_to_utf(str.c_str(), str.c_str() + str.size()); + } + + const comment_content_object &get_comment_content(const comment_id_type &comment) const { + try { + return db.get(comment); + } FC_CAPTURE_AND_RETHROW((comment)) + } + + const comment_content_object *find_comment_content(const comment_id_type &comment) const { + return db.find(comment); + } + using result_type = void; template @@ -130,16 +161,12 @@ namespace golos { namespace plugins { namespace social_network { } void operator()(const delete_comment_operation& o) const { - auto & db = database(); - - const auto &comment = _db.get_comment(o.author, o.permlink); - auto& content = db.get_comment_content(comment.id); + const auto &comment = db.get_comment(o.author, o.permlink); + auto& content = get_comment_content(comment.id); db.remove(content); } void operator()(const golos::protocol::comment_operation& o) const { - auto & db = database(); - const auto& comment = db.get_comment(o.author, o.permlink); if (comment.created != db.head_block_time()) { @@ -189,6 +216,10 @@ namespace golos { namespace plugins { namespace social_network { parent = &db.get_comment(o.parent_author, o.parent_permlink); } + // const auto& new_comment = database().get_comment(o.author, permlink); + + comment_id_type id = parent->id; + db.create([&](comment_content_object& con) { con.comment = id; from_string(con.title, o.title); @@ -210,14 +241,12 @@ namespace golos { namespace plugins { namespace social_network { } void social_network::impl::post_operation(const operation_notification &o) { - operation_visitor ovisit; - auto x = o.op.visit(ovisit); - - auto& db = pimpl->database(); + auto& db = database(); - if (!x.valid) { - return; - } + operation_visitor ovisit( db ); + + o.op.visit(ovisit); + // else work with comment_operation and upd content // std::cout << "\t\to.op.visit(ovisit) :\n\t\t" << "x.title = [" << x.title << "]\n\t\t" << diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 0a889f9fcc..1693ad6e5f 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -4,14 +4,18 @@ #include #include #include +#include + namespace golos { namespace plugins { namespace tags { + using golos::api::discussion_helper; struct operation_visitor { - operation_visitor(database& db); + operation_visitor(database& db, const std::shared_ptr &helper); using result_type = void; database& db_; + std::shared_ptr helper_; void remove_stats(const tag_object& tag) const; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index f353895e89..2adbe3c90f 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -35,7 +35,7 @@ namespace golos { namespace plugins { namespace tags { struct tags_plugin::impl final { impl(): database_(appbase::app().get_plugin().db()) { - helper = std::make_unique( + helper = std::make_shared( database_, follow::fill_account_reputation, fill_promoted); @@ -47,7 +47,7 @@ namespace golos { namespace plugins { namespace tags { #ifndef IS_LOW_MEM try { /// plugins shouldn't ever throw - note.op.visit(tags::operation_visitor(database())); + note.op.visit(tags::operation_visitor(database(), helper)); } catch (const fc::exception& e) { edump((e.to_detail_string())); } catch (...) { @@ -121,7 +121,7 @@ namespace golos { namespace plugins { namespace tags { private: golos::chain::database& database_; - std::unique_ptr helper; + std::shared_ptr helper; }; void tags_plugin::impl::select_active_votes( diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index 5e54276856..9a6f8a139f 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -3,8 +3,8 @@ namespace golos { namespace plugins { namespace tags { - operation_visitor::operation_visitor(database& db) - : db_(db) { + operation_visitor::operation_visitor(database& db, const std::shared_ptr &helper) + : db_(db), helper_(helper) { } void operation_visitor::remove_stats(const tag_object& tag) const { @@ -174,7 +174,7 @@ namespace golos { namespace plugins { namespace tags { auto trending = calculate_trending(comment.net_rshares, comment.created); const auto& comment_idx = db_.get_index().indices().get(); - auto meta = get_metadata(comment_api_object(comment, db_)); + auto meta = get_metadata(helper_->create_comment_api_object(comment)); auto citr = comment_idx.lower_bound(comment.id); const tag_object* language_tag = nullptr; @@ -307,7 +307,7 @@ namespace golos { namespace plugins { namespace tags { const auto& comment = db_.get_comment(op.author, op.permlink); const auto& author = db_.get_account(op.author).id; - auto meta = get_metadata(comment_api_object(comment, db_)); + auto meta = get_metadata(helper_->create_comment_api_object(comment)); const auto& stats_idx = db_.get_index().indices().get(); const auto& auth_idx = db_.get_index().indices().get(); From ed5df25ed2f51f55c356f43fb0a965011328b972 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Tue, 10 Jul 2018 09:47:13 +0300 Subject: [PATCH 043/250] Fixed linking errors. #796 --- .../plugins/social_network/social_network.hpp | 15 +-------------- plugins/social_network/social_network.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 8d7ad3128c..87a30a95b1 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -105,20 +105,7 @@ namespace golos { namespace plugins { namespace social_network { > comment_content_index; // Callback which is needed for correct work of discussion_helper - get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) { - if (!db.has_index()) { - return get_comment_content_res(); - } - auto & content = db.get(o.id); - - get_comment_content_res result; - - result.title = std::string(content.title.begin(), content.title.end()); - result.body = std::string(content.body.begin(), content.body.end()); - result.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); - - return result; - } + get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o); } } } // golos::plugins::social_network diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 451eca5023..194af5db0c 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -493,4 +493,20 @@ namespace golos { namespace plugins { namespace social_network { }); } + + get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) { + if (!db.has_index()) { + return get_comment_content_res(); + } + auto & content = db.get(o.id); + + get_comment_content_res result; + + result.title = std::string(content.title.begin(), content.title.end()); + result.body = std::string(content.body.begin(), content.body.end()); + result.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); + + return result; + } + } } } // golos::plugins::social_network From 1fb522e2094a717794b267bc6c6c308b1b417d47 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Mon, 2 Jul 2018 13:11:04 +0300 Subject: [PATCH 044/250] cli_wallet Fix signing of transactions when another account_auths #699 --- libraries/wallet/wallet.cpp | 140 +++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 65 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 8a667d6c7e..24b83f1b6e 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -687,88 +687,94 @@ namespace golos { namespace wallet { flat_set< account_name_type > req_posting_approvals; vector< authority > other_auths; - tx.get_required_authorities( req_active_approvals, req_owner_approvals, req_posting_approvals, other_auths ); + // gets required account names of operations + tx.get_required_authorities( req_active_approvals, req_owner_approvals, + req_posting_approvals, other_auths ); for( const auto& auth : other_auths ) for( const auto& a : auth.account_auths ) req_active_approvals.insert(a.first); - // std::merge lets us de-duplicate account_id's that occur in both - // sets, and dump them into a vector (as required by remote_db api) - // at the same time - vector< account_name_type > v_approving_account_names; - std::merge(req_active_approvals.begin(), req_active_approvals.end(), - req_owner_approvals.begin() , req_owner_approvals.end(), - std::back_inserter( v_approving_account_names ) ); + // collects all keys to common set and accounts to common map + + flat_map approving_account_lut; - for( const auto& a : req_posting_approvals ) - v_approving_account_names.push_back(a); - - /// TODO: fetch the accounts specified via other_auths as well. - - auto approving_account_objects = _remote_database_api->get_accounts( v_approving_account_names ); - - /// TODO: recursively check one layer deeper in the authority tree for keys - - FC_ASSERT( approving_account_objects.size() == v_approving_account_names.size(), "", ("aco.size:", approving_account_objects.size())("acn",v_approving_account_names.size()) ); + flat_set approving_key_set; - flat_map< string, golos::api::account_api_object > approving_account_lut; - size_t i = 0; - for( const optional< golos::api::account_api_object >& approving_acct : approving_account_objects ) { - if( !approving_acct.valid() ) { - wlog( "operation_get_required_auths said approval of non-existing account ${name} was needed", - ("name", v_approving_account_names[i]) ); - i++; - continue; - } - approving_account_lut[ approving_acct->name ] = *approving_acct; - i++; - } - auto get_account_from_lut = [&]( const std::string& name ) -> const golos::api::account_api_object& { - auto it = approving_account_lut.find( name ); - FC_ASSERT( it != approving_account_lut.end() ); - return it->second; - }; + std::vector active_account_auths; + std::vector owner_account_auths; + std::vector posting_account_auths; - flat_set approving_key_set; - for( account_name_type& acct_name : req_active_approvals ) { - const auto it = approving_account_lut.find( acct_name ); - if( it == approving_account_lut.end() ) - continue; - const golos::api::account_api_object& acct = it->second; - vector v_approving_keys = acct.active.get_keys(); - wdump((v_approving_keys)); - for( const public_key_type& approving_key : v_approving_keys ) { + auto fetch_keys = [&](const authority& auth) { + for (const public_key_type& approving_key : auth.get_keys()) { wdump((approving_key)); approving_key_set.insert( approving_key ); } + }; + + if (!req_active_approvals.empty()) { + auto req_active_accs =_remote_database_api->get_accounts(std::vector( + req_active_approvals.begin(), req_active_approvals.end())); + for (auto& acc : req_active_accs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.active); + for (const auto& auth : acc.active.account_auths) { + active_account_auths.push_back(auth.first); + } + } } - - for( account_name_type& acct_name : req_posting_approvals ) { - const auto it = approving_account_lut.find( acct_name ); - if( it == approving_account_lut.end() ) - continue; - const golos::api::account_api_object& acct = it->second; - vector v_approving_keys = acct.posting.get_keys(); - wdump((v_approving_keys)); - for( const public_key_type& approving_key : v_approving_keys ) - { - wdump((approving_key)); - approving_key_set.insert( approving_key ); + if (!req_owner_approvals.empty()) { + auto req_owner_accs =_remote_database_api->get_accounts(std::vector( + req_owner_approvals.begin(), req_owner_approvals.end())); + for (auto& acc : req_owner_accs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.owner); + for (const auto& auth : acc.owner.account_auths) { + owner_account_auths.push_back(auth.first); + } + } + } + if (!req_posting_approvals.empty()) { + auto req_posting_accs =_remote_database_api->get_accounts(std::vector( + req_posting_approvals.begin(), req_posting_approvals.end())); + for (auto& acc : req_posting_accs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.posting); + for (const auto& auth : acc.posting.account_auths) { + posting_account_auths.push_back(auth.first); + } } } - for( const account_name_type& acct_name : req_owner_approvals ) { - const auto it = approving_account_lut.find( acct_name ); - if( it == approving_account_lut.end() ) - continue; - const golos::api::account_api_object& acct = it->second; - vector v_approving_keys = acct.owner.get_keys(); - for( const public_key_type& approving_key : v_approving_keys ) { - wdump((approving_key)); - approving_key_set.insert( approving_key ); + if (!active_account_auths.empty()) { + auto active_account_auth_objs = _remote_database_api->get_accounts(active_account_auths); + for (auto& acc : active_account_auth_objs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.active); } } + if (!owner_account_auths.empty()) { + auto owner_account_auth_objs = _remote_database_api->get_accounts(owner_account_auths); + for (auto& acc : owner_account_auth_objs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.owner); + } + } + if (!posting_account_auths.empty()) { + auto posting_account_auth_objs = _remote_database_api->get_accounts(posting_account_auths); + for (auto& acc : posting_account_auth_objs) { + approving_account_lut[acc.name] = acc; + fetch_keys(acc.posting); + } + } + + auto get_account_from_lut = [&]( const std::string& name ) -> const golos::api::account_api_object& { + auto it = approving_account_lut.find( name ); + FC_ASSERT( it != approving_account_lut.end(), "No account in lut: '${name}'", ("name",name) ); + return it->second; + }; + + // get keys of each other auth into common set for( const authority& a : other_auths ) { for( const auto& k : a.key_auths ) { wdump((k.first)); @@ -781,6 +787,8 @@ namespace golos { namespace wallet { tx.set_expiration( dyn_props.time + fc::seconds(_tx_expiration_seconds) ); tx.signatures.clear(); + // checking each key from common set exists in wallet's keys + // and adding available ones to available set and map //idump((_keys)); flat_set< public_key_type > available_keys; flat_map< public_key_type, fc::ecc::private_key > available_private_keys; @@ -796,6 +804,7 @@ namespace golos { namespace wallet { } } + // removing excessive keys from available keys set auto minimal_signing_keys = tx.minimize_required_signatures( steem_chain_id, available_keys, @@ -808,6 +817,7 @@ namespace golos { namespace wallet { STEEMIT_MAX_SIG_CHECK_DEPTH ); + // checking if each private key exists and signing tx with it for( const public_key_type& k : minimal_signing_keys ) { auto it = available_private_keys.find(k); FC_ASSERT( it != available_private_keys.end() ); From 666cbf2eda6a961d82a979e546e1d558f2e06f80 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 5 Jul 2018 12:51:43 +0700 Subject: [PATCH 045/250] Cleanup code from unused exceptions. #786 --- .../golos/chain/database_exceptions.hpp | 73 ------------------- .../include/golos/network/exceptions.hpp | 4 - .../golos/plugins/json_rpc/utility.hpp | 4 - plugins/json_rpc/plugin.cpp | 13 +--- 4 files changed, 3 insertions(+), 91 deletions(-) diff --git a/libraries/chain/include/golos/chain/database_exceptions.hpp b/libraries/chain/include/golos/chain/database_exceptions.hpp index 544717fc4b..d13f689010 100644 --- a/libraries/chain/include/golos/chain/database_exceptions.hpp +++ b/libraries/chain/include/golos/chain/database_exceptions.hpp @@ -2,46 +2,6 @@ #include -#define STEEMIT_DECLARE_OP_BASE_EXCEPTIONS(op_name) \ - FC_DECLARE_DERIVED_EXCEPTION( \ - op_name ## _validate_exception, \ - golos::chain::operation_validate_exception, \ - 4040000 + 100 * protocol::operation::tag< protocol::op_name ## _operation >::value, \ - #op_name "_operation validation exception" \ - ) \ - FC_DECLARE_DERIVED_EXCEPTION( \ - op_name ## _evaluate_exception, \ - golos::chain::operation_evaluate_exception, \ - 4050000 + 100 * protocol::operation::tag< protocol::op_name ## _operation >::value, \ - #op_name "_operation evaluation exception" \ - ) - -#define STEEMIT_DECLARE_OP_VALIDATE_EXCEPTION(exc_name, op_name, seqnum, msg) \ - FC_DECLARE_DERIVED_EXCEPTION( \ - op_name ## _ ## exc_name, \ - golos::chain::op_name ## _validate_exception, \ - 4040000 + 100 * protocol::operation::tag< protocol::op_name ## _operation >::value \ - + seqnum, \ - msg \ - ) - -#define STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION(exc_name, op_name, seqnum, msg) \ - FC_DECLARE_DERIVED_EXCEPTION( \ - op_name ## _ ## exc_name, \ - golos::chain::op_name ## _evaluate_exception, \ - 4050000 + 100 * protocol::operation::tag< protocol::op_name ## _operation >::value \ - + seqnum, \ - msg \ - ) - -#define STEEMIT_DECLARE_INTERNAL_EXCEPTION(exc_name, seqnum, msg) \ - FC_DECLARE_DERIVED_EXCEPTION( \ - internal_ ## exc_name, \ - golos::chain::internal_exception, \ - 4990000 + seqnum, \ - msg \ - ) - #define STEEMIT_TRY_NOTIFY(signal, ...) \ try \ { \ @@ -66,18 +26,6 @@ namespace golos { FC_DECLARE_EXCEPTION(chain_exception, 4000000, "blockchain exception") - FC_DECLARE_DERIVED_EXCEPTION(database_query_exception, golos::chain::chain_exception, 4010000, "database query exception") - - FC_DECLARE_DERIVED_EXCEPTION(block_validate_exception, golos::chain::chain_exception, 4020000, "block validation exception") - - FC_DECLARE_DERIVED_EXCEPTION(transaction_exception, golos::chain::chain_exception, 4030000, "transaction validation exception") - - FC_DECLARE_DERIVED_EXCEPTION(operation_validate_exception, golos::chain::chain_exception, 4040000, "operation validation exception") - - FC_DECLARE_DERIVED_EXCEPTION(operation_evaluate_exception, golos::chain::chain_exception, 4050000, "operation evaluation exception") - - FC_DECLARE_DERIVED_EXCEPTION(utility_exception, golos::chain::chain_exception, 4060000, "utility method exception") - FC_DECLARE_DERIVED_EXCEPTION(undo_database_exception, golos::chain::chain_exception, 4070000, "undo database exception") FC_DECLARE_DERIVED_EXCEPTION(unlinkable_block_exception, golos::chain::chain_exception, 4080000, "unlinkable block") @@ -90,27 +38,6 @@ namespace golos { FC_DECLARE_DERIVED_EXCEPTION(pop_empty_chain, golos::chain::undo_database_exception, 4070001, "there are no blocks to pop") - STEEMIT_DECLARE_OP_BASE_EXCEPTIONS(transfer); -// STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION( from_account_not_whitelisted, transfer, 1, "owner mismatch" ) - - STEEMIT_DECLARE_OP_BASE_EXCEPTIONS(account_create); - - STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION(max_auth_exceeded, account_create, 1, "Exceeds max authority fan-out") - - STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION(auth_account_not_found, account_create, 2, "Auth account not found") - - STEEMIT_DECLARE_OP_BASE_EXCEPTIONS(account_update); - - STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION(max_auth_exceeded, account_update, 1, "Exceeds max authority fan-out") - - STEEMIT_DECLARE_OP_EVALUATE_EXCEPTION(auth_account_not_found, account_update, 2, "Auth account not found") - - FC_DECLARE_DERIVED_EXCEPTION(internal_exception, golos::chain::chain_exception, 4990000, "internal exception") - - STEEMIT_DECLARE_INTERNAL_EXCEPTION(verify_auth_max_auth_exceeded, 1, "Exceeds max authority fan-out") - - STEEMIT_DECLARE_INTERNAL_EXCEPTION(verify_auth_account_not_found, 2, "Auth account not found") - FC_DECLARE_DERIVED_EXCEPTION(database_revision_exception, golos::chain::chain_exception, 4120000, "database revision exception") FC_DECLARE_DERIVED_EXCEPTION(database_signal_exception, golos::chain::chain_exception, 4130000, "database signal exception") diff --git a/libraries/network/include/golos/network/exceptions.hpp b/libraries/network/include/golos/network/exceptions.hpp index b31eed0515..ff185c2d7f 100644 --- a/libraries/network/include/golos/network/exceptions.hpp +++ b/libraries/network/include/golos/network/exceptions.hpp @@ -32,10 +32,6 @@ namespace golos { FC_DECLARE_EXCEPTION(net_exception, 90000, "P2P Networking Exception"); - FC_DECLARE_DERIVED_EXCEPTION(send_queue_overflow, golos::network::net_exception, 90001, "send queue for this peer exceeded maximum size"); - - FC_DECLARE_DERIVED_EXCEPTION(insufficient_relay_fee, golos::network::net_exception, 90002, "insufficient relay fee"); - FC_DECLARE_DERIVED_EXCEPTION(already_connected_to_requested_peer, golos::network::net_exception, 90003, "already connected to requested peer"); FC_DECLARE_DERIVED_EXCEPTION(block_older_than_undo_history, golos::network::net_exception, 90004, "block is older than our undo history allows us to process"); diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp index f65e9d4f2a..fdd91db26d 100644 --- a/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp @@ -80,12 +80,8 @@ namespace golos { // Pass error to remote connection void error(int32_t code, std::string message, fc::optional data = fc::optional()); - void error(std::string message, fc::optional data = fc::optional()); - void error(int32_t code, const fc::exception &); - void error(const fc::exception &); - fc::optional error() const; private: diff --git a/plugins/json_rpc/plugin.cpp b/plugins/json_rpc/plugin.cpp index 591522fde5..6900666ef8 100644 --- a/plugins/json_rpc/plugin.cpp +++ b/plugins/json_rpc/plugin.cpp @@ -123,13 +123,6 @@ namespace golos { } } - void msg_pack::error(std::string message, fc::optional data) { - error(JSON_RPC_SERVER_ERROR, std::move(message), std::move(data)); - } - - void msg_pack::error(const fc::exception &e) { - error(JSON_RPC_SERVER_ERROR, e); - } void msg_pack::error(int32_t code, const fc::exception &e) { error(code, e.to_string(), fc::variant(*(e.dynamic_copy_exception()))); @@ -299,13 +292,13 @@ namespace golos { msg.error(JSON_RPC_INVALID_PARAMS, e); dump.error("invalid types"); } catch (const fc::exception& e) { - msg.error(e); + msg.error(JSON_RPC_INTERNAL_ERROR, e); dump.error("invalid request"); } catch (const std::exception& e) { - msg.error(e.what()); + msg.error(JSON_RPC_INTERNAL_ERROR, e.what()); dump.error(e.what()); } catch (...) { - msg.error("Unknown error - parsing rpc message failed"); + msg.error(JSON_RPC_INTERNAL_ERROR, "Unknown error - parsing rpc message failed"); dump.error("unknown"); } } From 55c34548db4e0838a97f557cbf671b0bad17734b Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 5 Jul 2018 13:29:39 +0700 Subject: [PATCH 046/250] Implement base exception and macros to work with errors #786 --- libraries/chain/database.cpp | 13 +- libraries/chain/steem_evaluator.cpp | 148 +++++++++++++++--- .../include/golos/protocol/exceptions.hpp | 117 ++++++++++++-- libraries/protocol/steem_operations.cpp | 28 ++-- plugins/json_rpc/CMakeLists.txt | 2 +- .../include/golos/plugins/json_rpc/plugin.hpp | 6 +- plugins/json_rpc/plugin.cpp | 12 ++ .../market_history/market_history_plugin.cpp | 30 +++- tests/tests/operation_tests.cpp | 20 +-- tests/tests/proposal_tests.cpp | 2 +- 10 files changed, 313 insertions(+), 65 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 76ba212e48..3422659bbe 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -611,7 +611,12 @@ namespace golos { namespace chain { const account_object &database::get_account(const account_name_type &name) const { try { return get(name); - } FC_CAPTURE_AND_RETHROW((name)) + } catch(const std::out_of_range &e) { + //GOLOS_THROW_MISSING_OBJECT("account", name); + GOLOS_ASSERT(false, missing_object, "Missing ${type} with id \"${id}\"", + ("type","account")("id",name)); + } + FC_CAPTURE_AND_RETHROW((name)) } const account_object *database::find_account(const account_name_type &name) const { @@ -3664,6 +3669,12 @@ namespace golos { namespace chain { try { apply_operation(op); ++_current_op_in_trx; + } catch(const fc::exception& e) { + FC_THROW_EXCEPTION(tx_invalid_operation, + "Invalid operation ${index} in transaction: ${errmsg}", + ("index", _current_op_in_trx) + ("errmsg", e.to_string()) + ("error", e)); } FC_CAPTURE_AND_RETHROW((op)); } _current_trx_id = transaction_id_type(); diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 721931df58..8feb0a2aba 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -21,10 +21,101 @@ std::string wstring_to_utf8(const std::wstring &str) { #endif +#define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) \ + FC_MULTILINE_MACRO_BEGIN \ + try { \ + VALIDATOR; \ + } catch (const fc::exception& e) { \ + FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for operation parameter \"${param}\": ${errmsg}", \ + ("param", FC_STRINGIZE(PARAM)) \ + ("value", OP.PARAM) \ + ("errmsg", e.to_string()) \ + ("error", e)); \ + } \ + FC_MULTILINE_MACRO_END + +#define GOLOS_CHECK_BALANCE( ACCOUNT, TYPE, REQUIRED ...) \ + FC_EXPAND_MACRO( \ + FC_MULTILINE_MACRO_BEGIN \ + asset exist = get_balance(ACCOUNT, TYPE, (REQUIRED).symbol); \ + if( UNLIKELY( exist < (REQUIRED) )) { \ + FC_THROW_EXCEPTION( golos::insufficient_funds, \ + "Account \"${account}\" does not have enough ${balance}: exist ${exist}, required ${required}", \ + ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("exist",exist)("required",REQUIRED)); \ + } \ + FC_MULTILINE_MACRO_END \ + ) + +#define GOLOS_CHECK_BANDWIDTH(COND, TYPE, MSG, ...) \ + GOLOS_ASSERT((COND), golos::bandwidth_exception, MSG, ("bandwidth",TYPE) __VA_ARGS__) + +#define GOLOS_CHECK_LOGIC(expr, TYPE, FORMAT, ...) \ + if (!(expr)) { \ + golos::logic_exception _E(FC_LOG_MESSAGE(error, FORMAT, ("err_id",TYPE)__VA_ARGS__)); \ + _E.err_id = TYPE; \ + throw _E; \ + } namespace golos { namespace chain { using fc::uint128_t; + enum balance_type { + MAIN_BALANCE, + SAVINGS, + VESTING, + EFFECTIVE_VESTING, + HAVING_VESTING, + AVAILABLE_VESTING + }; + + asset get_balance(const account_object &account, balance_type type, asset_symbol_type symbol) { + switch(type) { + case MAIN_BALANCE: + switch (symbol) { + case STEEM_SYMBOL: + return account.balance; + case SBD_SYMBOL: + return account.sbd_balance; + default: + FC_ASSERT(false, "invalid symbol"); + } + case SAVINGS: + switch (symbol) { + case STEEM_SYMBOL: + return account.savings_balance; + case SBD_SYMBOL: + return account.savings_sbd_balance; + default: + FC_ASSERT(false, "invalid symbol"); + } + case VESTING: + FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + return account.vesting_shares; + case EFFECTIVE_VESTING: + FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + return account.effective_vesting_shares(); + case HAVING_VESTING: + FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + return account.available_vesting_shares(false); + case AVAILABLE_VESTING: + FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + return account.available_vesting_shares(true); + default: FC_ASSERT(false, "invalid balance type"); + } + } + + std::string get_balance_name(balance_type type) { + switch(type) { + case MAIN_BALANCE: return "fund"; + case SAVINGS: return "savings"; + case VESTING: return "vesting shares"; + case EFFECTIVE_VESTING: return "effective vesting shares"; + case HAVING_VESTING: return "having vesting shares"; + case AVAILABLE_VESTING: return "available vesting shares"; + default: FC_ASSERT(false, "invalid balance type"); + } + } + inline void validate_permlink_0_1(const string &permlink) { FC_ASSERT(permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && permlink.size() < @@ -71,8 +162,8 @@ namespace golos { namespace chain { case '-': break; default: - FC_ASSERT(false, "Invalid permlink character: ${s}", ("s", - std::string() + c)); + FC_THROW_EXCEPTION(invalid_value, "Invalid permlink character: ${s}", + ("s", std::string() + c)); } } } @@ -519,11 +610,19 @@ namespace golos { namespace chain { if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__176)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) - FC_ASSERT((now - band->last_bandwidth_update) > - STEEMIT_MIN_ROOT_COMMENT_INTERVAL, "You may only post once every 5 minutes.", ("now", now)("last_root_post", band->last_bandwidth_update)); + GOLOS_CHECK_BANDWIDTH((now - band->last_bandwidth_update) > STEEMIT_MIN_ROOT_COMMENT_INTERVAL, + golos::bandwidth_exception::post_bandwidth, + "You may only post once every 5 minutes.", + ("now", now) + ("last", band->last_bandwidth_update) + ("next", band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL)); else - FC_ASSERT((now - auth.last_post) > - STEEMIT_MIN_REPLY_INTERVAL, "You may only comment once every 20 seconds.", ("now", now)("auth.last_post", auth.last_post)); + GOLOS_CHECK_BANDWIDTH((now - auth.last_post) > STEEMIT_MIN_REPLY_INTERVAL, + golos::bandwidth_exception::comment_bandwidth, + "You may only comment once every 20 seconds.", + ("now", now) + ("last", auth.last_post) + ("next", auth.last_post + STEEMIT_MIN_REPLY_INTERVAL)); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_6__113)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) FC_ASSERT((now - auth.last_post) > @@ -570,8 +669,8 @@ namespace golos { namespace chain { const auto &new_comment = _db.create([&](comment_object &com) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) { - validate_permlink_0_1(o.parent_permlink); - validate_permlink_0_1(o.permlink); + GOLOS_CHECK_OP_PARAM(o, parent_permlink, validate_permlink_0_1(o.parent_permlink)); + GOLOS_CHECK_OP_PARAM(o, permlink, validate_permlink_0_1(o.permlink)); } com.author = o.author; @@ -656,15 +755,12 @@ namespace golos { namespace chain { com.active = com.last_update; strcmp_equal equal; - if (!parent) { - FC_ASSERT(com.parent_author == - account_name_type(), "The parent of a comment cannot change."); - FC_ASSERT(equal(com.parent_permlink, o.parent_permlink), "The permlink of a comment cannot change."); - } else { - FC_ASSERT(com.parent_author == - o.parent_author, "The parent of a comment cannot change."); - FC_ASSERT(equal(com.parent_permlink, o.parent_permlink), "The permlink of a comment cannot change."); - } + GOLOS_CHECK_LOGIC(com.parent_author == (parent ? o.parent_author : account_name_type()), + logic_exception::parent_of_comment_cannot_change, + "The parent of a comment cannot change."); + GOLOS_CHECK_LOGIC(equal(com.parent_permlink, o.parent_permlink), + logic_exception::parent_perlink_of_comment_cannot_change, + "The parent permlink of a comment cannot change."); }); #ifndef IS_LOW_MEM @@ -894,8 +990,8 @@ namespace golos { namespace chain { }); } - FC_ASSERT(_db.get_balance(from_account, o.amount.symbol) >= - o.amount, "Account does not have sufficient funds for transfer."); + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); + _db.adjust_balance(from_account, -o.amount); _db.adjust_balance(to_account, o.amount); } @@ -2092,8 +2188,8 @@ namespace golos { namespace chain { database &_db = db(); const auto &from = _db.get_account(op.from); const auto &to = _db.get_account(op.to); - FC_ASSERT(_db.get_balance(from, op.amount.symbol) >= - op.amount, "Account does not have sufficient funds to transfer to savings."); + + GOLOS_CHECK_BALANCE(from, MAIN_BALANCE, op.amount); _db.adjust_balance(from, -op.amount); _db.adjust_savings_balance(to, op.amount); @@ -2104,11 +2200,13 @@ namespace golos { namespace chain { const auto &from = _db.get_account(op.from); _db.get_account(op.to); // Verify to account exists - FC_ASSERT(from.savings_withdraw_requests < - STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT, "Account has reached limit for pending withdraw requests."); + GOLOS_CHECK_LOGIC(from.savings_withdraw_requests < STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT, + golos::logic_exception::reached_limit_for_pending_withdraw_requests, + "Account has reached limit for pending withdraw requests.", + ("limit",STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT)); + + GOLOS_CHECK_BALANCE(from, SAVINGS, op.amount); - FC_ASSERT(_db.get_savings_balance(from, op.amount.symbol) >= - op.amount); _db.adjust_savings_balance(from, -op.amount); _db.create([&](savings_withdraw_object &s) { diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index fa1c208dc4..06318e21d8 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -14,9 +14,11 @@ } #define GOLOS_ASSERT(expr, exception_type, FORMAT, ...) \ - if (!(expr)) { \ - throw exception_type(GOLOS_ASSERT_MESSAGE(FORMAT, __VA_ARGS__)); \ - } + FC_MULTILINE_MACRO_BEGIN \ + if (!(expr)) { \ + throw exception_type(GOLOS_ASSERT_MESSAGE(FORMAT, __VA_ARGS__)); \ + } \ + FC_MULTILINE_MACRO_END #define GOLOS_DECLARE_DERIVED_EXCEPTION_BODY(TYPE, BASE, CODE, WHAT) \ public: \ @@ -50,41 +52,123 @@ GOLOS_DECLARE_DERIVED_EXCEPTION_BODY(TYPE, BASE, CODE, WHAT) \ }; +#define GOLOS_CHECK_PARAM(PARAM, VALIDATOR) \ + FC_MULTILINE_MACRO_BEGIN \ + try { \ + VALIDATOR; \ + } catch (const fc::exception& e) { \ + FC_THROW_EXCEPTION(golos::invalid_parameter, "Invalid value \"${value}\" for parameter \"${param}\": ${errmsg}", \ + ("param", FC_STRINGIZE(PARAM)) \ + ("value", PARAM) \ + ("errmsg", e.to_string()) \ + ("error", e)); \ + } \ + FC_MULTILINE_MACRO_END + +#define GOLOS_CHECK_VALUE(COND, MSG, ...) \ + GOLOS_ASSERT((COND), golos::invalid_value, MSG, __VA_ARGS__) + +namespace golos { + GOLOS_DECLARE_DERIVED_EXCEPTION( + golos_exception, fc::exception, + 300000, "golos base exception") + + + GOLOS_DECLARE_DERIVED_EXCEPTION( + insufficient_funds, golos_exception, + 300001, "Account does not have sufficient funds") + + GOLOS_DECLARE_DERIVED_EXCEPTION( + missing_object, golos_exception, + 300002, "Missing object"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + invalid_parameter, golos_exception, + 300004, "Invalid parameter value"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + limit_too_large, invalid_parameter, + 300003, "Exceeded limit value"); + + class bandwidth_exception : public golos_exception { + GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( + bandwidth_exception, golos_exception, + 400001, "bandwidth exceeded error"); + public: + enum bandwidth_types { + post_bandwidth, + comment_bandwidth, + }; + }; + + class logic_exception : public golos_exception { + GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( + logic_exception, golos_exception, + 400000, "business logic error"); + public: + enum error_types { + reached_limit_for_pending_withdraw_requests = 1, + parent_of_comment_cannot_change, + parent_perlink_of_comment_cannot_change, + }; + + error_types err_id; + }; + + GOLOS_DECLARE_DERIVED_EXCEPTION( + internal_error, golos_exception, + 300005, "internal error"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + invalid_value, internal_error, + 300006, "invalid value exception"); + +} // golos + + namespace golos { namespace protocol { GOLOS_DECLARE_DERIVED_EXCEPTION( transaction_exception, fc::exception, 3000000, "transaction exception") - class tx_missing_active_auth: public transaction_exception { + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_invalid_operation, transaction_exception, + 3000001, "invalid operation in transaction"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_missing_authority, transaction_exception, + 3010099, "missing authority"); + + class tx_missing_active_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - tx_missing_active_auth, transaction_exception, + tx_missing_active_auth, tx_missing_authority, 3010000, "missing required active authority"); public: std::vector missing_accounts; std::vector used_signatures; }; - class tx_missing_owner_auth: public transaction_exception { + class tx_missing_owner_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - tx_missing_owner_auth, transaction_exception, + tx_missing_owner_auth, tx_missing_authority, 3020000, "missing required owner authority"); public: std::vector missing_accounts; std::vector used_signatures; }; - class tx_missing_posting_auth: public transaction_exception { + class tx_missing_posting_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - tx_missing_posting_auth, transaction_exception, + tx_missing_posting_auth, tx_missing_authority, 3030000, "missing required posting authority"); public: std::vector missing_accounts; std::vector used_signatures; }; - class tx_missing_other_auth: public transaction_exception { + class tx_missing_other_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - tx_missing_other_auth, transaction_exception, + tx_missing_other_auth, tx_missing_authority, 3040000, "missing required other authority"); public: std::vector missing_auths; @@ -113,3 +197,14 @@ namespace golos { namespace protocol { }; } } // golos::protocol + +FC_REFLECT_ENUM(golos::logic_exception::error_types, + (reached_limit_for_pending_withdraw_requests) + (parent_of_comment_cannot_change) + (parent_perlink_of_comment_cannot_change) +); + +FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, + (post_bandwidth) + (comment_bandwidth) +); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 786c723a04..baddba5717 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace golos { namespace protocol { @@ -13,7 +14,7 @@ namespace golos { namespace protocol { } inline void validate_account_name(const string &name) { - FC_ASSERT(is_valid_account_name(name), "Account name ${n} is invalid", ("n", name)); + GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } inline void validate_account_json_metadata(const string& json_metadata) { @@ -67,21 +68,28 @@ namespace golos { namespace protocol { } void comment_operation::validate() const { - FC_ASSERT(title.size() < 256, "Title larger than size limit"); - FC_ASSERT(fc::is_utf8(title), "Title not formatted in UTF8"); - FC_ASSERT(body.size() > 0, "Body is empty"); - FC_ASSERT(fc::is_utf8(body), "Body not formatted in UTF8"); + GOLOS_CHECK_PARAM(title, { + GOLOS_CHECK_VALUE(title.size() < 256, "Title larger than size limit"); + GOLOS_CHECK_VALUE(fc::is_utf8(title), "Title not formatted in UTF8"); + }); + GOLOS_CHECK_PARAM(body, { + GOLOS_CHECK_VALUE(body.size() > 0, "Body is empty"); + GOLOS_CHECK_VALUE(fc::is_utf8(body), "Body not formatted in UTF8"); + }); if (parent_author.size()) { - validate_account_name(parent_author); + GOLOS_CHECK_PARAM(parent_author, validate_account_name(parent_author)); } - validate_account_name(author); - validate_permlink(parent_permlink); - validate_permlink(permlink); + + GOLOS_CHECK_PARAM(author, validate_account_name(author)); + GOLOS_CHECK_PARAM(parent_permlink, validate_permlink(parent_permlink)); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); if (json_metadata.size() > 0) { - FC_ASSERT(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); + GOLOS_CHECK_PARAM(json_metadata, { + GOLOS_CHECK_VALUE(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); + }); } } diff --git a/plugins/json_rpc/CMakeLists.txt b/plugins/json_rpc/CMakeLists.txt index 99e491fd15..9f9560e2d9 100644 --- a/plugins/json_rpc/CMakeLists.txt +++ b/plugins/json_rpc/CMakeLists.txt @@ -23,7 +23,7 @@ endif() add_library(golos::${CURRENT_TARGET} ALIAS golos_${CURRENT_TARGET}) set_property(TARGET golos_${CURRENT_TARGET} PROPERTY EXPORT_NAME ${CURRENT_TARGET}) -target_link_libraries(golos_${CURRENT_TARGET} appbase fc) +target_link_libraries(golos_${CURRENT_TARGET} golos_protocol appbase fc) target_include_directories(golos_${CURRENT_TARGET} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../") diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp index 6c371cb485..6b15079faf 100644 --- a/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp @@ -52,6 +52,10 @@ #define JSON_RPC_NO_PARAMS (-32001) #define JSON_RPC_PARSE_PARAMS_ERROR (-32002) #define JSON_RPC_ERROR_DURING_CALL (-32003) +#define JSON_RPC_INSUFFICIENT_FUNDS (-32004) +#define JSON_RPC_MISSING_AUTHORITY (-32005) +#define JSON_RPC_MISSING_OBJECT (-32006) +#define JSON_RPC_LOGIC_ERROR (-32007) namespace golos { namespace plugins { @@ -143,4 +147,4 @@ namespace golos { } } // steem::plugins::json_rpc -FC_REFLECT((golos::plugins::json_rpc::api_method_signature), (args)(ret)) \ No newline at end of file +FC_REFLECT((golos::plugins::json_rpc::api_method_signature), (args)(ret)) diff --git a/plugins/json_rpc/plugin.cpp b/plugins/json_rpc/plugin.cpp index 6900666ef8..71cef9e8d0 100644 --- a/plugins/json_rpc/plugin.cpp +++ b/plugins/json_rpc/plugin.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include @@ -285,6 +287,16 @@ namespace golos { try { rpc_jsonrpc(data.get_object(), msg); + + } catch (const golos::insufficient_funds& e) { + msg.error(JSON_RPC_INSUFFICIENT_FUNDS, e); + } catch (const golos::protocol::tx_missing_authority& e) { + msg.error(JSON_RPC_MISSING_AUTHORITY, e); + } catch (const golos::missing_object& e) { + msg.error(JSON_RPC_MISSING_OBJECT, e); + } catch (const golos::logic_exception& e) { + msg.error(JSON_RPC_LOGIC_ERROR, e); + } catch (const fc::parse_error_exception& e) { msg.error(JSON_RPC_INVALID_PARAMS, e); dump.error("invalid params"); diff --git a/plugins/market_history/market_history_plugin.cpp b/plugins/market_history/market_history_plugin.cpp index fc3e60447d..5c19b92099 100644 --- a/plugins/market_history/market_history_plugin.cpp +++ b/plugins/market_history/market_history_plugin.cpp @@ -5,10 +5,28 @@ #include #include +#include + #define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); + FC_ASSERT( args.args->size() == s, "Expected "#s" argument(s), was ${n}", ("n", args.args->size()) ); + +#define GOLOS_CHECK_LIMIT(limit, max_value) \ + GOLOS_ASSERT( limit <= max_value, golos::limit_too_large, "Exceeded limit value. Maximum allowed ${max}", \ + ("limit",limit)("max",max_value)) + +#define GOLOS_DECLARE_PARAM(PARAM, GETTER) auto (PARAM) = [&]() {\ + try {return (GETTER);} \ + catch (const fc::exception &e) { \ + FC_THROW_EXCEPTION(golos::invalid_parameter, \ + "Invalid parameter \"${name}\": ${reason}", \ + ("param", BOOST_PP_STRINGIZE(PARAM)) \ + ("errmsg", e.to_string()) \ + ("error", e) \ + ); \ + } \ +}() namespace golos { @@ -223,7 +241,7 @@ namespace golos { } order_book market_history_plugin::market_history_plugin_impl::get_order_book(uint32_t limit) const { - FC_ASSERT(limit <= 500); + GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, 500)); const auto &order_idx = database().get_index().indices().get(); auto itr = order_idx.lower_bound(price::max(SBD_SYMBOL, STEEM_SYMBOL)); @@ -465,7 +483,7 @@ namespace golos { DEFINE_API(market_history_plugin, get_order_book) { CHECK_ARG_SIZE(1) - auto limit = args.args->at(0).as(); + GOLOS_DECLARE_PARAM(limit, args.args->at(0).as()); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_order_book(limit); @@ -521,10 +539,12 @@ namespace golos { } DEFINE_API(market_history_plugin, get_open_orders) { - auto tmp = args.args->at(0).as(); + CHECK_ARG_SIZE(1); + GOLOS_DECLARE_PARAM(account, args.args->at(0).as()); + //auto tmp = args.args->at(0).as(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { - return _my->get_open_orders(tmp); + return _my->get_open_orders(account); }); } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 3612ab4afc..de54b77f37 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6234,7 +6234,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test specifying a non-existent benefactor"); @@ -6245,7 +6245,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test setting when comment has been voted on"); @@ -6264,7 +6264,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test success"); @@ -6280,7 +6280,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.extensions.clear(); op.extensions.insert(b); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); } FC_LOG_AND_RETHROW() } @@ -6381,7 +6381,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.memo_key = priv_key.get_public_key(); op.json_metadata = "{\"foo\":\"bar\"}"; sign_tx_with_ops(tx, alice_private_key, withdraw, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test success under normal conditions"); push_tx_with_ops(tx, alice_private_key, op); @@ -6611,7 +6611,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegatee = "alice"; op.vesting_shares = asset(max_allowed.amount + 1, VESTS_SYMBOL); sign_tx_with_ops(tx, bob_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); op.vesting_shares = max_allowed; push_tx_with_ops(tx, bob_private_key, op); @@ -6628,12 +6628,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegator = "sam"; op.delegatee = "dave"; sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test failure delegating more vesting shares than account has"); op.vesting_shares = asset(sam_vest.amount + 1, VESTS_SYMBOL); sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test failure delegating vesting shares that are part of a power down"); sam_vest = asset(sam_vest.amount / 2, VESTS_SYMBOL); @@ -6643,7 +6643,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = asset(sam_vest.amount + 2, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, withdraw); sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Test available_vesting_shares calculation with active power down"); BOOST_REQUIRE(sam_acc.available_vesting_shares(true) == @@ -6658,7 +6658,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) withdraw.vesting_shares = asset(sam_vest.amount, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, op); sign_tx_with_ops(tx, sam_private_key, withdraw); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), fc::assert_exception); + STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); BOOST_TEST_MESSAGE("--- Remove a delegation and ensure it is returned after 1 week"); op.vesting_shares = ASSET_GESTS(0); diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index 6b2f50b8a2..126ed65943 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop3.author = cop.author; uop3.title = cop.title; uop3.key_approvals_to_add.insert(dave_public_key); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, dave_private_key, uop3), tx_irrelevant_sig); + BOOST_REQUIRE_THROW(push_tx_with_ops(tx, dave_private_key, uop3), tx_invalid_operation); // TODO tx_invalid_operation -> tx_irrelevant_sig proposal_update_operation uop4; uop4.author = cop.author; From 16ab84c4c4527a4c93e81d024f61f5f9f9bb9736 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 10 Jul 2018 12:54:15 +0700 Subject: [PATCH 047/250] Write base classes and macros for write test-cases with error checks #786 --- .../include/golos/chain/steem_evaluator.hpp | 4 +- libraries/chain/steem_evaluator.cpp | 41 +--- .../include/golos/protocol/exceptions.hpp | 117 ++++++--- libraries/protocol/proposal_operations.cpp | 4 +- libraries/protocol/steem_operations.cpp | 20 +- .../market_history/market_history_plugin.cpp | 33 +-- tests/common/database_fixture.cpp | 41 ++++ tests/common/database_fixture.hpp | 185 ++++++++++++-- tests/tests/operation_tests.cpp | 231 +++++++++++------- 9 files changed, 463 insertions(+), 213 deletions(-) diff --git a/libraries/chain/include/golos/chain/steem_evaluator.hpp b/libraries/chain/include/golos/chain/steem_evaluator.hpp index 8a698df583..0522ef2552 100644 --- a/libraries/chain/include/golos/chain/steem_evaluator.hpp +++ b/libraries/chain/include/golos/chain/steem_evaluator.hpp @@ -5,7 +5,9 @@ #include #define ASSERT_REQ_HF(HF, FEATURE) \ - FC_ASSERT(db().has_hardfork(HF), FEATURE " is not enabled until HF " BOOST_PP_STRINGIZE(HF)); + GOLOS_ASSERT(db().has_hardfork(HF), unsupported_operation, \ + "${feature} is not enabled until HF ${hardfork}", \ + ("feature",FEATURE)("hardfork",BOOST_PP_STRINGIZE(HF))); namespace golos { namespace chain { using namespace golos::protocol; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 8feb0a2aba..305dbf3342 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -21,19 +21,6 @@ std::string wstring_to_utf8(const std::wstring &str) { #endif -#define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) \ - FC_MULTILINE_MACRO_BEGIN \ - try { \ - VALIDATOR; \ - } catch (const fc::exception& e) { \ - FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for operation parameter \"${param}\": ${errmsg}", \ - ("param", FC_STRINGIZE(PARAM)) \ - ("value", OP.PARAM) \ - ("errmsg", e.to_string()) \ - ("error", e)); \ - } \ - FC_MULTILINE_MACRO_END - #define GOLOS_CHECK_BALANCE( ACCOUNT, TYPE, REQUIRED ...) \ FC_EXPAND_MACRO( \ FC_MULTILINE_MACRO_BEGIN \ @@ -41,20 +28,14 @@ std::string wstring_to_utf8(const std::wstring &str) { if( UNLIKELY( exist < (REQUIRED) )) { \ FC_THROW_EXCEPTION( golos::insufficient_funds, \ "Account \"${account}\" does not have enough ${balance}: exist ${exist}, required ${required}", \ - ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("exist",exist)("required",REQUIRED)); \ + ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("required",REQUIRED)); \ } \ FC_MULTILINE_MACRO_END \ ) -#define GOLOS_CHECK_BANDWIDTH(COND, TYPE, MSG, ...) \ - GOLOS_ASSERT((COND), golos::bandwidth_exception, MSG, ("bandwidth",TYPE) __VA_ARGS__) - -#define GOLOS_CHECK_LOGIC(expr, TYPE, FORMAT, ...) \ - if (!(expr)) { \ - golos::logic_exception _E(FC_LOG_MESSAGE(error, FORMAT, ("err_id",TYPE)__VA_ARGS__)); \ - _E.err_id = TYPE; \ - throw _E; \ - } +#define GOLOS_CHECK_BANDWIDTH(NOW, NEXT, TYPE, MSG, ...) \ + GOLOS_ASSERT((NOW) > (NEXT), golos::bandwidth_exception, MSG, \ + ("bandwidth",TYPE)("now",NOW)("next",NEXT) __VA_ARGS__) namespace golos { namespace chain { using fc::uint128_t; @@ -610,19 +591,13 @@ namespace golos { namespace chain { if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__176)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) - GOLOS_CHECK_BANDWIDTH((now - band->last_bandwidth_update) > STEEMIT_MIN_ROOT_COMMENT_INTERVAL, + GOLOS_CHECK_BANDWIDTH(now, band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, golos::bandwidth_exception::post_bandwidth, - "You may only post once every 5 minutes.", - ("now", now) - ("last", band->last_bandwidth_update) - ("next", band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL)); + "You may only post once every 5 minutes."); else - GOLOS_CHECK_BANDWIDTH((now - auth.last_post) > STEEMIT_MIN_REPLY_INTERVAL, + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, golos::bandwidth_exception::comment_bandwidth, - "You may only comment once every 20 seconds.", - ("now", now) - ("last", auth.last_post) - ("next", auth.last_post + STEEMIT_MIN_REPLY_INTERVAL)); + "You may only comment once every 20 seconds."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_6__113)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) FC_ASSERT((now - auth.last_post) > diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 06318e21d8..a788e70caa 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -52,48 +52,97 @@ GOLOS_DECLARE_DERIVED_EXCEPTION_BODY(TYPE, BASE, CODE, WHAT) \ }; +#define GOLOS_CHECK_LOGIC(expr, TYPE, MSG, ...) \ + GOLOS_ASSERT(expr, golos::logic_exception, MSG, ("errid", TYPE)__VA_ARGS__) + +#define GOLOS_DECLARE_PARAM(PARAM, GETTER) auto (PARAM) = [&]() {\ + try {return (GETTER);} \ + catch (const fc::exception &e) { \ + FC_THROW_EXCEPTION(golos::invalid_parameter, \ + "Invalid parameter \"${name}\": ${reason}", \ + ("param", BOOST_PP_STRINGIZE(PARAM)) \ + ("errmsg", e.to_string()) \ + ("error", e) \ + ); \ + } \ +}() + #define GOLOS_CHECK_PARAM(PARAM, VALIDATOR) \ FC_MULTILINE_MACRO_BEGIN \ try { \ VALIDATOR; \ - } catch (const fc::exception& e) { \ + } catch (const golos::invalid_value& e) { \ FC_THROW_EXCEPTION(golos::invalid_parameter, "Invalid value \"${value}\" for parameter \"${param}\": ${errmsg}", \ ("param", FC_STRINGIZE(PARAM)) \ ("value", PARAM) \ ("errmsg", e.to_string()) \ - ("error", e)); \ + ("error", static_cast(e))); \ + } \ + FC_MULTILINE_MACRO_END + +#define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) \ + FC_MULTILINE_MACRO_BEGIN \ + try { \ + VALIDATOR; \ + } catch (const golos::invalid_value& e) { \ + FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for operation parameter \"${param}\": ${errmsg}", \ + ("param", FC_STRINGIZE(PARAM)) \ + ("value", OP.PARAM) \ + ("errmsg", e.to_string()) \ + ("error", static_cast(e))); \ } \ FC_MULTILINE_MACRO_END #define GOLOS_CHECK_VALUE(COND, MSG, ...) \ GOLOS_ASSERT((COND), golos::invalid_value, MSG, __VA_ARGS__) +#define GOLOS_CHECK_LIMIT(limit, max_value) \ + GOLOS_ASSERT( limit <= max_value, golos::limit_too_large, "Exceeded limit value. Maximum allowed ${max}", \ + ("limit",limit)("max",max_value)) + +#define GOLOS_CHECK_ARGS_COUNT(args, required) \ + GOLOS_ASSERT( (args)->size() == (required), invalid_arguments_count, \ + "Expected ${required} argument(s), was ${count}", \ + ("count", (args)->size())("required", required) ); + +#define GOLOS_CHECK_OPT_ARGS_COUNT(args, min, max) \ + GOLOS_ASSERT( (args)->size() >= (min) && (args)->size() <= max, invalid_arguments_count, \ + "Expected ${min}..${max} argument(s), was ${count}", \ + ("count", (args)->size())("min", min)("max", max) ); + namespace golos { GOLOS_DECLARE_DERIVED_EXCEPTION( golos_exception, fc::exception, - 300000, "golos base exception") + 0, "golos base exception") + + GOLOS_DECLARE_DERIVED_EXCEPTION( + operation_exception, golos_exception, + 1000000, "Opertaion exception"); + GOLOS_DECLARE_DERIVED_EXCEPTION( + unsupported_operation, operation_exception, + 1010000, "Unsupported operation"); GOLOS_DECLARE_DERIVED_EXCEPTION( - insufficient_funds, golos_exception, - 300001, "Account does not have sufficient funds") + invalid_arguments_count, operation_exception, + 1020000, "Invalid argument count"); GOLOS_DECLARE_DERIVED_EXCEPTION( - missing_object, golos_exception, - 300002, "Missing object"); + missing_object, operation_exception, + 1030000, "Missing object"); GOLOS_DECLARE_DERIVED_EXCEPTION( - invalid_parameter, golos_exception, - 300004, "Invalid parameter value"); + invalid_parameter, operation_exception, + 1040000, "Invalid parameter value"); GOLOS_DECLARE_DERIVED_EXCEPTION( - limit_too_large, invalid_parameter, - 300003, "Exceeded limit value"); + business_exception, golos_exception, + 2000000, "Business logic error"); - class bandwidth_exception : public golos_exception { + class bandwidth_exception : public business_exception { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - bandwidth_exception, golos_exception, - 400001, "bandwidth exceeded error"); + bandwidth_exception, business_exception, + 2010000, "bandwidth exceeded error"); public: enum bandwidth_types { post_bandwidth, @@ -101,48 +150,58 @@ namespace golos { }; }; - class logic_exception : public golos_exception { + GOLOS_DECLARE_DERIVED_EXCEPTION( + insufficient_funds, business_exception, + 2020000, "Account does not have sufficient funds") + + class logic_exception : public business_exception { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( - logic_exception, golos_exception, - 400000, "business logic error"); + logic_exception, business_exception, + 2030000, "business logic error"); public: enum error_types { reached_limit_for_pending_withdraw_requests = 1, parent_of_comment_cannot_change, parent_perlink_of_comment_cannot_change, }; - - error_types err_id; }; GOLOS_DECLARE_DERIVED_EXCEPTION( internal_error, golos_exception, - 300005, "internal error"); + 4000000, "internal error"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + assert_exception, internal_error, + 4010000, "assert exception"); GOLOS_DECLARE_DERIVED_EXCEPTION( invalid_value, internal_error, - 300006, "invalid value exception"); + 4020000, "invalid value exception"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + limit_too_large, invalid_value, + 4020100, "Exceeded limit value"); } // golos namespace golos { namespace protocol { GOLOS_DECLARE_DERIVED_EXCEPTION( - transaction_exception, fc::exception, + transaction_exception, golos_exception, 3000000, "transaction exception") GOLOS_DECLARE_DERIVED_EXCEPTION( tx_invalid_operation, transaction_exception, - 3000001, "invalid operation in transaction"); + 3010000, "invalid operation in transaction"); GOLOS_DECLARE_DERIVED_EXCEPTION( tx_missing_authority, transaction_exception, - 3010099, "missing authority"); + 3020000, "missing authority"); class tx_missing_active_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( tx_missing_active_auth, tx_missing_authority, - 3010000, "missing required active authority"); + 3020100, "missing required active authority"); public: std::vector missing_accounts; std::vector used_signatures; @@ -151,7 +210,7 @@ namespace golos { namespace protocol { class tx_missing_owner_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( tx_missing_owner_auth, tx_missing_authority, - 3020000, "missing required owner authority"); + 3020200, "missing required owner authority"); public: std::vector missing_accounts; std::vector used_signatures; @@ -160,7 +219,7 @@ namespace golos { namespace protocol { class tx_missing_posting_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( tx_missing_posting_auth, tx_missing_authority, - 3030000, "missing required posting authority"); + 3020300, "missing required posting authority"); public: std::vector missing_accounts; std::vector used_signatures; @@ -169,7 +228,7 @@ namespace golos { namespace protocol { class tx_missing_other_auth: public tx_missing_authority { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( tx_missing_other_auth, tx_missing_authority, - 3040000, "missing required other authority"); + 3020400, "missing required other authority"); public: std::vector missing_auths; }; @@ -177,7 +236,7 @@ namespace golos { namespace protocol { class tx_irrelevant_sig: public transaction_exception { GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( tx_irrelevant_sig, transaction_exception, - 3050000, "irrelevant signature included"); + 3030000, "irrelevant signature included"); public: std::vector unused_signatures; }; diff --git a/libraries/protocol/proposal_operations.cpp b/libraries/protocol/proposal_operations.cpp index 35c0378dc9..3dccb4d0de 100644 --- a/libraries/protocol/proposal_operations.cpp +++ b/libraries/protocol/proposal_operations.cpp @@ -8,7 +8,7 @@ namespace golos { namespace protocol { - inline void validate_account_name(const string& name) { + static inline void validate_account_name(const string& name) { FC_ASSERT(is_valid_account_name(name), "Account name ${n} is invalid", ("n", name)); } @@ -92,4 +92,4 @@ namespace golos { namespace protocol { FC_ASSERT(fc::is_utf8(title), "Title not formatted in UTF8"); } -} } // golos::chain \ No newline at end of file +} } // golos::chain diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index baddba5717..e912ab98b0 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -13,7 +13,7 @@ namespace golos { namespace protocol { FC_ASSERT(fc::is_utf8(permlink), "permlink not formatted in UTF8"); } - inline void validate_account_name(const string &name) { + static inline void validate_account_name(const string &name) { GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } @@ -529,13 +529,17 @@ namespace golos { namespace protocol { } void transfer_to_savings_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - FC_ASSERT(amount.amount > 0); - FC_ASSERT(amount.symbol == STEEM_SYMBOL || - amount.symbol == SBD_SYMBOL); - FC_ASSERT(memo.size() < STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); - FC_ASSERT(fc::is_utf8(memo), "Memo is not UTF8"); + GOLOS_CHECK_PARAM(from, validate_account_name(from)); + GOLOS_CHECK_PARAM(to, validate_account_name(to)); + GOLOS_CHECK_PARAM(amount, { + GOLOS_CHECK_VALUE(amount.amount > 0, "Amount must be positive"); + GOLOS_CHECK_VALUE(amount.symbol == STEEM_SYMBOL || + amount.symbol == SBD_SYMBOL, "Available currency GOLOS or GBG"); + }); + GOLOS_CHECK_PARAM(memo, { + GOLOS_CHECK_VALUE(memo.size() < STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); + GOLOS_CHECK_VALUE(fc::is_utf8(memo), "Memo is not UTF8"); + }); } void transfer_from_savings_operation::validate() const { diff --git a/plugins/market_history/market_history_plugin.cpp b/plugins/market_history/market_history_plugin.cpp index 5c19b92099..7ec0401d17 100644 --- a/plugins/market_history/market_history_plugin.cpp +++ b/plugins/market_history/market_history_plugin.cpp @@ -8,27 +8,6 @@ #include - -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected "#s" argument(s), was ${n}", ("n", args.args->size()) ); - -#define GOLOS_CHECK_LIMIT(limit, max_value) \ - GOLOS_ASSERT( limit <= max_value, golos::limit_too_large, "Exceeded limit value. Maximum allowed ${max}", \ - ("limit",limit)("max",max_value)) - -#define GOLOS_DECLARE_PARAM(PARAM, GETTER) auto (PARAM) = [&]() {\ - try {return (GETTER);} \ - catch (const fc::exception &e) { \ - FC_THROW_EXCEPTION(golos::invalid_parameter, \ - "Invalid parameter \"${name}\": ${reason}", \ - ("param", BOOST_PP_STRINGIZE(PARAM)) \ - ("errmsg", e.to_string()) \ - ("error", e) \ - ); \ - } \ -}() - - namespace golos { namespace plugins { namespace market_history { @@ -482,7 +461,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_order_book) { - CHECK_ARG_SIZE(1) + GOLOS_CHECK_ARGS_COUNT(args.args, 1); GOLOS_DECLARE_PARAM(limit, args.args->at(0).as()); auto &db = _my->database(); return db.with_weak_read_lock([&]() { @@ -491,7 +470,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_order_book_extended) { - CHECK_ARG_SIZE(1) + GOLOS_CHECK_ARGS_COUNT(args.args, 1); auto limit = args.args->at(0).as(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { @@ -501,7 +480,7 @@ namespace golos { DEFINE_API(market_history_plugin, get_trade_history) { - CHECK_ARG_SIZE(3) + GOLOS_CHECK_ARGS_COUNT(args.args, 3); auto start = args.args->at(0).as(); auto end = args.args->at(1).as(); auto limit = args.args->at(2).as(); @@ -512,7 +491,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_recent_trades) { - CHECK_ARG_SIZE(1) + GOLOS_CHECK_ARGS_COUNT(args.args, 1); auto limit = args.args->at(0).as(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { @@ -521,7 +500,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_market_history) { - CHECK_ARG_SIZE(3) + GOLOS_CHECK_ARGS_COUNT(args.args, 3); auto bucket_seconds = args.args->at(0).as(); auto start = args.args->at(1).as(); auto end = args.args->at(2).as(); @@ -539,7 +518,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_open_orders) { - CHECK_ARG_SIZE(1); + GOLOS_CHECK_ARGS_COUNT(args.args, 1); GOLOS_DECLARE_PARAM(account, args.args->at(0).as()); //auto tmp = args.args->at(0).as(); auto &db = _my->database(); diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index b449a60313..265cc28941 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -18,6 +18,47 @@ uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP = 1431700000; + +namespace fc { + +std::ostream& operator<<(std::ostream& out, const fc::exception& e) { + out << e.to_detail_string(); + return out; +} + +std::ostream& operator<<(std::ostream& out, const fc::time_point& v) { + out << static_cast(v); + return out; +} + +std::ostream& operator<<(std::ostream& out, const fc::uint128_t v) { + out << static_cast(v); + return out; +} + +std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v) { + out << static_cast(v); + return out; +} + +std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v) { + out << static_cast(v); + return out; +} + +} // namespace fc + + +namespace golos { namespace protocol { + +std::ostream& operator<<(std::ostream& out, const asset& v) { + out << v.to_string(); + return out; +} + +} } // namespace golos::protocol + + namespace golos { namespace chain { using std::cout; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 63250babf5..acdd18699f 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -80,27 +82,152 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); << req_throw_info << std::endl; \ } -#define REQUIRE_OP_VALIDATION_FAILURE_2(op, field, value, exc_type) \ -{ \ - const auto temp = op.field; \ - op.field = value; \ - STEEMIT_REQUIRE_THROW( op.validate(), exc_type ); \ - op.field = temp; \ -} -#define REQUIRE_OP_VALIDATION_FAILURE(op, field, value) \ - REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, fc::exception ) - -#define REQUIRE_THROW_WITH_VALUE_2(op, field, value, exc_type) \ -{ \ - auto bak = op.field; \ - op.field = value; \ - trx.operations.back() = op; \ - op.field = bak; \ - STEEMIT_REQUIRE_THROW(db.push_transaction(trx, ~0), exc_type); \ -} +#define GOLOS_CHECK_THROW_PROPS_IMPL( S, E, C, TL ) \ + try { \ + BOOST_TEST_PASSPOINT(); \ + S; \ + BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected", TL, CHECK_MSG ); } \ + catch( E const& ex ) { \ + ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ + BOOST_CHECK_IMPL( true, "exception '" BOOST_STRINGIZE( E ) "' is caught", TL, CHECK_MSG ); \ + const fc::variant_object &props = ex.get_log().at(0).get_data(); \ + try { \ + C; \ + } catch (const fc::exception& err) { \ + BOOST_CHECK_IMPL( false, "caught exception '" << err.name() << "' while check props:" << \ + err.to_detail_string(), TL, CHECK_MSG); \ + } \ + } catch ( ... ) { \ + try { \ + throw; \ + } catch (const fc::exception& ex) { \ + BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ + "but '" << ex.name() << "' is caught", TL, CHECK_MSG); \ + } catch (...) { \ + BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) " is expected, " \ + "but unknown is caught", TL, CHECK_MSG); \ + } \ + } \ + +#define GOLOS_WARN_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, WARN) +#define GOLOS_CHECK_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, CHECK) +#define GOLOS_REQUIRE_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, REQUIRE) + +template +struct ErrorValidator {}; + +typedef void (*ErrorValidateFunc)(const std::string&, const fc::variant& props); + +#define CHECK_ERROR(exception, ...) [&](const std::string& name, const fc::variant& props) \ + {\ + ErrorValidator v; \ + v.validate(name, props, __VA_ARGS__); \ + } + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + const std::string& param) { + BOOST_CHECK_EQUAL(name, "invalid_parameter"); + BOOST_CHECK_EQUAL(props["param"].get_string(), param); + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + const std::string& account, const std::string& balance, const std::string& amount) { + BOOST_CHECK_EQUAL(name, "insufficient_funds"); + BOOST_CHECK_EQUAL(props["account"].get_string(), account); + BOOST_CHECK_EQUAL(props["balance"].get_string(), balance); + BOOST_CHECK_EQUAL(props["required"].get_string(), amount); + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + int index, ErrorValidateFunc validator = NULL) { + BOOST_CHECK_EQUAL(name, "tx_invalid_operation"); + BOOST_CHECK_EQUAL(props["index"].as_uint64(), index); + if(validator) { + validator(props["error"]["name"].get_string(), props["error"]["stack"][(size_t)0]["data"]); + } + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + const std::string& type, const std::string& id) { + BOOST_CHECK_EQUAL(name, "missing_object"); + BOOST_CHECK_EQUAL(props["type"].get_string(), type); + BOOST_CHECK_EQUAL(props["id"].get_string(), id); + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + golos::logic_exception::error_types err) { + BOOST_CHECK_EQUAL(name, "logic_exception"); + BOOST_CHECK_EQUAL(props["errid"].get_string(), + fc::reflector::to_string(err)); + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + golos::bandwidth_exception::bandwidth_types type) { + BOOST_CHECK_EQUAL(name, "bandwidth_exception"); + BOOST_CHECK_EQUAL(props["bandwidth"].get_string(), + fc::reflector::to_string(type)); + BOOST_CHECK_NO_THROW(props["now"].get_string()); + BOOST_CHECK_NO_THROW(props["next"].get_string()); + } +}; + + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_irrelevant_sig"); + } +}; + +#define GOLOS_CHECK_ERROR_PROPS_IMPL( S, E, C, TL ) \ + try { \ + BOOST_TEST_PASSPOINT(); \ + S; \ + BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected", TL, CHECK_MSG ); } \ + catch( E const& ex ) { \ + ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ + BOOST_CHECK_IMPL( true, "exception '" BOOST_STRINGIZE( E ) "' is caught", TL, CHECK_MSG ); \ + const std::string name = ex.name(); \ + const fc::variant_object &props = ex.get_log().at(0).get_data(); \ + try { \ + C(name, props); \ + } catch (const fc::exception& err) { \ + BOOST_CHECK_IMPL( false, "caught exception '" << err.name() << "' while check props:" << \ + err.to_detail_string(), TL, CHECK_MSG); \ + } \ + } catch ( ... ) { \ + try { \ + throw; \ + } catch (const fc::exception& ex) { \ + BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ + "but '" << ex.name() << "' is caught", TL, CHECK_MSG); \ + } catch (...) { \ + BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) " is expected, " \ + "but unknown is caught", TL, CHECK_MSG); \ + } \ + } \ + +#define GOLOS_WARN_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, WARN) +#define GOLOS_CHECK_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, CHECK) +#define GOLOS_REQUIRE_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, REQUIRE) -#define REQUIRE_THROW_WITH_VALUE(op, field, value) \ - REQUIRE_THROW_WITH_VALUE_2( op, field, value, fc::exception ) ///This simply resets v back to its default-constructed value. Requires v to have a working assingment operator and /// default constructor. @@ -146,6 +273,24 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); ) +namespace fc { + +std::ostream& operator<<(std::ostream& out, const fc::exception& e); +std::ostream& operator<<(std::ostream& out, const fc::time_point& v); +std::ostream& operator<<(std::ostream& out, const fc::uint128_t v); +std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v); +std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v); + +} // namespace fc + + +namespace golos { namespace protocol { + +std::ostream& operator<<(std::ostream& out, const asset& v); + +} } // namespace golos::protocol + + #ifndef STEEMIT_INIT_PRIVATE_KEY # define STEEMIT_INIT_PRIVATE_KEY (fc::ecc::private_key::regenerate(fc::sha256::hash(BLOCKCHAIN_NAME))) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index de54b77f37..19302570c1 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -25,6 +25,7 @@ using namespace golos::chain; using namespace golos::protocol; using std::string; + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_validate) { @@ -587,7 +588,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(bandwidth_exception, golos::bandwidth_exception::comment_bandwidth))); validate_database(); @@ -5288,34 +5291,50 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("failure when 'from' is empty"); op.from = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "from")); BOOST_TEST_MESSAGE("failure when 'to' is empty"); op.from = "alice"; op.to = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "to")); BOOST_TEST_MESSAGE("sucess when 'to' is not empty"); op.to = "bob"; - op.validate(); + BOOST_CHECK_NO_THROW(op.validate()); BOOST_TEST_MESSAGE("failure when amount is VESTS"); op.to = "alice"; op.amount = ASSET("1.000 VESTS"); - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "amount")); BOOST_TEST_MESSAGE("success when amount is SBD"); op.amount = ASSET("1.000 GBG"); - op.validate(); + BOOST_CHECK_NO_THROW(op.validate()); BOOST_TEST_MESSAGE("success when amount is STEEM"); op.amount = ASSET("1.000 GOLOS"); - op.validate(); + BOOST_CHECK_NO_THROW(op.validate()); + + + BOOST_TEST_MESSAGE("failure when amount is negative"); + op.memo = std::string(); + op.amount = ASSET("-1.000 GOLOS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "amount")); + + + BOOST_TEST_MESSAGE("failure when memo too large"); + op.memo = string(STEEMIT_MAX_MEMO_SIZE, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "memo")); } FC_LOG_AND_RETHROW() } @@ -5362,8 +5381,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) fund("alice", ASSET("10.000 GOLOS")); fund("alice", ASSET("10.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("10.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("10.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("10.000 GBG")); transfer_to_savings_operation op; signed_transaction tx; @@ -5376,7 +5395,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "20.000 GOLOS"))); validate_database(); @@ -5387,7 +5408,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "sam"))); validate_database(); @@ -5397,10 +5420,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("9.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_balance == ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("1.000 GOLOS")); validate_database(); @@ -5410,10 +5433,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("9.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_sbd_balance == ASSET("1.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("9.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("1.000 GBG")); validate_database(); @@ -5424,10 +5447,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("8.000 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").savings_balance == ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("8.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_balance, ASSET("1.000 GOLOS")); validate_database(); @@ -5437,10 +5460,23 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("8.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_sbd_balance, ASSET("1.000 GBG")); + validate_database(); + + + + BOOST_TEST_MESSAGE("--- failure when transferring without authorities"); + op.from = "bob"; + op.to = "alice"; + op.amount = ASSET("1.000 GOLOS"); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("8.000 GBG")); - BOOST_REQUIRE(db->get_account("bob").savings_sbd_balance == ASSET("1.000 GBG")); + tx.clear(); + tx.operations.push_back(op); + tx.sign(alice_private_key, db->get_chain_id()); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), tx_missing_active_auth, {}); validate_database(); } FC_LOG_AND_RETHROW() @@ -5542,13 +5578,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(save); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); save.amount = ASSET("10.000 GBG"); tx.clear(); tx.operations.push_back(save); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- failure when account has insufficient funds"); @@ -5561,7 +5597,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "savings", "20.000 GOLOS"))); BOOST_TEST_MESSAGE("--- failure withdrawing to non-existant account"); @@ -5571,7 +5609,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "sam"))); BOOST_TEST_MESSAGE("--- success withdrawing GOLOS to self"); @@ -5580,17 +5620,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_balance == ASSET("9.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 1); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).from == op.from); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).to == op.to); - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).request_id == op.request_id); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).amount == op.amount); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).complete == db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("9.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 1); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).from, op.from); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).to, op.to); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).request_id, op.request_id); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).amount, op.amount); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); @@ -5601,17 +5641,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_sbd_balance == ASSET("9.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 2); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).from == op.from); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).to == op.to); - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).request_id == op.request_id); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).amount == op.amount); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).complete == db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("9.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 2); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).from, op.from); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).to, op.to); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).request_id, op.request_id); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).amount, op.amount); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); @@ -5621,6 +5661,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); + + // TODO try to add dublicate transaction throws logic_error STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); @@ -5632,17 +5674,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_balance == ASSET("8.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 3); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).from == op.from); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).to == op.to); - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).request_id == op.request_id); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).amount == op.amount); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).complete == db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("8.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 3); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).from, op.from); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).to, op.to); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).request_id, op.request_id); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).amount, op.amount); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); @@ -5653,37 +5695,37 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_sbd_balance == ASSET("8.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 4); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).from == op.from); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).to == op.to); - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).request_id == op.request_id); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).amount == op.amount); - BOOST_REQUIRE(db->get_savings_withdraw("alice", op.request_id).complete == db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("8.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 4); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).from, op.from); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).to, op.to); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).request_id, op.request_id); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).amount, op.amount); + BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); BOOST_TEST_MESSAGE("--- withdraw on timeout"); generate_blocks(db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 4); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 4); validate_database(); generate_block(); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").sbd_balance == ASSET("1.000 GBG")); - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").sbd_balance == ASSET("1.000 GBG")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 0); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("1.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").sbd_balance, ASSET("1.000 GBG")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 0); validate_database(); @@ -5698,15 +5740,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); db->push_transaction(tx, 0); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == i + 1); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, i + 1); } op.request_id = STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT; tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, golos::logic_exception::reached_limit_for_pending_withdraw_requests))); + + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT); validate_database(); } FC_LOG_AND_RETHROW() @@ -6234,7 +6279,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test specifying a non-existent benefactor"); @@ -6245,7 +6290,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test setting when comment has been voted on"); @@ -6264,7 +6309,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test success"); @@ -6280,7 +6325,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.extensions.clear(); op.extensions.insert(b); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), fc::assert_exception, {}); } FC_LOG_AND_RETHROW() } @@ -6381,7 +6426,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.memo_key = priv_key.get_public_key(); op.json_metadata = "{\"foo\":\"bar\"}"; sign_tx_with_ops(tx, alice_private_key, withdraw, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test success under normal conditions"); push_tx_with_ops(tx, alice_private_key, op); @@ -6440,14 +6485,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegation = ASSET_GESTS(0); op.new_account_name = "dave"; sign_tx_with_ops(tx, alice_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), fc::exception, {}); BOOST_TEST_MESSAGE("--- Test failure when insufficient fee to reach target delegation"); fund("alice", required_fee); op.fee = ASSET_GOLOS(0); op.delegation = required_gests - ASSET_GESTS(1); sign_tx_with_ops(tx, alice_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), fc::exception, {}); validate_database(); BOOST_TEST_MESSAGE("--- Test removing delegation from new account"); @@ -6611,7 +6656,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegatee = "alice"; op.vesting_shares = asset(max_allowed.amount + 1, VESTS_SYMBOL); sign_tx_with_ops(tx, bob_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); op.vesting_shares = max_allowed; push_tx_with_ops(tx, bob_private_key, op); @@ -6628,12 +6673,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegator = "sam"; op.delegatee = "dave"; sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test failure delegating more vesting shares than account has"); op.vesting_shares = asset(sam_vest.amount + 1, VESTS_SYMBOL); sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test failure delegating vesting shares that are part of a power down"); sam_vest = asset(sam_vest.amount / 2, VESTS_SYMBOL); @@ -6643,7 +6688,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = asset(sam_vest.amount + 2, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, withdraw); sign_tx_with_ops(tx, sam_private_key, op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test available_vesting_shares calculation with active power down"); BOOST_REQUIRE(sam_acc.available_vesting_shares(true) == @@ -6658,7 +6703,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) withdraw.vesting_shares = asset(sam_vest.amount, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, op); sign_tx_with_ops(tx, sam_private_key, withdraw); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx), tx_invalid_operation); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Remove a delegation and ensure it is returned after 1 week"); op.vesting_shares = ASSET_GESTS(0); @@ -6695,7 +6740,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure when bad account name passed"); op.account = "-bad-"; op.json_metadata = "{}"; - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + STEEMIT_REQUIRE_THROW(op.validate(), invalid_value); BOOST_TEST_MESSAGE("--- Test failure when json_metadata is empty"); op.account = "alice"; From 295dc2fde71dbe1d7147a1c2c478c62402a7c961 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 11 Jul 2018 12:47:05 +0300 Subject: [PATCH 048/250] Added comment_content stroing depth logic. #796 --- .../plugins/social_network/social_network.hpp | 7 +- plugins/social_network/social_network.cpp | 142 ++++++++++++------ plugins/tags/plugin.cpp | 2 +- 3 files changed, 104 insertions(+), 47 deletions(-) diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 87a30a95b1..e84046b7f8 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -89,18 +89,23 @@ namespace golos { namespace plugins { namespace social_network { shared_string title; shared_string body; shared_string json_metadata; + + uint32_t block_number; }; using comment_content_id_type = object_id; struct by_comment; + struct by_block_number; typedef multi_index_container< comment_content_object, indexed_by< ordered_unique, member>, - ordered_unique, member>>, + ordered_unique, member>, + ordered_unique, member> + >, // TODO fix code style!! allocator > comment_content_index; diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 08f01995e7..fa2740fb48 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -36,6 +36,28 @@ # define DEFAULT_VOTE_LIMIT 10000 #endif + +// Depth of comment_content information storage history. +struct content_depth_params { + content_depth_params() { + } + + inline bool miss_content() const { + return has_comment_title_depth && has_comment_body_depth && has_comment_json_metadata_depth; + } + + + uint32_t comment_title_depth; + uint32_t comment_body_depth; + uint32_t comment_json_metadata_depth; + + bool has_comment_title_depth = false; + bool has_comment_body_depth = false; + bool has_comment_json_metadata_depth = false; + + bool set_null_after_update = false; +}; + namespace golos { namespace plugins { namespace social_network { using golos::plugins::tags::fill_promoted; using golos::api::discussion_helper; @@ -82,10 +104,8 @@ namespace golos { namespace plugins { namespace social_network { discussion get_content(std::string author, std::string permlink, uint32_t limit) const; discussion get_discussion(const comment_object& c, uint32_t vote_limit) const ; - - void set_comment_title_depth(const uint32_t & value); - void set_comment_body_depth(const uint32_t & value); - void set_comment_json_metadata_depth(const uint32_t & value); + + void set_depth_parameters(const content_depth_params ¶ms); // Removes comment_content data which is not needed anymore void clear_comment_content_info(); @@ -93,19 +113,12 @@ namespace golos { namespace plugins { namespace social_network { // Looks for a comment_operation, fills the comment_content state objects. void post_operation(const operation_notification &o); + void on_block(const signed_block &b); + private: golos::chain::database& database_; std::unique_ptr helper; - - // Depth of comment_content information storage history. - uint32_t comment_title_depth; - uint32_t comment_body_depth; - uint32_t comment_json_metadata_depth; - - // #TODO delete - // bool has_comment_title_depth; - // bool has_comment_body_depth; - // bool has_comment_json_metadata_depth; + content_depth_params depth_parameters; }; @@ -120,24 +133,17 @@ namespace golos { namespace plugins { namespace social_network { helper->select_active_votes(result, total_count, author, permlink, limit); } - void social_network::impl::set_comment_title_depth(const uint32_t & value) { - comment_title_depth = value; - } - void social_network::impl::set_comment_body_depth(const uint32_t & value) { - comment_body_depth = value; - } - void social_network::impl::set_comment_json_metadata_depth(const uint32_t & value) { - comment_json_metadata_depth = value; + void social_network::impl::set_depth_parameters(const content_depth_params ¶ms) { + depth_parameters = params; } struct operation_visitor { golos::chain::database &db; + content_depth_params depth_parameters; - operation_visitor(golos::chain::database &db) : db(db) { + operation_visitor(golos::chain::database &db, const content_depth_params ¶ms) : db(db), depth_parameters(params) { } - // using boost::locale::conv::utf_to_utf; - std::wstring utf8_to_wstring(const std::string &str) const { return utf_to_utf(str.c_str(), str.c_str() + str.size()); } @@ -169,23 +175,30 @@ namespace golos { namespace plugins { namespace social_network { } void operator()(const golos::protocol::comment_operation& o) const { + if (depth_parameters.miss_content()) { + return; + } + const auto& comment = db.get_comment(o.author, o.permlink); if (comment.created != db.head_block_time()) { + printf("edit case\n"); // Edit case db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { if (o.title.size()) { - from_string(con.title, o.title); + if (depth_parameters.has_comment_title_depth) { + from_string(con.title, o.title); + } } if (o.json_metadata.size()) { - if (fc::is_utf8(o.json_metadata)) { + if (depth_parameters.has_comment_json_metadata_depth && fc::is_utf8(o.json_metadata)) { from_string(con.json_metadata, o.json_metadata ); } else { wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); } } - if (o.body.size()) { + if (o.body.size() && depth_parameters.has_comment_body_depth) { try { diff_match_patch dmp; auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); @@ -207,35 +220,49 @@ namespace golos { namespace plugins { namespace social_network { from_string(con.body, o.body); } } + // Set depth null if needed (this parameter is given in config) + if (depth_parameters.set_null_after_update) { + con.block_number = db.head_block_num(); + } }); } else { // Creation case + printf("creation case\n"); const comment_object *parent = nullptr; if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &db.get_comment(o.parent_author, o.parent_permlink); } - - // const auto& new_comment = database().get_comment(o.author, permlink); - - comment_id_type id = parent->id; - + const auto &new_comment = db.get_comment(o.author, o.permlink); + printf("after if\n"); + comment_id_type id = new_comment.id; + printf("before db.create\n"); db.create([&](comment_content_object& con) { + printf("in db.create\n"); con.comment = id; - from_string(con.title, o.title); - if (o.body.size() < 1024*1024*128) { + if (depth_parameters.has_comment_title_depth) { + con.title = o.title; + } + printf("after title\n"); + if (depth_parameters.has_comment_body_depth && o.body.size() < 1024*1024*128) { from_string(con.body, o.body); } - if (fc::is_utf8(o.json_metadata)) { + printf("after body\n"); + if (depth_parameters.has_comment_json_metadata_depth && fc::is_utf8(o.json_metadata)) { from_string(con.json_metadata, o.json_metadata); } else { wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); } + printf("after json_metadata\n"); + + con.block_number = db.head_block_num(); + printf("after block_number\n"); }); } + printf("DONE with comment_content_object edit or create\n"); } }; @@ -245,15 +272,27 @@ namespace golos { namespace plugins { namespace social_network { void social_network::impl::post_operation(const operation_notification &o) { auto& db = database(); - operation_visitor ovisit( db ); + operation_visitor ovisit(db, depth_parameters); o.op.visit(ovisit); - - // else work with comment_operation and upd content + } + void social_network::impl::on_block(const signed_block &b) { + auto& db = database(); + + const auto &idx = db.get_index().indices().get(); + + for (auto itr = idx.rbegin(); itr != idx.rend(); ++itr) { + printf("on_block in for\n"); + db.modify(*itr, [&](comment_content_object& con) { + std::cout << con.block_number << std::endl; + }); + } + + if ( idx.rbegin() != idx.rend() ){ + printf("after on_block for\n"); + } + - // std::cout << "\t\to.op.visit(ovisit) :\n\t\t" << "x.title = [" << x.title << "]\n\t\t" << - // "x.body = [" << x.body << "]\n\t\t" << - // "x.json_metadata = [" << x.json_metadata << "]" << std::endl; } @@ -286,6 +325,9 @@ namespace golos { namespace plugins { namespace social_network { ) ( "comment-json-metadata-depth", boost::program_options::value(), "max count of storing records of comment.json_metadata" + ) ( + "set-content-storing-depth-null-after-update", boost::program_options::value()->default_value(false), + "max count of storing records of comment.json_metadata" ); } @@ -301,18 +343,28 @@ namespace golos { namespace plugins { namespace social_network { pimpl->post_operation(o); }); + content_depth_params params; if (options.count("comment-title-depth")) { - pimpl->set_comment_title_depth( options.at("comment-title-depth").as() ); + params.comment_title_depth = options.at("comment-title-depth").as(); + params.has_comment_title_depth = true; } if (options.count("comment-body-depth")) { - pimpl->set_comment_body_depth( options.at("comment-body-depth").as() ); + params.comment_body_depth = options.at("comment-body-depth").as(); + params.has_comment_body_depth = true; } if (options.count("comment-json-metadata-depth")) { - pimpl->set_comment_json_metadata_depth( options.at("comment-json-metadata-depth").as() ); + params.comment_json_metadata_depth = options.at("comment-json-metadata-depth").as(); + params.has_comment_json_metadata_depth = true; + } + + if (options.count("set-content-storing-depth-null-after-update")) { + params.set_null_after_update = options.at("set-content-storing-depth-null-after-update").as(); } + + pimpl->set_depth_parameters(params); } social_network::~social_network() = default; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 36590fa562..7aa1104084 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -285,7 +285,7 @@ namespace golos { namespace plugins { namespace tags { query.start_comment = create_discussion(*comment, query); auto& d = query.start_comment; - operation_visitor v(database_); + operation_visitor v(database_, helper); d.hot = v.calculate_hot(d.net_rshares, d.created); d.trending = v.calculate_trending(d.net_rshares, d.created); From e315c695738b5cc8d138676407e47b22d5c82fc6 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 11 Jul 2018 14:40:21 +0300 Subject: [PATCH 049/250] Fixed errors with add_plugin_index and depth logic. #796 --- plugins/social_network/social_network.cpp | 41 +++++++++++------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index fa2740fb48..367e32bd1e 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -182,23 +182,22 @@ namespace golos { namespace plugins { namespace social_network { const auto& comment = db.get_comment(o.author, o.permlink); if (comment.created != db.head_block_time()) { - printf("edit case\n"); // Edit case db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { - if (o.title.size()) { - if (depth_parameters.has_comment_title_depth) { - from_string(con.title, o.title); - } + if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { + from_string(con.title, o.title); } if (o.json_metadata.size()) { - if (depth_parameters.has_comment_json_metadata_depth && fc::is_utf8(o.json_metadata)) { + if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && + fc::is_utf8(o.json_metadata) + ) { from_string(con.json_metadata, o.json_metadata ); } else { wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); } } - if (o.body.size() && depth_parameters.has_comment_body_depth) { + if (o.body.size() && (!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0)) { try { diff_match_patch dmp; auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); @@ -229,40 +228,38 @@ namespace golos { namespace plugins { namespace social_network { } else { // Creation case - printf("creation case\n"); const comment_object *parent = nullptr; if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &db.get_comment(o.parent_author, o.parent_permlink); } + const auto &new_comment = db.get_comment(o.author, o.permlink); - printf("after if\n"); comment_id_type id = new_comment.id; - printf("before db.create\n"); + db.create([&](comment_content_object& con) { - printf("in db.create\n"); con.comment = id; - if (depth_parameters.has_comment_title_depth) { - con.title = o.title; + if (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0) { + from_string(con.title, o.title); } - printf("after title\n"); - if (depth_parameters.has_comment_body_depth && o.body.size() < 1024*1024*128) { + + if ((!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { from_string(con.body, o.body); } - printf("after body\n"); - if (depth_parameters.has_comment_json_metadata_depth && fc::is_utf8(o.json_metadata)) { + + if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && + fc::is_utf8(o.json_metadata) + ) { from_string(con.json_metadata, o.json_metadata); - } else { + } + else { wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); } - printf("after json_metadata\n"); con.block_number = db.head_block_num(); - printf("after block_number\n"); }); } - printf("DONE with comment_content_object edit or create\n"); } }; @@ -337,7 +334,7 @@ namespace golos { namespace plugins { namespace social_network { auto& db = pimpl->database(); - // add_plugin_index(db); + add_plugin_index(db); db.post_apply_operation.connect([&](const operation_notification &o) { pimpl->post_operation(o); From dceb2454030b0b098a29bdda899730a97ea5c761 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Thu, 12 Jul 2018 06:42:09 +0300 Subject: [PATCH 050/250] Added missing constructor for discussion_helper. Fixed some errors. #796 --- libraries/api/discussion_helper.cpp | 19 +++++++++++ .../include/golos/api/discussion_helper.hpp | 6 ++++ plugins/social_network/social_network.cpp | 33 +++++++------------ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index bc55a4f7d0..d86766dc62 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -62,6 +62,16 @@ namespace golos { namespace api { fill_reputation_(fill_reputation), fill_promoted_(fill_promoted) { } + impl( + golos::chain::database& db, + std::function&)> fill_reputation, + std::function fill_promoted, + std::function get_comment_content_callback) + : database_(db), + fill_reputation_(fill_reputation), + fill_promoted_(fill_promoted), + get_comment_content_callback(get_comment_content_callback) { + } impl( golos::chain::database& db, std::function get_comment_content_callback) @@ -313,6 +323,15 @@ namespace golos { namespace api { pimpl = std::make_unique(db, fill_reputation, fill_promoted); } + discussion_helper::discussion_helper( + golos::chain::database& db, + std::function&)> fill_reputation, + std::function fill_promoted, + std::function get_comment_content_callback + ) { + pimpl = std::make_unique(db, fill_reputation, fill_promoted, get_comment_content_callback); + } + discussion_helper::discussion_helper( golos::chain::database& db, std::function get_comment_content_callback diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index e4b3d1b096..0eac1caf79 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -25,6 +25,12 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted); + discussion_helper( + golos::chain::database& db, + std::function&)> fill_reputation, + std::function fill_promoted, + std::function get_comment_content_callback + ); discussion_helper( golos::chain::database& db, std::function get_comment_content_callback diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 367e32bd1e..a4106413d3 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -66,7 +66,7 @@ namespace golos { namespace plugins { namespace social_network { struct social_network::impl final { impl(): database_(appbase::app().get_plugin().db()) { - helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted); + helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted, get_comment_content_callback); } ~impl() = default; @@ -228,11 +228,6 @@ namespace golos { namespace plugins { namespace social_network { } else { // Creation case - const comment_object *parent = nullptr; - - if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { - parent = &db.get_comment(o.parent_author, o.parent_permlink); - } const auto &new_comment = db.get_comment(o.author, o.permlink); comment_id_type id = new_comment.id; @@ -240,16 +235,19 @@ namespace golos { namespace plugins { namespace social_network { db.create([&](comment_content_object& con) { con.comment = id; if (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0) { + printf("Was in title\n"); from_string(con.title, o.title); } if ((!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { + printf("Was in body\n"); from_string(con.body, o.body); } if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && fc::is_utf8(o.json_metadata) ) { + printf("Was in json_metadata\n"); from_string(con.json_metadata, o.json_metadata); } else { @@ -274,21 +272,7 @@ namespace golos { namespace plugins { namespace social_network { o.op.visit(ovisit); } void social_network::impl::on_block(const signed_block &b) { - auto& db = database(); - - const auto &idx = db.get_index().indices().get(); - - for (auto itr = idx.rbegin(); itr != idx.rend(); ++itr) { - printf("on_block in for\n"); - db.modify(*itr, [&](comment_content_object& con) { - std::cout << con.block_number << std::endl; - }); - } - - if ( idx.rbegin() != idx.rend() ){ - printf("after on_block for\n"); - } - + } @@ -464,12 +448,17 @@ namespace golos { namespace plugins { namespace social_network { } discussion social_network::impl::get_content(std::string author, std::string permlink, uint32_t limit) const { + printf("in get_content\n"); + std::cout << "author = " << author << ", permlink = " << permlink << std::endl; + const auto& by_permlink_idx = database().get_index().indices().get(); auto itr = by_permlink_idx.find(std::make_tuple(author, permlink)); if (itr != by_permlink_idx.end()) { + printf("return get_discussion(*itr, limit);\n"); return get_discussion(*itr, limit); } - return helper->create_discussion(author); + printf("return helper->create_discussion(*itr);\n"); + return helper->create_discussion(*itr); } DEFINE_API(social_network, get_content) { From 086b5dbbcfd9e5dc4d6d7a6264a4044063946233 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 12 Jul 2018 15:56:12 +0700 Subject: [PATCH 051/250] Fix wintness scheduler for testnet. #834 --- libraries/chain/database.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 3422659bbe..37284f7ed4 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1518,13 +1518,14 @@ namespace golos { namespace chain { new_virtual_time = fc::uint128_t(); reset_virtual_schedule_time(); } - +#ifndef STEEMIT_BUILD_TESTNET size_t expected_active_witnesses = std::min(size_t(STEEMIT_MAX_WITNESSES), widx.size()); if (head_block_num() > 14400) { FC_ASSERT(active_witnesses.size() == expected_active_witnesses, "number of active witnesses does not equal expected_active_witnesses=${expected_active_witnesses}", ("active_witnesses.size()", active_witnesses.size())("STEEMIT_MAX_WITNESSES", STEEMIT_MAX_WITNESSES)("expected_active_witnesses", expected_active_witnesses)); } +#endif auto majority_version = wso.majority_version; From 5f0d01d39a2790a6215f1a5ea57b5bd5d2734715 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Thu, 12 Jul 2018 22:59:19 +0300 Subject: [PATCH 052/250] Added auto removing not needed content_object data by depth given in config. #796 --- plugins/social_network/social_network.cpp | 115 ++++++++++++++++++---- 1 file changed, 95 insertions(+), 20 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index a4106413d3..a5c42c1042 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -12,9 +12,10 @@ #include #include -// #include #include +#include + #define CHECK_ARG_SIZE(_S) \ FC_ASSERT( \ args.args->size() == _S, \ @@ -43,7 +44,21 @@ struct content_depth_params { } inline bool miss_content() const { - return has_comment_title_depth && has_comment_body_depth && has_comment_json_metadata_depth; + return has_comment_title_depth && !comment_title_depth && + has_comment_body_depth && !comment_body_depth && + has_comment_json_metadata_depth && !comment_json_metadata_depth; + } + + inline bool need_clear() const { + return has_comment_title_depth || has_comment_body_depth || has_comment_json_metadata_depth; + } + + inline bool should_delete_whole_content_object(const uint32_t & delta) const { + return comment_title_depth > delta && comment_body_depth > delta && comment_json_metadata_depth > delta; + } + + inline bool should_delete_part_of_content_object(const uint32_t & delta) const { + return comment_title_depth > delta || comment_body_depth > delta || comment_json_metadata_depth > delta; } @@ -107,14 +122,12 @@ namespace golos { namespace plugins { namespace social_network { void set_depth_parameters(const content_depth_params ¶ms); - // Removes comment_content data which is not needed anymore - void clear_comment_content_info(); - // Looks for a comment_operation, fills the comment_content state objects. void post_operation(const operation_notification &o); void on_block(const signed_block &b); + private: golos::chain::database& database_; std::unique_ptr helper; @@ -138,6 +151,8 @@ namespace golos { namespace plugins { namespace social_network { } struct operation_visitor { + using result_type = void; + golos::chain::database &db; content_depth_params depth_parameters; @@ -161,9 +176,7 @@ namespace golos { namespace plugins { namespace social_network { const comment_content_object *find_comment_content(const comment_id_type &comment) const { return db.find(comment); } - - using result_type = void; - + template void operator()(const T& o) const { } @@ -235,19 +248,16 @@ namespace golos { namespace plugins { namespace social_network { db.create([&](comment_content_object& con) { con.comment = id; if (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0) { - printf("Was in title\n"); from_string(con.title, o.title); } if ((!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { - printf("Was in body\n"); from_string(con.body, o.body); } if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && fc::is_utf8(o.json_metadata) ) { - printf("Was in json_metadata\n"); from_string(con.json_metadata, o.json_metadata); } else { @@ -259,10 +269,42 @@ namespace golos { namespace plugins { namespace social_network { }); } } - }; - void social_network::impl::clear_comment_content_info() { - } + // Checking should we delete comment_content if needed depth has been expired + void operator()(const comment_payout_update_operation& o) const { + if (!depth_parameters.need_clear()) { + return; + } + + const auto &comment = db.get_comment(o.author, o.permlink); + auto& content = get_comment_content(comment.id); + auto delta = db.head_block_num() - content.block_number; + + if (depth_parameters.should_delete_whole_content_object(delta)) { + db.remove(content); + return; + } + + if (depth_parameters.should_delete_part_of_content_object(delta)) { + db.modify(content, [&](comment_content_object& con) { + if (delta > depth_parameters.comment_title_depth) { + con.title.clear(); + } + + if (delta > depth_parameters.comment_body_depth) { + con.body.clear(); + } + + if (delta > depth_parameters.comment_json_metadata_depth) { + con.json_metadata.clear(); + } + }); + + return; + } + } + + }; void social_network::impl::post_operation(const operation_notification &o) { auto& db = database(); @@ -272,8 +314,42 @@ namespace golos { namespace plugins { namespace social_network { o.op.visit(ovisit); } void social_network::impl::on_block(const signed_block &b) { - + auto & db = database(); + + const auto &idx = db.get_index().indices().get(); + + for (auto itr = idx.begin(); itr != idx.end(); ++itr) { + auto & content = *itr; + + const auto &cidx = db.get_index().indices().get(); + + auto comment = cidx.find(content.comment); + + int64_t cash_window_sec = STEEMIT_CASHOUT_WINDOW_SECONDS; + auto time_delta = db.head_block_time() - comment->created; + auto delta = db.head_block_num() - content.block_number; + if (time_delta > fc::microseconds(cash_window_sec) && depth_parameters.should_delete_part_of_content_object(delta)) { + if (depth_parameters.should_delete_whole_content_object(delta)) { + db.remove(content); + continue; + } + db.modify(content, [&](comment_content_object& con) { + if (delta > depth_parameters.comment_title_depth) { + con.title.clear(); + } + + if (delta > depth_parameters.comment_body_depth) { + con.body.clear(); + } + + if (delta > depth_parameters.comment_json_metadata_depth) { + con.json_metadata.clear(); + } + }); + + } + } } @@ -324,6 +400,10 @@ namespace golos { namespace plugins { namespace social_network { pimpl->post_operation(o); }); + db.applied_block.connect([&](const signed_block &b) { + pimpl->on_block(b); + }); + content_depth_params params; if (options.count("comment-title-depth")) { @@ -448,16 +528,11 @@ namespace golos { namespace plugins { namespace social_network { } discussion social_network::impl::get_content(std::string author, std::string permlink, uint32_t limit) const { - printf("in get_content\n"); - std::cout << "author = " << author << ", permlink = " << permlink << std::endl; - const auto& by_permlink_idx = database().get_index().indices().get(); auto itr = by_permlink_idx.find(std::make_tuple(author, permlink)); if (itr != by_permlink_idx.end()) { - printf("return get_discussion(*itr, limit);\n"); return get_discussion(*itr, limit); } - printf("return helper->create_discussion(*itr);\n"); return helper->create_discussion(*itr); } From 66a15553fae95741c72f2d8dfb0047357e123ec0 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 13 Jul 2018 13:34:56 +0700 Subject: [PATCH 053/250] Implement convertion from exceptions into JSON response #788 --- .../include/golos/protocol/exceptions.hpp | 22 +- .../include/golos/plugins/json_rpc/plugin.hpp | 16 +- plugins/json_rpc/plugin.cpp | 213 +++++++------ tests/CMakeLists.txt | 3 +- tests/plugin_tests/json_rpc.cpp | 288 ++++++++++++++++++ 5 files changed, 431 insertions(+), 111 deletions(-) create mode 100644 tests/plugin_tests/json_rpc.cpp diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index a788e70caa..91404a421a 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -59,7 +59,7 @@ try {return (GETTER);} \ catch (const fc::exception &e) { \ FC_THROW_EXCEPTION(golos::invalid_parameter, \ - "Invalid parameter \"${name}\": ${reason}", \ + "Invalid parameter \"${param}\": ${errmsg}", \ ("param", BOOST_PP_STRINGIZE(PARAM)) \ ("errmsg", e.to_string()) \ ("error", e) \ @@ -124,16 +124,24 @@ namespace golos { 1010000, "Unsupported operation"); GOLOS_DECLARE_DERIVED_EXCEPTION( - invalid_arguments_count, operation_exception, - 1020000, "Invalid argument count"); + parameter_exception, operation_exception, + 1020000, "Parameter exception"); GOLOS_DECLARE_DERIVED_EXCEPTION( - missing_object, operation_exception, - 1030000, "Missing object"); + invalid_arguments_count, parameter_exception, + 1020100, "Invalid argument count"); GOLOS_DECLARE_DERIVED_EXCEPTION( - invalid_parameter, operation_exception, - 1040000, "Invalid parameter value"); + missing_object, parameter_exception, + 1020200, "Missing object"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + object_already_exist, parameter_exception, + 1020300, "Object already exist"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + invalid_parameter, parameter_exception, + 1020400, "Invalid parameter value"); GOLOS_DECLARE_DERIVED_EXCEPTION( business_exception, golos_exception, diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp index 6b15079faf..994be50c5c 100644 --- a/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/plugin.hpp @@ -48,14 +48,14 @@ #define JSON_RPC_METHOD_NOT_FOUND (-32601) #define JSON_RPC_INVALID_PARAMS (-32602) #define JSON_RPC_INTERNAL_ERROR (-32603) -#define JSON_RPC_SERVER_ERROR (-32000) -#define JSON_RPC_NO_PARAMS (-32001) -#define JSON_RPC_PARSE_PARAMS_ERROR (-32002) -#define JSON_RPC_ERROR_DURING_CALL (-32003) -#define JSON_RPC_INSUFFICIENT_FUNDS (-32004) -#define JSON_RPC_MISSING_AUTHORITY (-32005) -#define JSON_RPC_MISSING_OBJECT (-32006) -#define JSON_RPC_LOGIC_ERROR (-32007) + +#define SERVER_INTERNAL_ERROR (-32000) +#define SERVER_UNSUPPORTED_OPERATION (-32001) // unsupported_operation +#define SERVER_INVALID_PARAMETER (-32002) // parameter_exception (invalid_arguments_count, missing_object, object_already_exist) +#define SERVER_BUSINESS_LOGIC_ERROR (-32003) // business_exception (bandwidth_exception, insufficient_funds, logic_exception) +#define SERVER_MISSING_AUTHORITY (-32004) // tx_missing_authority +#define SERVER_INVALID_OPERATION (-32005) // tx_invalid_operation (client must check inner exception) +#define SERVER_INVALID_TRANSACTION (-32006) // transaction_exception namespace golos { namespace plugins { diff --git a/plugins/json_rpc/plugin.cpp b/plugins/json_rpc/plugin.cpp index 71cef9e8d0..5f94414940 100644 --- a/plugins/json_rpc/plugin.cpp +++ b/plugins/json_rpc/plugin.cpp @@ -161,92 +161,114 @@ namespace golos { _methods.push_back(canonical_name.str()); } - api_method *find_api_method(std::string api, std::string method) { + api_method *find_api_method(std::string api, std::string method, msg_pack& msg) { auto api_itr = _registered_apis.find(api); - FC_ASSERT(api_itr != _registered_apis.end(), "Could not find API ${api}", ("api", api)); + if (api_itr == _registered_apis.end()) { + msg.error(JSON_RPC_METHOD_NOT_FOUND, "Could not find API ${api}", + fc::mutable_variant_object()("api", api)); + return nullptr; + } auto method_itr = api_itr->second.find(method); - FC_ASSERT(method_itr != api_itr->second.end(), "Could not find method ${method}", - ("method", method)); + if (method_itr == api_itr->second.end()) { + msg.error(JSON_RPC_METHOD_NOT_FOUND, "Could not find method ${method}", + fc::mutable_variant_object()("method", method)); + return nullptr; + } return &(method_itr->second); } - api_method *process_params(string method, const fc::variant_object &request, msg_pack &func_args) { + api_method *process_params(const fc::variant_object &request, msg_pack &func_args) { api_method *ret = nullptr; - if (method == "call") { - FC_ASSERT(request.contains("params")); + if (!request.contains("params")) { + func_args.error(JSON_RPC_INVALID_REQUEST, "A member \"params\" does not exist"); + return nullptr; + } - std::vector v; + std::vector v; - if (request["params"].is_array()) { - v = request["params"].as >(); - } + if (request["params"].is_array()) { + v = request["params"].as >(); + } - FC_ASSERT(v.size() == 2 || v.size() == 3, "params should be {\"api\", \"method\", \"args\""); + if (v.size() < 2 || v.size() > 3) { + func_args.error(JSON_RPC_INVALID_REQUEST, "A member \"params\" should be [\"api\", \"method\", \"args\"]"); + return nullptr; + } - ret = find_api_method(v[0].as_string(), v[1].as_string()); - func_args.plugin = v[0].as_string(); - func_args.method = v[1].as_string(); - fc::variant tmp = (v.size() == 3) ? v[2] : fc::json::from_string("{}"); - func_args.args = tmp.as>(); - } else { - vector v; - boost::split(v, method, boost::is_any_of(".")); + if (nullptr == (ret = find_api_method(v[0].as_string(), v[1].as_string(), func_args))) { + return nullptr; + } - FC_ASSERT(v.size() == 2, "method specification invalid. Should be api.method"); + func_args.plugin = v[0].as_string(); + func_args.method = v[1].as_string(); + fc::variant tmp = (v.size() == 3) ? v[2] : fc::json::from_string("[]"); - ret = find_api_method(v[0], v[1]); - func_args.plugin = v[0]; - func_args.method = v[1]; - fc::variant tmp = (v.size() == 3) ? v[2] : fc::json::from_string("{}"); + try { func_args.args = tmp.as>(); + } catch (const fc::bad_cast_exception& e) { + func_args.error(JSON_RPC_INVALID_REQUEST, "A member \"args\" should be array", static_cast(e)); + return nullptr; } return ret; } - void rpc_jsonrpc(const fc::variant_object &request, msg_pack &msg) { - // TODO: id is optional value or not? - if (request.contains("id")) { - msg.rpc_id(request["id"]); - } + void rpc_jsonrpc(const fc::variant &data, msg_pack &msg) { + fc::variant_object request; - if (!request.contains("jsonrpc") || request["jsonrpc"].as_string() != "2.0") { - return msg.error(JSON_RPC_INVALID_REQUEST, "jsonrpc value is not \"2.0\""); - } else if (!request.contains("method")) { - return msg.error(JSON_RPC_INVALID_REQUEST, "A member \"method\" does not exist"); - } + try { + request = data.get_object(); + + // TODO: id is optional value or not? + if (request.contains("id")) { + msg.rpc_id(request["id"]); + } - string method; + if (!request.contains("jsonrpc") || request["jsonrpc"].as_string() != "2.0") { + return msg.error(JSON_RPC_INVALID_REQUEST, "jsonrpc value is not \"2.0\""); + } - try { - method = request["method"].as_string(); - } catch (const fc::assert_exception &e) { - return msg.error(JSON_RPC_METHOD_NOT_FOUND, e); + if (!request.contains("method") || request["method"].as_string() != "call") { + return msg.error(JSON_RPC_INVALID_REQUEST, "A member \"method\" is not \"call\""); + } + } catch (const fc::bad_cast_exception& e) { + return msg.error(JSON_RPC_INVALID_REQUEST, "Invalid request structure", static_cast(e)); } - // This is to maintain backwards compatibility with existing call structure. - if ((method == "call" && request.contains("params")) || method != "call") { - api_method *call = nullptr; - try { - call = process_params(method, request, msg); - } catch (const fc::assert_exception &e) { - return msg.error(JSON_RPC_PARSE_PARAMS_ERROR, e); - } + api_method *call = process_params(request, msg); + if (call == nullptr) { + return; + } - try { - auto result = (*call)(msg); - if (msg.valid()) { - msg.result(std::move(result)); - } - } catch (const fc::assert_exception &e) { - return msg.error(JSON_RPC_ERROR_DURING_CALL, e); + try { + auto result = (*call)(msg); + if (msg.valid()) { + msg.result(std::move(result)); } - } else { - return msg.error(JSON_RPC_NO_PARAMS, "A member \"params\" does not exist"); + } catch (const golos::unsupported_operation& e) { + msg.error(SERVER_UNSUPPORTED_OPERATION, e); + + } catch (const golos::parameter_exception& e) { + msg.error(SERVER_INVALID_PARAMETER, e); + + } catch (const golos::business_exception& e) { + msg.error(SERVER_BUSINESS_LOGIC_ERROR, e); + + } catch (const golos::protocol::tx_missing_authority& e) { + msg.error(SERVER_MISSING_AUTHORITY, e); + + } catch (const golos::protocol::tx_invalid_operation& e) { + msg.error(SERVER_INVALID_OPERATION, e); + + } catch (const golos::protocol::transaction_exception& e) { + msg.error(SERVER_INVALID_TRANSACTION, e); + + } catch (const golos::golos_exception& e) { + msg.error(SERVER_INTERNAL_ERROR, e); } } @@ -286,28 +308,13 @@ namespace golos { dump_rpc_time dump(data); try { - rpc_jsonrpc(data.get_object(), msg); + rpc_jsonrpc(data, msg); - } catch (const golos::insufficient_funds& e) { - msg.error(JSON_RPC_INSUFFICIENT_FUNDS, e); - } catch (const golos::protocol::tx_missing_authority& e) { - msg.error(JSON_RPC_MISSING_AUTHORITY, e); - } catch (const golos::missing_object& e) { - msg.error(JSON_RPC_MISSING_OBJECT, e); - } catch (const golos::logic_exception& e) { - msg.error(JSON_RPC_LOGIC_ERROR, e); - - } catch (const fc::parse_error_exception& e) { - msg.error(JSON_RPC_INVALID_PARAMS, e); - dump.error("invalid params"); - } catch (const fc::bad_cast_exception& e) { - msg.error(JSON_RPC_INVALID_PARAMS, e); - dump.error("invalid types"); } catch (const fc::exception& e) { - msg.error(JSON_RPC_INTERNAL_ERROR, e); + msg.error(JSON_RPC_INTERNAL_ERROR, std::string("Internal error: ") + e.to_string(), e); dump.error("invalid request"); } catch (const std::exception& e) { - msg.error(JSON_RPC_INTERNAL_ERROR, e.what()); + msg.error(JSON_RPC_INTERNAL_ERROR, std::string("Internal error: ") + e.what()); dump.error(e.what()); } catch (...) { msg.error(JSON_RPC_INTERNAL_ERROR, "Unknown error - parsing rpc message failed"); @@ -340,6 +347,41 @@ namespace golos { next_handler(); } + void call(const string &message, response_handler_type response_handler) { + auto send_error = [response_handler](int32_t code, const std::string& msg, fc::optional d = fc::optional()) { + json_rpc_response response; + response.error = json_rpc_error(code, msg, d); + response_handler(fc::json::to_string(response)); + }; + + try { + fc::variant v; + + try { + v = fc::json::from_string(message); + } catch (const fc::exception& e) { + return send_error(JSON_RPC_PARSE_ERROR, "Invalid JSON-structure", e); + } + + if (v.is_array()) { + vector messages = v.as>(); + + if(messages.size() == 0) { + return send_error(JSON_RPC_INVALID_REQUEST, "Array of requests must be non-empty"); + } + rpc(messages, response_handler); + } else { + msg_pack msg([response_handler](json_rpc_response &response){ + response_handler(fc::json::to_string(response)); + }); + + rpc(v, msg); + } + } catch (const fc::exception &e) { + return send_error(JSON_RPC_INTERNAL_ERROR, e.to_string(), e); + } + } + void initialize() { } @@ -405,26 +447,7 @@ namespace golos { } void plugin::call(const string &message, response_handler_type response_handler) { - try { - fc::variant v = fc::json::from_string(message); - - if (v.is_array()) { - vector messages = v.as>(); - - FC_ASSERT(messages.size(), "Array is invalid"); - pimpl->rpc(messages, response_handler); - } else { - msg_pack msg([response_handler](json_rpc_response &response){ - response_handler(fc::json::to_string(response)); - }); - - pimpl->rpc(v, msg); - } - } catch (const fc::exception &e) { - json_rpc_response response; - response.error = json_rpc_error(JSON_RPC_SERVER_ERROR, e.to_string(), fc::variant(*(e.dynamic_copy_exception()))); - response_handler(fc::json::to_string(response)); - } + pimpl->call(message, response_handler); } } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 90facad010..af98407b7d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,7 +34,8 @@ add_test(NAME chain_test_run COMMAND chain_test) file(GLOB PLUGIN_TESTS "plugin_tests/main.cpp" "plugin_tests/market_history.cpp" - "plugin_tests/plugin_ops.cpp") + "plugin_tests/plugin_ops.cpp" + "plugin_tests/json_rpc.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") diff --git a/tests/plugin_tests/json_rpc.cpp b/tests/plugin_tests/json_rpc.cpp new file mode 100644 index 0000000000..517fe21618 --- /dev/null +++ b/tests/plugin_tests/json_rpc.cpp @@ -0,0 +1,288 @@ +#ifdef STEEMIT_BUILD_TESTNET + +#include + +#include +#include +#include + +#include + +#include "database_fixture.hpp" + +using namespace golos::chain; +using namespace golos::protocol; + +typedef golos::plugins::json_rpc::plugin json_rpc_plugin; + +namespace test_plugin { + + using golos::plugins::json_rpc::msg_pack; + + DEFINE_API_ARGS(throw_exception, msg_pack, std::string) + + class testing_api final : public appbase::plugin { + public: + testing_api() { } + ~testing_api() { } + + constexpr static const char *plugin_name = "testing_api"; + + APPBASE_PLUGIN_REQUIRES((json_rpc_plugin)); + + static const std::string &name() { + static std::string name = plugin_name; + return name; + } + + void set_program_options(boost::program_options::options_description &, + boost::program_options::options_description &) override { + } + + void plugin_initialize(const boost::program_options::variables_map &options) override { + JSON_RPC_REGISTER_API(plugin_name); + } + + void plugin_startup() override { } + + void plugin_shutdown() override { } + + DECLARE_API((throw_exception)) + }; + + DEFINE_API(testing_api, throw_exception) { + auto error = args.args->at(0).get_string(); + + if (error == "unsupported_operation") + FC_THROW_EXCEPTION(golos::unsupported_operation, "Unsupported operation"); + + if (error == "invalid_parameter") + FC_THROW_EXCEPTION(golos::invalid_parameter, "Invalid parameter"); + + if (error == "business_exception") + FC_THROW_EXCEPTION(golos::business_exception, "Business logic error"); + + if (error == "tx_missing_authority") + FC_THROW_EXCEPTION(golos::protocol::tx_missing_authority, "Missing authority"); + + if (error == "tx_invalid_operation") + FC_THROW_EXCEPTION(golos::protocol::tx_invalid_operation, "Invalid operation"); + + if (error == "transaction_exception") + FC_THROW_EXCEPTION(golos::protocol::transaction_exception, "Transaction error"); + + if (error == "golos_exception") + FC_THROW_EXCEPTION(golos::golos_exception, "Internal server exception"); + + if (error == "fc::exception") + FC_THROW_EXCEPTION(fc::exception, "Internal error"); + + if (error == "std::exception") + throw std::logic_error("Internal error"); + + throw "Internal error"; + } +} // namespace test_plugin + +fc::variant call(json_rpc_plugin& plugin, const std::string& request) { + fc::variant response; + plugin.call(request, [&](const std::string& str) {response = fc::json::from_string(str);}); + return response; +} + +void check_error_response(const fc::variant& response, const fc::variant& id, int32_t code, const std::string& error_name = std::string()) { + BOOST_CHECK_EQUAL(response["jsonrpc"].get_string(), "2.0"); + BOOST_CHECK_EQUAL(response["id"].get_type(), id.get_type()); + if (!id.is_null()) { + BOOST_CHECK_EQUAL(response["id"].as_string(), id.as_string()); + } + BOOST_CHECK(response["error"].is_object()); + BOOST_CHECK(response["error"]["message"].is_string()); + BOOST_CHECK(response["error"]["code"].is_integer()); + BOOST_CHECK_EQUAL(response["error"]["code"].as(), code); + + if (!error_name.empty()) { + auto data = response["error"]["data"].get_object(); + BOOST_CHECK_EQUAL(data["name"].get_string(), error_name); + } +} + +BOOST_FIXTURE_TEST_SUITE(json_rpc, database_fixture) + + BOOST_AUTO_TEST_CASE(json_rpc_test) { + try { + initialize(); + + + auto &rpc_plugin = appbase::app().register_plugin(); + auto &testing_api = appbase::app().register_plugin(); + + boost::program_options::variables_map options; + rpc_plugin.plugin_initialize(options); + testing_api.plugin_initialize(options); + + open_database(); + + startup(); + rpc_plugin.plugin_startup(); + testing_api.plugin_startup(); + + + BOOST_TEST_MESSAGE("--- empty request"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "").get_object(); + check_error_response(response, fc::variant(), JSON_RPC_PARSE_ERROR); + }); + + BOOST_TEST_MESSAGE("--- invalid json sctructure"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{]").get_object(); + check_error_response(response, fc::variant(), JSON_RPC_PARSE_ERROR); + }); + + BOOST_TEST_MESSAGE("--- empty array of request"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "[]").get_object(); + check_error_response(response, fc::variant(), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- empty request object"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{}").get_object(); + check_error_response(response, fc::variant(), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid 'jsonrpc' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"1.2\"}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid type of 'jsonrpc' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":[]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid 'method' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"database_api.get_dynamic_global_properties\"}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid type of 'method' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":[]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- missing 'params' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\"}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid type of 'params' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":1234}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- invalid type of 'args' field"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",{}]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INVALID_REQUEST); + }); + + BOOST_TEST_MESSAGE("--- missing API"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"missing_api\",\"missing_method\"]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_METHOD_NOT_FOUND); + }); + + BOOST_TEST_MESSAGE("--- missing method"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"missing_method\",[]]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_METHOD_NOT_FOUND); + }); + + BOOST_TEST_MESSAGE("--- return UNSUPPORTED_OPERATION when thrown golos::unsupported_operation"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"unsupported_operation\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_UNSUPPORTED_OPERATION, "unsupported_operation"); + }); + + BOOST_TEST_MESSAGE("--- return INVALID_PARAMETER when thrown golos::parameter_exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"invalid_parameter\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_INVALID_PARAMETER, "invalid_parameter"); + }); + + BOOST_TEST_MESSAGE("--- return BUSINESS_LOGIC_ERROR when thrown golos::business_exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"business_exception\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_BUSINESS_LOGIC_ERROR, "business_exception"); + }); + + BOOST_TEST_MESSAGE("--- return MISSING_AUTHORITY when thrown golos::protocol::tx_missing_authority"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"tx_missing_authority\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_MISSING_AUTHORITY, "tx_missing_authority"); + }); + + BOOST_TEST_MESSAGE("--- return INVALID_OPERATION when thrown golos::protocol::tx_invalid_operation"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"tx_invalid_operation\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_INVALID_OPERATION, "tx_invalid_operation"); + }); + + BOOST_TEST_MESSAGE("--- return INVALID_TRANSACTION when thrown golos::protocol::transaction_exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"transaction_exception\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_INVALID_TRANSACTION, "transaction_exception"); + }); + + BOOST_TEST_MESSAGE("--- return INTERNAL_ERROR when thrown golos::golos_exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"golos_exception\"]]}").get_object(); + check_error_response(response, fc::variant(1u), SERVER_INTERNAL_ERROR, "golos_exception"); + }); + + + BOOST_TEST_MESSAGE("--- return INTERNAL_ERROR when thrown fc::exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"fc::exception\"]]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INTERNAL_ERROR); + }); + + BOOST_TEST_MESSAGE("--- return INTERNAL_ERROR when thrown std::excption"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"std::exception\"]]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INTERNAL_ERROR); + }); + + BOOST_TEST_MESSAGE("--- return INTERNAL_ERROR when thrown unknown exception"); + BOOST_CHECK_NO_THROW({ + auto response = call(rpc_plugin, "{\"id\":1, \"jsonrpc\":\"2.0\",\"method\":\"call\",\"params\":[" + "\"testing_api\",\"throw_exception\",[\"...\"]]}").get_object(); + check_error_response(response, fc::variant(1u), JSON_RPC_INTERNAL_ERROR); + }); + + } + FC_LOG_AND_RETHROW() + } + +BOOST_AUTO_TEST_SUITE_END() +#endif From 2059e65c5b9322f74600f0f2e1d5665936e9adc5 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Fri, 13 Jul 2018 09:36:55 +0300 Subject: [PATCH 054/250] Mongo_db transfer and fill transfer collections, etc. #830 #833 --- .../golos/plugins/mongo_db/mongo_db_state.hpp | 5 + plugins/mongo_db/mongo_db_plugin.cpp | 1 - plugins/mongo_db/mongo_db_state.cpp | 227 +++++++++++++++++- 3 files changed, 223 insertions(+), 10 deletions(-) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp index 32228e6ba3..e8a7aa4ec9 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp @@ -128,6 +128,11 @@ namespace mongo_db { void format_required_approval(const required_approval_object& reqapp, const account_name_type& proposal_author, const std::string& proposal_title); + void format_liquidity_reward_balance(const liquidity_reward_balance_object& lrbo, + const account_name_type& owner); + + void format_liquidity_reward_balance(const account_name_type& owner); + named_document create_document(const std::string& name, const std::string& key, const std::string& keyval); diff --git a/plugins/mongo_db/mongo_db_plugin.cpp b/plugins/mongo_db/mongo_db_plugin.cpp index 3aca0827ed..712218db67 100644 --- a/plugins/mongo_db/mongo_db_plugin.cpp +++ b/plugins/mongo_db/mongo_db_plugin.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 62980abb9e..d02c303198 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include #include #include @@ -22,7 +20,6 @@ namespace mongo_db { using bsoncxx::builder::stream::document; using bsoncxx::builder::stream::open_document; using bsoncxx::builder::stream::close_document; - using namespace golos::plugins::follow; using golos::chain::by_account; using golos::chain::decline_voting_rights_request_index; @@ -68,6 +65,8 @@ namespace mongo_db { format_value(body, "removed", false); + format_value(body, "block_num", state_block.block_num()); + format_value(body, "author", auth); format_value(body, "permlink", perm); format_value(body, "abs_rshares", comment.abs_rshares); @@ -636,6 +635,50 @@ namespace mongo_db { } } + void state_writer::format_liquidity_reward_balance(const liquidity_reward_balance_object& lrbo, + const account_name_type& owner) { + try { + auto oid = std::string(owner); + auto oid_hash = hash_oid(oid); + + auto doc = create_document("liquidity_reward_balance_object", "_id", oid_hash); + + // We don't need any 'owner_id' because oid is owner + + auto& body = doc.doc; + + body << "$set" << open_document; + + format_oid(body, oid); + + format_value(body, "owner", owner); + format_value(body, "steem_volume", lrbo.steem_volume); + format_value(body, "sbd_volume", lrbo.sbd_volume); + //format_value(body, "weight", lrbo.weight); // weight not exported now + format_value(body, "last_update", lrbo.last_update); + + body << close_document; + + bmi_insert_or_replace(all_docs, std::move(doc)); + } catch (...) { + // + } + } + + void state_writer::format_liquidity_reward_balance(const account_name_type& owner) { + try { + auto &obj_owner = db_.get_account(owner); + const auto &ridx = db_.get_index().indices().get(); + auto itr = ridx.find(obj_owner.id); + if (ridx.end() != itr) { + format_liquidity_reward_balance(*itr, owner); + } + } + catch (...) { + // + } + } + auto state_writer::operator()(const vote_operation& op) -> result_type { format_comment(op.author, op.permlink); @@ -756,6 +799,38 @@ namespace mongo_db { auto state_writer::operator()(const transfer_to_vesting_operation& op) -> result_type { format_account(op.from); format_account(op.to); + try { + const auto &dgp = db_.get_dynamic_global_properties(); + + auto doc = create_document("transfer_to_vesting", "", ""); + auto& body = doc.doc; + + document from_index; + from_index << "from_id" << 1; + doc.indexes_to_create.push_back(std::move(from_index)); + + document to_index; + to_index << "to_id" << 1; + doc.indexes_to_create.push_back(std::move(to_index)); + + format_value(body, "from", op.from); + format_oid(body, "from_id", op.from); + format_value(body, "to", op.to); + format_oid(body, "to_id", op.to); + format_value(body, "amount", op.amount); + + asset amount_gests; + amount_gests.amount = op.amount.amount / + (dgp.total_reward_fund_steem.amount / dgp.total_vesting_shares.amount); + amount_gests.symbol = VESTS_SYMBOL; + + format_value(body, "amount_gests", amount_gests); + + all_docs.push_back(std::move(doc)); + } + catch (...) { + // + } } auto state_writer::operator()(const withdraw_vesting_operation& op) -> result_type { @@ -819,6 +894,7 @@ namespace mongo_db { format_oid(body, oid); + format_value(body, "filled", false); format_value(body, "owner", std::string(op.owner)); format_value(body, "requestid", op.requestid); format_value(body, "amount", op.amount); @@ -968,6 +1044,7 @@ namespace mongo_db { format_oid(body, oid); + format_value(body, "filled", false); format_value(body, "from_account", std::string(from_account.name)); format_value(body, "to_account", std::string(to_account.name)); format_value(body, "percent", wvro.percent); @@ -1146,6 +1223,27 @@ namespace mongo_db { auto state_writer::operator()(const transfer_to_savings_operation& op) -> result_type { format_account(op.from); format_account(op.to); + + auto doc = create_document("transfer_to_savings", "", ""); + + document from_index; + from_index << "from_id" << 1; + doc.indexes_to_create.push_back(std::move(from_index)); + + document to_index; + to_index << "to_id" << 1; + doc.indexes_to_create.push_back(std::move(to_index)); + + auto& body = doc.doc; + + format_value(body, "from", op.from); + format_oid(body, "from_id", op.from); + format_value(body, "to", op.to); + format_oid(body, "to_id", op.to); + format_value(body, "amount", op.amount); + format_value(body, "memo", op.memo); + + all_docs.push_back(std::move(doc)); } auto state_writer::operator()(const transfer_from_savings_operation& op) -> result_type { @@ -1312,23 +1410,123 @@ namespace mongo_db { } auto state_writer::operator()(const fill_convert_request_operation& op) -> result_type { - + try { + format_account(op.owner); + + auto oid = std::string(op.owner).append("/").append(std::to_string(op.requestid)); + auto oid_hash = hash_oid(oid); + + auto cro = create_document("convert_request_object", "_id", oid_hash); + + auto& body = cro.doc; + + body << "$set" << open_document; + + format_oid(body, oid); + + format_value(body, "filled", true); + format_value(body, "amount_out", op.amount_out); + + body << close_document; + + bmi_insert_or_replace(all_docs, std::move(cro)); + } + catch (...) { + // + } } auto state_writer::operator()(const liquidity_reward_operation& op) -> result_type { - + try { + auto &owner = db_.get_account(op.owner); + const auto &ridx = db_.get_index().indices().get(); + auto itr = ridx.find(owner.id); + if (ridx.end() != itr) { + format_liquidity_reward_balance(*itr, op.owner); + } + } + catch (...) { + // + } } auto state_writer::operator()(const interest_operation& op) -> result_type { - + try { + auto doc = create_document("interest", "", ""); + auto& body = doc.doc; + + document owner_index; + owner_index << "owner_id" << 1; + doc.indexes_to_create.push_back(std::move(owner_index)); + + format_oid(body, "owner_id", op.owner); + format_value(body, "owner", op.owner); + format_value(body, "interest", op.interest); + + all_docs.push_back(std::move(doc)); + } + catch (...) { + // + } } auto state_writer::operator()(const fill_vesting_withdraw_operation& op) -> result_type { - + try { + format_account(op.from_account); + format_account(op.to_account); + auto oid = op.from_account + "/" + op.to_account; + auto oid_hash = hash_oid(oid); + + auto doc = create_document("withdraw_vesting_route_object", "_id", oid_hash); + + auto &body = doc.doc; + + body << "$set" << open_document; + + format_oid(body, oid); + + format_value(body, "filled", true); + format_value(body, "withdrawn", op.withdrawn); + format_value(body, "deposited", op.deposited); + + body << close_document; + + bmi_insert_or_replace(all_docs, std::move(doc)); + } + catch (...) { + // + } } auto state_writer::operator()(const fill_order_operation& op) -> result_type { - + format_liquidity_reward_balance(op.current_owner); + format_liquidity_reward_balance(op.open_owner); + try { + auto doc = create_document("fill_order_id", "", ""); + auto& body = doc.doc; + + document current_owner_index; + current_owner_index << "current_owner" << 1; + doc.indexes_to_create.push_back(std::move(current_owner_index)); + + document open_owner_index; + open_owner_index << "open_owner_id" << 1; + doc.indexes_to_create.push_back(std::move(open_owner_index)); + + format_value(body, "current_owner", op.current_owner); + format_oid(body, "current_owner_id", op.current_owner); + format_value(body, "current_orderid", op.current_orderid); + format_value(body, "current_pays", op.current_pays); + format_value(body, "open_owner", op.open_owner); + format_oid(body, "open_owner_id", op.open_owner); + format_value(body, "open_orderid", op.open_orderid); + format_value(body, "open_pays", op.open_pays); + + all_docs.push_back(std::move(doc)); + } + catch (...) { + // + } } auto state_writer::operator()(const shutdown_witness_operation& op) -> result_type { @@ -1336,7 +1534,18 @@ namespace mongo_db { } auto state_writer::operator()(const fill_transfer_from_savings_operation& op) -> result_type { - + try { + format_account(op.from); + format_account(op.to); + db_.get_savings_withdraw(op.from, op.request_id); + } catch (...) { + auto oid = std::string(op.from).append("/").append(std::to_string(op.request_id)); + auto oid_hash = hash_oid(oid); + + auto doc = create_removal_document("savings_withdraw_object", "_id", oid_hash); + + bmi_insert_or_replace(all_docs, std::move(doc)); + } } auto state_writer::operator()(const hardfork_operation& op) -> result_type { From 951b2ba255f90eb3d716edd148d331b67dc65b79 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Fri, 13 Jul 2018 11:46:40 +0300 Subject: [PATCH 055/250] Fixed tests. Added few mehtods to social_network. #796 --- libraries/api/CMakeLists.txt | 1 + libraries/api/comment_api_object.cpp | 45 +++++++++++++ .../include/golos/api/comment_api_object.hpp | 39 +---------- .../social_network/comment_content_object.hpp | 67 +++++++++++++++++++ .../plugins/social_network/social_network.hpp | 63 +++-------------- plugins/social_network/social_network.cpp | 33 +++++++++ tests/CMakeLists.txt | 4 +- tests/common/database_fixture.cpp | 5 +- tests/common/database_fixture.hpp | 2 + tests/tests/operation_tests.cpp | 3 +- 10 files changed, 166 insertions(+), 96 deletions(-) create mode 100644 libraries/api/comment_api_object.cpp create mode 100644 plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp diff --git a/libraries/api/CMakeLists.txt b/libraries/api/CMakeLists.txt index b7efed09ef..972a068b78 100644 --- a/libraries/api/CMakeLists.txt +++ b/libraries/api/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND CURRENT_TARGET_SOURCES discussion_helper.cpp chain_api_properties.cpp witness_api_object.cpp + comment_api_object.cpp ) if(BUILD_SHARED_LIBRARIES) diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp new file mode 100644 index 0000000000..2b9500c225 --- /dev/null +++ b/libraries/api/comment_api_object.cpp @@ -0,0 +1,45 @@ +#include + +namespace golos { namespace api { + + using namespace golos::chain; + comment_api_object::comment_api_object(const comment_api_object& o ) { + id = o.id; + parent_author = o.parent_author; + parent_permlink = o.parent_permlink; + author = o.author; + permlink = o.permlink; + last_update = o.last_update; + created = o.created; + active = o.active; + last_payout = o.last_payout; + depth = o.depth; + children = o.children; + children_rshares2 = o.children_rshares2; + net_rshares = o.net_rshares; + abs_rshares = o.abs_rshares; + vote_rshares = o.vote_rshares; + children_abs_rshares = o.children_abs_rshares; + cashout_time = o.cashout_time; + max_cashout_time = o.max_cashout_time; + total_vote_weight = o.total_vote_weight; + reward_weight = o.reward_weight; + total_payout_value = o.total_payout_value; + curator_payout_value = o.curator_payout_value; + author_rewards = o.author_rewards; + net_votes = o.net_votes; + mode = o.mode; + root_comment = o.root_comment; + max_accepted_payout = o.max_accepted_payout; + percent_steem_dollars = o.percent_steem_dollars; + allow_replies = o.allow_replies; + allow_votes = o.allow_votes; + allow_curation_rewards = o.allow_curation_rewards; + beneficiaries = o.beneficiaries; + title = o.title; + body = o.body; + json_metadata = o.json_metadata; + category = o.category; + } + +} } //golos::api \ No newline at end of file diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 20124b4d59..051cc581e5 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -11,44 +11,7 @@ namespace golos { namespace api { struct comment_api_object { comment_api_object() = default; - comment_api_object(const comment_api_object& o ) { - id = o.id; - parent_author = o.parent_author; - parent_permlink = o.parent_permlink; - author = o.author; - permlink = o.permlink; - last_update = o.last_update; - created = o.created; - active = o.active; - last_payout = o.last_payout; - depth = o.depth; - children = o.children; - children_rshares2 = o.children_rshares2; - net_rshares = o.net_rshares; - abs_rshares = o.abs_rshares; - vote_rshares = o.vote_rshares; - children_abs_rshares = o.children_abs_rshares; - cashout_time = o.cashout_time; - max_cashout_time = o.max_cashout_time; - total_vote_weight = o.total_vote_weight; - reward_weight = o.reward_weight; - total_payout_value = o.total_payout_value; - curator_payout_value = o.curator_payout_value; - author_rewards = o.author_rewards; - net_votes = o.net_votes; - mode = o.mode; - root_comment = o.root_comment; - max_accepted_payout = o.max_accepted_payout; - percent_steem_dollars = o.percent_steem_dollars; - allow_replies = o.allow_replies; - allow_votes = o.allow_votes; - allow_curation_rewards = o.allow_curation_rewards; - beneficiaries = o.beneficiaries; - title = o.title; - body = o.body; - json_metadata = o.json_metadata; - category = o.category; - } + comment_api_object(const comment_api_object& o ); comment_object::id_type id; diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp new file mode 100644 index 0000000000..d9d1ef4e44 --- /dev/null +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +namespace golos { namespace plugins { namespace social_network { + using plugins::json_rpc::msg_pack; + using golos::api::discussion; + using golos::api::account_vote; + using golos::api::vote_state; + using golos::api::get_comment_content_res; + using namespace golos::chain; + + #ifndef SOCIAL_NETWORK_SPACE_ID + #define SOCIAL_NETWORK_SPACE_ID 23 + #endif + + enum social_network_types { + comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 + }; + + + class comment_content_object + : public object { + public: + comment_content_object() = delete; + + template + comment_content_object(Constructor &&c, allocator a) + :title(a), body(a), json_metadata(a) { + c(*this); + } + + id_type id; + + comment_id_type comment; + + shared_string title; + shared_string body; + shared_string json_metadata; + + uint32_t block_number; + }; + + + using comment_content_id_type = object_id; + + struct by_comment; + struct by_block_number; + + typedef multi_index_container< + comment_content_object, + indexed_by< + ordered_unique, member>, + ordered_unique, member>, + ordered_unique, member> + >, // TODO fix code style!! + allocator + > comment_content_index; +} } } + + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::social_network::comment_content_object, + golos::plugins::social_network::comment_content_index +) \ No newline at end of file diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index e84046b7f8..ae7ffb6ea6 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -7,7 +7,7 @@ #include #include #include - +#include namespace golos { namespace plugins { namespace social_network { using plugins::json_rpc::msg_pack; @@ -16,6 +16,7 @@ namespace golos { namespace plugins { namespace social_network { using golos::api::vote_state; using golos::api::get_comment_content_res; using namespace golos::chain; + using golos::api::comment_api_object; DEFINE_API_ARGS(get_content, msg_pack, discussion) DEFINE_API_ARGS(get_content_replies, msg_pack, std::vector) @@ -55,66 +56,18 @@ namespace golos { namespace plugins { namespace social_network { void plugin_startup() override; void plugin_shutdown() override; - private: - struct impl; - std::unique_ptr pimpl; - }; - - get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o); - -#ifndef SOCIAL_NETWORK_SPACE_ID -#define SOCIAL_NETWORK_SPACE_ID 23 -#endif - - enum social_network_types { - comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 - }; - + comment_api_object create_comment_api_object(const comment_object & o) const; - class comment_content_object - : public object { - public: - comment_content_object() = delete; + const comment_content_object &get_comment_content(const comment_id_type &comment) const ; + const comment_content_object *find_comment_content(const comment_id_type &comment) const ; - template - comment_content_object(Constructor &&c, allocator a) - :title(a), body(a), json_metadata(a) { - c(*this); - } - id_type id; - - comment_id_type comment; - - shared_string title; - shared_string body; - shared_string json_metadata; - - uint32_t block_number; + private: + struct impl; + std::unique_ptr pimpl; }; - - using comment_content_id_type = object_id; - - struct by_comment; - struct by_block_number; - - typedef multi_index_container< - comment_content_object, - indexed_by< - ordered_unique, member>, - ordered_unique, member>, - ordered_unique, member> - >, // TODO fix code style!! - allocator - > comment_content_index; - // Callback which is needed for correct work of discussion_helper get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o); } } } // golos::plugins::social_network - -CHAINBASE_SET_INDEX_TYPE( - golos::plugins::social_network::comment_content_object, - golos::plugins::social_network::comment_content_index -) \ No newline at end of file diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index a5c42c1042..0660f71204 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -127,6 +127,12 @@ namespace golos { namespace plugins { namespace social_network { void on_block(const signed_block &b); + comment_api_object create_comment_api_object(const comment_object & o) const ; + + const comment_content_object &get_comment_content(const comment_id_type &comment) const ; + + const comment_content_object *find_comment_content(const comment_id_type &comment) const ; + private: golos::chain::database& database_; @@ -135,6 +141,25 @@ namespace golos { namespace plugins { namespace social_network { }; + const comment_content_object &social_network::impl::get_comment_content(const comment_id_type &comment) const { + try { + return database().get(comment); + } FC_CAPTURE_AND_RETHROW((comment)) + } + + const comment_content_object &social_network::get_comment_content(const comment_id_type &comment) const { + return pimpl->get_comment_content(comment); + } + + + const comment_content_object *social_network::impl::find_comment_content(const comment_id_type &comment) const { + return database().find(comment); + } + + const comment_content_object *social_network::find_comment_content(const comment_id_type &comment) const { + return pimpl->find_comment_content(comment); + } + discussion social_network::impl::get_discussion(const comment_object& c, uint32_t vote_limit) const { return helper->get_discussion(c, vote_limit); } @@ -430,6 +455,14 @@ namespace golos { namespace plugins { namespace social_network { social_network::~social_network() = default; + comment_api_object social_network::impl::create_comment_api_object(const comment_object & o) const { + return helper->create_comment_api_object(o); + } + + comment_api_object social_network::create_comment_api_object(const comment_object & o) const { + return pimpl->create_comment_api_object(o); + } + void social_network::impl::select_content_replies( std::vector& result, std::string author, std::string permlink, uint32_t limit ) const { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 90facad010..ac2f90369f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries( golos_market_history golos_debug_node golos::api + golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) add_test(NAME chain_test_run COMMAND chain_test) @@ -36,7 +37,7 @@ file(GLOB PLUGIN_TESTS "plugin_tests/market_history.cpp" "plugin_tests/plugin_ops.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) -target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node fc ${PLATFORM_SPECIFIC_LIBS}) +target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") add_test(NAME plugin_test_run COMMAND plugin_test) @@ -55,6 +56,7 @@ macro(add_exec_test) golos_account_history golos_market_history golos_debug_node + golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories("${GET_NAME}_test" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") add_test(NAME "${GET_NAME}_test_run" COMMAND "${GET_NAME}_test") diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index b449a60313..af23027fa7 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -276,12 +276,14 @@ namespace golos { namespace chain { ch_plugin = &appbase::app().register_plugin(); oh_plugin = &appbase::app().register_plugin(); ah_plugin = &appbase::app().register_plugin(); + sn_plugin = &appbase::app().register_plugin(); db_plugin = &appbase::app().register_plugin(); appbase::app().initialize< golos::plugins::chain::plugin, account_history::plugin, - debug_node::plugin + debug_node::plugin, + golos::plugins::social_network::social_network >( argc, argv ); db_plugin->set_logging(false); @@ -312,6 +314,7 @@ namespace golos { namespace chain { oh_plugin->plugin_startup(); ah_plugin->plugin_startup(); db_plugin->plugin_startup(); + sn_plugin->plugin_startup(); validate_database(); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 63250babf5..fdfb46082b 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -170,6 +171,7 @@ namespace golos { namespace chain { golos::plugins::debug_node::plugin *db_plugin = nullptr; golos::plugins::operation_history::plugin *oh_plugin = nullptr; golos::plugins::account_history::plugin *ah_plugin = nullptr; + golos::plugins::social_network::social_network *sn_plugin = nullptr; optional data_dir; bool skip_key_index_test = false; diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 3612ab4afc..3f0d885807 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -23,6 +23,7 @@ using namespace golos; using namespace golos::api; using namespace golos::chain; using namespace golos::protocol; +using golos::plugins::social_network::comment_content_object; using std::string; BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) @@ -436,7 +437,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) db->push_transaction(tx, 0); const comment_object &alice_comment = db->get_comment("alice", string("lorem")); - const comment_content_object& alice_content = db->get_comment_content(alice_comment.id); + const comment_content_object& alice_content = sn_plugin->get_comment_content(alice_comment.id); BOOST_REQUIRE(alice_comment.author == op.author); BOOST_REQUIRE(to_string(alice_comment.permlink) == op.permlink); From 920948811a58afd56ae2529707cc47cb4ace51de Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 4 Jul 2018 18:40:56 +0300 Subject: [PATCH 056/250] Add producer_reward_operation #743 --- libraries/chain/database.cpp | 74 +++++++------------ .../chain/include/golos/chain/database.hpp | 6 +- .../include/golos/protocol/operations.hpp | 3 +- .../protocol/steem_virtual_operations.hpp | 9 +++ plugins/account_history/plugin.cpp | 4 + 5 files changed, 43 insertions(+), 53 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 37284f7ed4..1fc30874d1 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2417,8 +2417,11 @@ namespace golos { namespace chain { * This method pays out vesting, reward shares and witnesses every block. */ void database::process_funds() { - const auto &props = get_dynamic_global_properties(); - const auto &wso = get_witness_schedule_object(); + const auto& wso = get_witness_schedule_object(); + const auto& props = get_dynamic_global_properties(); + const auto& cwit = get_witness(props.current_witness); + const auto& wacc = get_account(cwit.owner); + optional producer_reward; if (has_hardfork(STEEMIT_HARDFORK_0_16__551)) { /** @@ -2445,8 +2448,6 @@ namespace golos { namespace chain { (new_steem * STEEMIT_VESTING_FUND_PERCENT) / STEEMIT_100_PERCENT; /// 26.67% to vesting fund auto witness_reward = new_steem - content_reward - vesting_reward; /// Remaining 6.66% to witness pay - - const auto &cwit = get_witness(props.current_witness); witness_reward *= STEEMIT_MAX_WITNESSES; if (cwit.schedule == witness_object::timeshare) { @@ -2470,13 +2471,21 @@ namespace golos { namespace chain { p.virtual_supply += asset(new_steem, STEEM_SYMBOL); }); - create_vesting(get_account(cwit.owner), asset(witness_reward, STEEM_SYMBOL)); + producer_reward = create_vesting(wacc, asset(witness_reward, STEEM_SYMBOL)); } else { + auto witness_pay = get_producer_reward(); + /// pay witness in vesting shares + if (props.head_block_number >= STEEMIT_START_MINER_VOTING_BLOCK || (wacc.vesting_shares.amount == 0)) { + producer_reward = create_vesting(wacc, witness_pay); + } else { + modify(wacc, [&](account_object &a) { + a.balance += witness_pay; + }); + } + auto content_reward = get_content_reward(); auto curate_reward = get_curation_reward(); - auto witness_pay = get_producer_reward(); auto vesting_reward = content_reward + curate_reward + witness_pay; - content_reward = content_reward + curate_reward; if (props.head_block_number < STEEMIT_START_VESTING_BLOCK) { @@ -2485,13 +2494,16 @@ namespace golos { namespace chain { vesting_reward.amount.value *= 9; } - modify(props, [&](dynamic_global_property_object &p) { + modify(props, [&](dynamic_global_property_object& p) { p.total_vesting_fund_steem += vesting_reward; p.total_reward_fund_steem += content_reward; p.current_supply += content_reward + witness_pay + vesting_reward; p.virtual_supply += content_reward + witness_pay + vesting_reward; }); } + + if (producer_reward) + push_virtual_operation(producer_reward_operation(wacc.name, *producer_reward)); } void database::process_savings_withdraws() { @@ -2552,47 +2564,15 @@ namespace golos { namespace chain { return reward; } - asset database::get_producer_reward() { - const auto &props = get_dynamic_global_properties(); - static_assert(STEEMIT_BLOCK_INTERVAL == - 3, "this code assumes a 3-second time interval"); + asset database::get_producer_reward() const { + static_assert(STEEMIT_BLOCK_INTERVAL == 3, "this code assumes a 3-second time interval"); + const auto& props = get_dynamic_global_properties(); asset percent(protocol::calc_percent_reward_per_block(props.virtual_supply.amount), STEEM_SYMBOL); - const auto &witness_account = get_account(props.current_witness); - - if (has_hardfork(STEEMIT_HARDFORK_0_16)) { - auto pay = std::max(percent, STEEMIT_MIN_PRODUCER_REWARD); - - /// pay witness in vesting shares - if (props.head_block_number >= - STEEMIT_START_MINER_VOTING_BLOCK || - (witness_account.vesting_shares.amount.value == 0)) { - // const auto& witness_obj = get_witness( props.current_witness ); - create_vesting(witness_account, pay); - } else { - modify(get_account(witness_account.name), [&](account_object &a) { - a.balance += pay; - }); - } - - return pay; - } else { - auto pay = std::max(percent, STEEMIT_MIN_PRODUCER_REWARD_PRE_HF_16); - - /// pay witness in vesting shares - if (props.head_block_number >= - STEEMIT_START_MINER_VOTING_BLOCK || - (witness_account.vesting_shares.amount.value == 0)) { - // const auto& witness_obj = get_witness( props.current_witness ); - create_vesting(witness_account, pay); - } else { - modify(get_account(witness_account.name), [&](account_object &a) { - a.balance += pay; - }); - } - - return pay; - } + // why this needed? the method called only before hf16 + auto min_reward = has_hardfork(STEEMIT_HARDFORK_0_16) ? STEEMIT_MIN_PRODUCER_REWARD : STEEMIT_MIN_PRODUCER_REWARD_PRE_HF_16; + auto pay = std::max(percent, min_reward); + return pay; } asset database::get_pow_reward() const { diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index e463db5eb6..af744b2a1e 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -432,13 +432,9 @@ namespace golos { namespace chain { share_type claim_rshare_reward(share_type rshares, uint16_t reward_weight, asset max_steem); asset get_liquidity_reward() const; - asset get_content_reward() const; - - asset get_producer_reward(); - + asset get_producer_reward() const; asset get_curation_reward() const; - asset get_pow_reward() const; uint16_t get_curation_rewards_percent() const; diff --git a/libraries/protocol/include/golos/protocol/operations.hpp b/libraries/protocol/include/golos/protocol/operations.hpp index 59e1511068..0bed9b25df 100644 --- a/libraries/protocol/include/golos/protocol/operations.hpp +++ b/libraries/protocol/include/golos/protocol/operations.hpp @@ -81,7 +81,8 @@ namespace golos { namespace protocol { hardfork_operation, comment_payout_update_operation, comment_benefactor_reward_operation, - return_vesting_delegation_operation + return_vesting_delegation_operation, + producer_reward_operation > operation; /*void operation_get_required_authorities( const operation& op, diff --git a/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp b/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp index a990f38985..a6a45e1171 100644 --- a/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp @@ -187,6 +187,14 @@ namespace golos { namespace protocol { asset reward; }; + struct producer_reward_operation : public virtual_operation { + producer_reward_operation() {} + producer_reward_operation(const string& p, const asset& v) : producer(p), vesting_shares(v) {} + + account_name_type producer; + asset vesting_shares; + }; + struct return_vesting_delegation_operation: public virtual_operation { return_vesting_delegation_operation() { } @@ -213,3 +221,4 @@ FC_REFLECT((golos::protocol::hardfork_operation), (hardfork_id)) FC_REFLECT((golos::protocol::comment_payout_update_operation), (author)(permlink)) FC_REFLECT((golos::protocol::comment_benefactor_reward_operation), (benefactor)(author)(permlink)(reward)) FC_REFLECT((golos::protocol::return_vesting_delegation_operation), (account)(vesting_shares)) +FC_REFLECT((golos::protocol::producer_reward_operation), (producer)(vesting_shares)) diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 05fba3494c..b4795a1cbc 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -341,6 +341,10 @@ if( options.count(name) ) { \ impacted.insert(op.author); } + void operator()(const producer_reward_operation& op) { + impacted.insert(op.producer); + } + void operator()(const delegate_vesting_shares_operation& op) { impacted.insert(op.delegator); impacted.insert(op.delegatee); From 2fcd5cbb233ba69e8d693fe81de91d8cbef5dbb2 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 9 Jul 2018 10:20:46 +0300 Subject: [PATCH 057/250] Add virtual operations to block_applied_callback #743 --- .../golos/chain/operation_notification.hpp | 34 ++-- .../protocol/include/golos/protocol/block.hpp | 14 +- .../include/golos/protocol/transaction.hpp | 6 +- plugins/database_api/api.cpp | 185 +++++++++++------- .../golos/plugins/database_api/plugin.hpp | 2 +- .../golos/plugins/json_rpc/utility.hpp | 9 +- 6 files changed, 139 insertions(+), 111 deletions(-) diff --git a/libraries/chain/include/golos/chain/operation_notification.hpp b/libraries/chain/include/golos/chain/operation_notification.hpp index a235c77db5..4fd34c5acd 100644 --- a/libraries/chain/include/golos/chain/operation_notification.hpp +++ b/libraries/chain/include/golos/chain/operation_notification.hpp @@ -1,26 +1,24 @@ #pragma once #include - #include -namespace golos { - using protocol::operation; - namespace chain { - - struct operation_notification { - operation_notification(const operation &o) : op(o) { - } +namespace golos { namespace chain { - bool stored_in_db = false; - int64_t db_id = 0; - transaction_id_type trx_id; - uint32_t block = 0; - uint32_t trx_in_block = 0; - uint16_t op_in_trx = 0; - uint32_t virtual_op = 0; - const operation &op; - }; +using protocol::operation; +struct operation_notification { + operation_notification(const operation &o) : op(o) { } -} + + bool stored_in_db = false; + int64_t db_id = 0; + transaction_id_type trx_id; + uint32_t block = 0; + uint32_t trx_in_block = 0; + uint16_t op_in_trx = 0; + uint32_t virtual_op = 0; + const operation &op; +}; + +} } // golos::chain diff --git a/libraries/protocol/include/golos/protocol/block.hpp b/libraries/protocol/include/golos/protocol/block.hpp index 19c19d0f17..9ea860d8c9 100644 --- a/libraries/protocol/include/golos/protocol/block.hpp +++ b/libraries/protocol/include/golos/protocol/block.hpp @@ -3,16 +3,14 @@ #include #include -namespace golos { - namespace protocol { +namespace golos { namespace protocol { - struct signed_block : public signed_block_header { - checksum_type calculate_merkle_root() const; +struct signed_block : public signed_block_header { + checksum_type calculate_merkle_root() const; - vector transactions; - }; + vector transactions; +}; - } -} // golos::protocol +} } // golos::protocol FC_REFLECT_DERIVED((golos::protocol::signed_block), ((golos::protocol::signed_block_header)), (transactions)) diff --git a/libraries/protocol/include/golos/protocol/transaction.hpp b/libraries/protocol/include/golos/protocol/transaction.hpp index 90841ac765..a6b7238b4f 100644 --- a/libraries/protocol/include/golos/protocol/transaction.hpp +++ b/libraries/protocol/include/golos/protocol/transaction.hpp @@ -6,8 +6,7 @@ #include -namespace golos { - namespace protocol { +namespace golos { namespace protocol { struct transaction { uint16_t ref_block_num = 0; @@ -127,8 +126,7 @@ namespace golos { /// @} transactions group - } -} // golos::protocol +} } // golos::protocol FC_REFLECT((golos::protocol::transaction), (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) FC_REFLECT_DERIVED((golos::protocol::signed_transaction), ((golos::protocol::transaction)), (signatures)) diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index 6fa3ea69e0..b8a77e13de 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -1,16 +1,15 @@ #include - +#include #include - #include +#include -#include +// #include #include #include #include #include -#include #define GET_REQUIRED_FEES_MAX_RECURSION 4 @@ -31,15 +30,14 @@ struct block_applied_callback_info { cont::iterator it; void connect( - boost::signals2::signal &sig, - cont &free_cont, + boost::signals2::signal& sig, + cont& free_cont, block_applied_callback cb ) { callback = cb; - - connection = sig.connect([this, &free_cont](const signed_block &block) { + connection = sig.connect([this, &free_cont](const signed_block& block) { try { - this->callback(fc::variant(block)); + this->callback(block); } catch (...) { free_cont.push_back(*this->it); this->connection.disconnect(); @@ -48,6 +46,8 @@ struct block_applied_callback_info { } }; +// maybe change to applied_operation, so it contain tx_num +using block_operations = std::vector; struct plugin::api_impl final { public: @@ -58,11 +58,12 @@ struct plugin::api_impl final { } // Subscriptions - void set_subscribe_callback(std::function cb, bool clear_filter); - void set_pending_transaction_callback(std::function cb); + // void set_subscribe_callback(std::function cb, bool clear_filter); + void set_pending_transaction_callback(std::function cb); void set_block_applied_callback(block_applied_callback cb); void clear_block_applied_callback(); - void cancel_all_subscriptions(); + // void cancel_all_subscriptions(); + void op_applied_callback(const operation_notification& o); // Blocks and transactions optional get_block_header(uint32_t block_num) const; @@ -88,29 +89,28 @@ struct plugin::api_impl final { std::vector get_withdraw_routes(std::string account, withdraw_route_type type) const; std::vector get_proposed_transactions(const std::string&, uint32_t, uint32_t) const; - template - void subscribe_to_item(const T &i) const { - auto vec = fc::raw::pack(i); - if (!_subscribe_callback) { - return; - } - - if (!is_subscribed_to_item(i)) { - idump((i)); - _subscribe_filter.insert(vec.data(), vec.size()); - } - } - - template - bool is_subscribed_to_item(const T &i) const { - if (!_subscribe_callback) { - return false; - } - - return _subscribe_filter.contains(i); - } - - mutable fc::bloom_filter _subscribe_filter; + // template + // void subscribe_to_item(const T &i) const { + // auto vec = fc::raw::pack(i); + // if (!_subscribe_callback) { + // return; + // } + + // if (!is_subscribed_to_item(i)) { + // idump((i)); + // _subscribe_filter.insert(vec.data(), vec.size()); + // } + // } + + // template + // bool is_subscribed_to_item(const T &i) const { + // if (!_subscribe_callback) { + // return false; + // } + // return _subscribe_filter.contains(i); + // } + + // mutable fc::bloom_filter _subscribe_filter; std::function _subscribe_callback; std::function _pending_trx_callback; @@ -125,42 +125,49 @@ struct plugin::api_impl final { block_applied_callback_info::cont active_block_applied_callback; block_applied_callback_info::cont free_block_applied_callback; + block_operations& get_block_vops(uint32_t block_num) { + if (block_num == _block_virtual_ops_block_num) { + return _block_virtual_ops; + } else { + elog("Trying get operations for wrong block: ${b}", ("b", block_num)("_block", _block_virtual_ops_block_num)); + return _block_virtual_ops; //!!! TODO: return empty or assert + } + } + private: + golos::chain::database& _db; - golos::chain::database &_db; + uint32_t _block_virtual_ops_block_num = 0; + block_operations _block_virtual_ops; }; -//void find_accounts(std::set &accounts, const discussion &d) { -// accounts.insert(d.author); -//} - ////////////////////////////////////////////////////////////////////// // // // Subscriptions // // // ////////////////////////////////////////////////////////////////////// -void plugin::set_subscribe_callback(std::function cb, bool clear_filter) { - my->database().with_weak_read_lock([&]() { - my->set_subscribe_callback(cb, clear_filter); - }); -} - -void plugin::api_impl::set_subscribe_callback( - std::function cb, - bool clear_filter -) { - _subscribe_callback = cb; - if (clear_filter || !cb) { - static fc::bloom_parameters param; - param.projected_element_count = 10000; - param.false_positive_probability = 1.0 / 10000; - param.maximum_size = 1024 * 8 * 8 * 2; - param.compute_optimal_parameters(); - _subscribe_filter = fc::bloom_filter(param); - } -} +// void plugin::set_subscribe_callback(std::function cb, bool clear_filter) { +// my->database().with_weak_read_lock([&]() { +// my->set_subscribe_callback(cb, clear_filter); +// }); +// } + +// void plugin::api_impl::set_subscribe_callback( +// std::function cb, +// bool clear_filter +// ) { +// _subscribe_callback = cb; +// if (clear_filter || !cb) { +// static fc::bloom_parameters param; +// param.projected_element_count = 10000; +// param.false_positive_probability = 1.0 / 10000; +// param.maximum_size = 1024 * 8 * 8 * 2; +// param.compute_optimal_parameters(); +// _subscribe_filter = fc::bloom_filter(param); +// } +// } void plugin::set_pending_transaction_callback(std::function cb) { my->database().with_weak_read_lock([&]() { @@ -172,15 +179,15 @@ void plugin::api_impl::set_pending_transaction_callback(std::functiondatabase().with_weak_read_lock([&]() { - my->cancel_all_subscriptions(); - }); -} +// void plugin::cancel_all_subscriptions() { +// my->database().with_weak_read_lock([&]() { +// my->cancel_all_subscriptions(); +// }); +// } -void plugin::api_impl::cancel_all_subscriptions() { - set_subscribe_callback(std::function(), true); -} +// void plugin::api_impl::cancel_all_subscriptions() { +// set_subscribe_callback(std::function(), true); +// } ////////////////////////////////////////////////////////////////////// // // @@ -235,15 +242,28 @@ optional plugin::api_impl::get_block(uint32_t block_num) const { return database().fetch_block_by_number(block_num); } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +struct block_with_vops : public signed_block { + block_with_vops(signed_block b, block_operations ops): signed_block(b), _virtual_operations(ops) { + }; + + // name field starting with _ coz it's not directly related to block + block_operations _virtual_operations; +}; + DEFINE_API(plugin, set_block_applied_callback) { - CHECK_ARG_SIZE(1) + CHECK_ARG_SIZE(1); // argument not used now // Delegate connection handlers to callback msg_pack_transfer transfer(args); my->database().with_weak_read_lock([&]{ - my->set_block_applied_callback([msg = transfer.msg()](const fc::variant & block_header) { - msg->unsafe_result(fc::variant(block_header)); + my->set_block_applied_callback([this,msg = transfer.msg()](const signed_block& block) { + auto ops = my->get_block_vops(block.block_num()); + msg->unsafe_result( + ops.size() ? fc::variant(block_with_vops(block, ops)) : fc::variant(block) + ); }); }); @@ -252,7 +272,7 @@ DEFINE_API(plugin, set_block_applied_callback) { return {}; } -void plugin::api_impl::set_block_applied_callback(std::function callback) { +void plugin::api_impl::set_block_applied_callback(block_applied_callback callback) { auto info_ptr = std::make_shared(); active_block_applied_callback.push_back(info_ptr); @@ -272,6 +292,16 @@ void plugin::clear_block_applied_callback() { my->clear_block_applied_callback(); } +void plugin::api_impl::op_applied_callback(const operation_notification& o) { + if (o.block != _block_virtual_ops_block_num) { + _block_virtual_ops.clear(); + _block_virtual_ops_block_num = o.block; + } + if (is_virtual_operation(o.op)) { + _block_virtual_ops.push_back(o.op); + } +} + ////////////////////////////////////////////////////////////////////// // // // Globals // @@ -843,13 +873,17 @@ DEFINE_API(plugin, get_proposed_transactions) { }); } -void plugin::plugin_initialize(const boost::program_options::variables_map &options) { +void plugin::plugin_initialize(const boost::program_options::variables_map& options) { ilog("database_api plugin: plugin_initialize() begin"); my = std::make_unique(); JSON_RPC_REGISTER_API(plugin_name) - my->database().applied_block.connect([this](const protocol::signed_block &) { + auto& db = my->database(); + db.applied_block.connect([this](const protocol::signed_block&) { this->clear_block_applied_callback(); }); + db.pre_apply_operation.connect([&](const operation_notification& o) { + my->op_applied_callback(o); + }); ilog("database_api plugin: plugin_initialize() end"); } @@ -858,3 +892,6 @@ void plugin::plugin_startup() { } } } } // golos::plugins::database_api + +FC_REFLECT_DERIVED((golos::plugins::database_api::block_with_vops), ((golos::protocol::signed_block)), + (_virtual_operations)) diff --git a/plugins/database_api/include/golos/plugins/database_api/plugin.hpp b/plugins/database_api/include/golos/plugins/database_api/plugin.hpp index 1ad7997d4b..f734670a80 100755 --- a/plugins/database_api/include/golos/plugins/database_api/plugin.hpp +++ b/plugins/database_api/include/golos/plugins/database_api/plugin.hpp @@ -94,7 +94,7 @@ struct signed_block_api_object : public signed_block { }; -using block_applied_callback = std::function; +using block_applied_callback = std::function; /// API, args, return DEFINE_API_ARGS(get_block_header, msg_pack, optional) diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp index fdd91db26d..080052a9a3 100644 --- a/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/utility.hpp @@ -40,9 +40,8 @@ BOOST_PP_CAT( method, _return ) method( BOOST_PP_CAT( method, _args )& ); #define DEFINE_API(class, api_name) \ api_name ## _return class :: api_name ( api_name ## _args& args ) -namespace golos { - namespace plugins { - namespace json_rpc { +namespace golos { namespace plugins { namespace json_rpc { + class msg_pack final { public: fc::variant id; @@ -124,8 +123,6 @@ namespace golos { struct void_type { }; - } - } -} // golos::plugins::json_rpc +} } } // golos::plugins::json_rpc FC_REFLECT((golos::plugins::json_rpc::void_type),) From ac1c973342170bc9d9fb3f89161f48d8ad49b6eb Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Tue, 10 Jul 2018 11:10:57 +0300 Subject: [PATCH 058/250] Fix tests after adding producer_reward virtual op #743 1. Templated get_last_operations() to get only required operations 2. Fix "Increase shared file size immediately" spam while testing 3. Minor fixes to conform code style --- libraries/chain/database.cpp | 2 +- .../chain/include/golos/chain/database.hpp | 2 +- libraries/wallet/wallet.cpp | 9 ++- plugins/account_history/plugin.cpp | 2 +- tests/common/database_fixture.cpp | 34 ++++----- tests/common/database_fixture.hpp | 70 +++++++++++-------- tests/tests/operation_time_tests.cpp | 10 ++- 7 files changed, 67 insertions(+), 62 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 1fc30874d1..4b847084d2 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -437,7 +437,7 @@ namespace golos { namespace chain { if (free_gb == 0) { uint32_t free_mb = uint32_t(free_mem / (1024 * 1024)); - if (free_mb <= 500 && current_block_num % 10 == 0) { + if (free_mb <= (_is_testing ? 2 : 500) && current_block_num % 10 == 0) { elog("Free memory is now ${n}M. Increase shared file size immediately!", ("n", free_mb)); } } diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index af744b2a1e..6aa9d91026 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -49,7 +49,7 @@ namespace golos { namespace chain { } bool _is_producing = false; - + bool _is_testing = false; ///< set for tests to avoid low free memory spam bool _log_hardforks = true; enum validation_steps { diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 24b83f1b6e..4bb00c3476 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1371,7 +1371,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } else { accounts.push_back(get_account(account)); } - + for (auto it = accounts.begin(); it != accounts.end(); it++) { key_with_data memo_key_data; memo_key_data.public_key = std::string(it->memo_key); @@ -1381,7 +1381,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st all_keys.push_back(memo_key_data); auto acc_owner_keys = it->owner.get_keys(); - for (auto it2 = acc_owner_keys.begin(); it2 != acc_owner_keys.end(); it2++) { + for (auto it2 = acc_owner_keys.begin(); it2 != acc_owner_keys.end(); it2++) { key_with_data key_data; key_data.public_key = std::string(*it2); key_data.private_key = get_private_key(*it2); @@ -1391,7 +1391,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } auto acc_active_keys = it->active.get_keys(); - for (auto it2 = acc_active_keys.begin(); it2 != acc_active_keys.end(); it2++) { + for (auto it2 = acc_active_keys.begin(); it2 != acc_active_keys.end(); it2++) { key_with_data key_data; key_data.public_key = std::string(*it2); key_data.private_key = get_private_key(*it2); @@ -1401,7 +1401,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } auto acc_posting_keys = it->posting.get_keys(); - for (auto it2 = acc_posting_keys.begin(); it2 != acc_posting_keys.end(); it2++) { + for (auto it2 = acc_posting_keys.begin(); it2 != acc_posting_keys.end(); it2++) { key_with_data key_data; key_data.public_key = std::string(*it2); key_data.private_key = get_private_key(*it2); @@ -2618,4 +2618,3 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } } } // steem::wallet - diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index b4795a1cbc..ea0ce46f94 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -26,7 +26,7 @@ T dejsonify(const string &s) { #define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value)) #define LOAD_VALUE_SET(options, name, container, type) \ -if( options.count(name) ) { \ +if (options.count(name)) { \ const std::vector& ops = options[name].as>(); \ std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &dejsonify); \ } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 265cc28941..414cf65515 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -1,9 +1,8 @@ #include #include -#include #include - +#include #include #include @@ -12,7 +11,6 @@ #include "database_fixture.hpp" -//using namespace golos::chain::test; #define STEEM_NAMESPACE_PREFIX std::string("golos::protocol::") @@ -301,7 +299,7 @@ namespace golos { namespace chain { void database_fixture::initialize() { int argc = boost::unit_test::framework::master_test_suite().argc; - char **argv = boost::unit_test::framework::master_test_suite().argv; + char** argv = boost::unit_test::framework::master_test_suite().argv; for (int i = 1; i < argc; i++) { const std::string arg = argv[i]; if (arg == "--record-assert-trip") { @@ -320,15 +318,15 @@ namespace golos { namespace chain { db_plugin = &appbase::app().register_plugin(); appbase::app().initialize< - golos::plugins::chain::plugin, - account_history::plugin, - debug_node::plugin - >( argc, argv ); + golos::plugins::chain::plugin, + account_history::plugin, + debug_node::plugin + >(argc, argv); db_plugin->set_logging(false); db = &ch_plugin->db(); - BOOST_REQUIRE( db ); + BOOST_REQUIRE(db); } void database_fixture::startup(bool generate_hardfork) { @@ -341,13 +339,13 @@ namespace golos { namespace chain { vest(STEEMIT_INIT_MINER_NAME, 10000); // Fill up the rest of the required miners - for (int i = STEEMIT_NUM_INIT_MINERS; - i < STEEMIT_MAX_WITNESSES; i++) { + for (int i = STEEMIT_NUM_INIT_MINERS; i < STEEMIT_MAX_WITNESSES; i++) { account_create(STEEMIT_INIT_MINER_NAME + fc::to_string(i), init_account_pub_key); fund(STEEMIT_INIT_MINER_NAME + fc::to_string(i), STEEMIT_MIN_PRODUCER_REWARD.amount.value); - witness_create(STEEMIT_INIT_MINER_NAME + fc::to_string(i), - init_account_priv_key, "foo.bar", init_account_pub_key, - STEEMIT_MIN_PRODUCER_REWARD.amount); + witness_create( + STEEMIT_INIT_MINER_NAME + fc::to_string(i), + init_account_priv_key, "foo.bar", init_account_pub_key, + STEEMIT_MIN_PRODUCER_REWARD.amount); } oh_plugin->plugin_startup(); @@ -361,9 +359,9 @@ namespace golos { namespace chain { if (!data_dir) { data_dir = fc::temp_directory(golos::utilities::temp_directory_path()); db->_log_hardforks = false; + db->_is_testing = true; db->open(data_dir->path(), data_dir->path(), INITIAL_TEST_SUPPLY, - 1024 * 1024 * - 8, chainbase::database::read_write); // 8 MB file for testing + 1024 * 1024 * 10, chainbase::database::read_write); // 10 MB file for testing } } @@ -641,14 +639,12 @@ namespace golos { namespace chain { vector database_fixture::get_last_operations(uint32_t num_ops) { vector ops; - const auto &acc_hist_idx = db->get_index().indices().get(); + const auto& acc_hist_idx = db->get_index().indices().get(); auto itr = acc_hist_idx.end(); - while (itr != acc_hist_idx.begin() && ops.size() < num_ops) { itr--; ops.push_back(fc::raw::unpack(db->get(itr->op).serialized_op)); } - return ops; } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index acdd18699f..f2e95edaf5 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -27,15 +27,13 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); golos::chain::test::_push_block // See below -#define REQUIRE_OP_VALIDATION_SUCCESS(op, field, value) \ -{ \ +#define REQUIRE_OP_VALIDATION_SUCCESS(op, field, value) { \ const auto temp = op.field; \ op.field = value; \ op.validate(); \ op.field = temp; \ } -#define REQUIRE_OP_EVALUATION_SUCCESS(op, field, value) \ -{ \ +#define REQUIRE_OP_EVALUATION_SUCCESS(op, field, value) { \ const auto temp = op.field; \ op.field = value; \ trx.operations.back() = op; \ @@ -43,8 +41,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); db.push_transaction( trx, ~0 ); \ } -/*#define STEEMIT_REQUIRE_THROW( expr, exc_type ) \ -{ \ +/*#define STEEMIT_REQUIRE_THROW( expr, exc_type ) { \ std::string req_throw_info = fc::json::to_string( \ fc::mutable_variant_object() \ ("source_file", __FILE__) \ @@ -64,8 +61,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); #define STEEMIT_REQUIRE_THROW(expr, exc_type) \ BOOST_REQUIRE_THROW( expr, exc_type ); -#define STEEMIT_CHECK_THROW(expr, exc_type) \ -{ \ +#define STEEMIT_CHECK_THROW(expr, exc_type) { \ std::string req_throw_info = fc::json::to_string( \ fc::mutable_variant_object() \ ("source_file", __FILE__) \ @@ -74,11 +70,11 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); ("exc_type", #exc_type) \ ); \ if( fc::enable_record_assert_trip ) \ - std::cout << "STEEMIT_CHECK_THROW begin " \ + std::cout << "STEEMIT_CHECK_THROW begin " \ << req_throw_info << std::endl; \ BOOST_CHECK_THROW( expr, exc_type ); \ if( fc::enable_record_assert_trip ) \ - std::cout << "STEEMIT_CHECK_THROW end " \ + std::cout << "STEEMIT_CHECK_THROW end " \ << req_throw_info << std::endl; \ } @@ -171,7 +167,7 @@ struct ErrorValidator { void validate(const std::string& name, const fc::variant& props, golos::logic_exception::error_types err) { BOOST_CHECK_EQUAL(name, "logic_exception"); - BOOST_CHECK_EQUAL(props["errid"].get_string(), + BOOST_CHECK_EQUAL(props["errid"].get_string(), fc::reflector::to_string(err)); } }; @@ -204,10 +200,10 @@ struct ErrorValidator { catch( E const& ex ) { \ ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ BOOST_CHECK_IMPL( true, "exception '" BOOST_STRINGIZE( E ) "' is caught", TL, CHECK_MSG ); \ - const std::string name = ex.name(); \ + const std::string name = ex.name(); \ const fc::variant_object &props = ex.get_log().at(0).get_data(); \ try { \ - C(name, props); \ + C(name, props); \ } catch (const fc::exception& err) { \ BOOST_CHECK_IMPL( false, "caught exception '" << err.name() << "' while check props:" << \ err.to_detail_string(), TL, CHECK_MSG); \ @@ -268,8 +264,8 @@ struct ErrorValidator { // that is why comparision can be done only with some correction #define GOLOS_VEST_REQUIRE_EQUAL(left, right) \ BOOST_REQUIRE( \ - std::abs((left).amount.value - (right).amount.value) < 5 && \ - (left).symbol == (right).symbol \ + std::abs((left).amount.value - (right).amount.value) < 5 && \ + (left).symbol == (right).symbol \ ) @@ -301,20 +297,18 @@ namespace golos { namespace chain { using namespace golos::protocol; struct database_fixture { - // the reason we use an app is to exercise the indexes of built-in - // plugins - chain::database *db; + // the reason we use an app is to exercise the indexes of built-in plugins + chain::database* db; signed_transaction trx; fc::ecc::private_key init_account_priv_key = STEEMIT_INIT_PRIVATE_KEY; string debug_key = golos::utilities::key_to_wif(init_account_priv_key); public_key_type init_account_pub_key = init_account_priv_key.get_public_key(); - uint32_t default_skip = 0 | database::skip_undo_history_check | - database::skip_authority_check; + uint32_t default_skip = 0 | database::skip_undo_history_check | database::skip_authority_check; - golos::plugins::chain::plugin *ch_plugin = nullptr; - golos::plugins::debug_node::plugin *db_plugin = nullptr; - golos::plugins::operation_history::plugin *oh_plugin = nullptr; - golos::plugins::account_history::plugin *ah_plugin = nullptr; + golos::plugins::chain::plugin* ch_plugin = nullptr; + golos::plugins::debug_node::plugin* db_plugin = nullptr; + golos::plugins::operation_history::plugin* oh_plugin = nullptr; + golos::plugins::account_history::plugin* ah_plugin = nullptr; optional data_dir; bool skip_key_index_test = false; @@ -336,9 +330,10 @@ namespace golos { namespace chain { void open_database(); void close_database(); - void generate_block(uint32_t skip = 0, - const fc::ecc::private_key &key = STEEMIT_INIT_PRIVATE_KEY, - int miss_blocks = 0); + void generate_block( + uint32_t skip = 0, + const fc::ecc::private_key& key = STEEMIT_INIT_PRIVATE_KEY, + int miss_blocks = 0); /** * @brief Generates block_count blocks @@ -404,6 +399,23 @@ namespace golos { namespace chain { vector get_last_operations(uint32_t ops); + // we have producer_reward virtual op now, so get_last_operations + // can be hard to use after generate_blocks. + // this get_last_operations variant helps to get only required op type + template + vector get_last_operations(uint32_t num_ops) { + vector ops; + const auto& acc_hist_idx = db->get_index().indices().get(); + auto itr = acc_hist_idx.end(); + while (itr != acc_hist_idx.begin() && ops.size() < num_ops) { + itr--; + auto op = fc::raw::unpack(db->get(itr->op).serialized_op); + if (op.which() == operation::tag::value) + ops.push_back(op.get()); + } + return ops; + } + void validate_database(void); @@ -476,9 +488,9 @@ namespace golos { namespace chain { }; namespace test { - bool _push_block(database &db, const signed_block &b, uint32_t skip_flags = 0); + bool _push_block(database& db, const signed_block& b, uint32_t skip_flags = 0); - void _push_transaction(database &db, const signed_transaction &tx, uint32_t skip_flags = 0); + void _push_transaction(database& db, const signed_transaction& tx, uint32_t skip_flags = 0); } } } // golos:chain diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 07eddf191e..2ac9a02455 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -3,13 +3,11 @@ #include #include - #include #include #include -#include #include - +#include #include #include @@ -923,7 +921,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) } FC_LOG_AND_RETHROW() } - + BOOST_AUTO_TEST_CASE(vesting_withdraw_route) { try { ACTORS((alice)(bob)(sam)) @@ -1932,8 +1930,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) db->head_block_time() + fc::seconds(STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF10.to_seconds() / 2), true); - ops = get_last_operations(1); - fill_order_op = ops[0].get(); + auto fill_ops = get_last_operations(1); + fill_order_op = fill_ops[0]; BOOST_REQUIRE(fill_order_op.open_owner == "alice"); BOOST_REQUIRE(fill_order_op.open_orderid == 6); From d111fd59dee880c792c661d3fc9edf15054faa0c Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Thu, 12 Jul 2018 10:40:41 +0300 Subject: [PATCH 059/250] Add ability to set block_applied_callback data type #743 --- plugins/database_api/api.cpp | 168 ++++++++++++++++------------------- 1 file changed, 77 insertions(+), 91 deletions(-) diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index b8a77e13de..1a8e0c7540 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -4,7 +4,6 @@ #include #include -// #include #include #include @@ -46,8 +45,47 @@ struct block_applied_callback_info { } }; -// maybe change to applied_operation, so it contain tx_num -using block_operations = std::vector; +// block_operation used in block_applied_callback to represent virtual operations. +// default operation type have no position info (trx, on_in_trx) +struct block_operation { + block_operation() = default; + block_operation(const operation_notification& o) : + trx_in_block(o.trx_in_block), + op_in_trx(o.op_in_trx), + virtual_op(o.virtual_op), + op(o.op) {}; + + uint32_t trx_in_block = 0; + uint16_t op_in_trx = 0; + uint32_t virtual_op = 0; + operation op; +}; + +using block_operations = std::vector; + +struct block_with_vops : public signed_block { + block_with_vops(signed_block b, block_operations ops): signed_block(b), _virtual_operations(ops) { + }; + + // name field starting with _ coz it's not directly related to block + block_operations _virtual_operations; +}; + +struct virtual_operations { + virtual_operations(uint32_t block_num, block_operations ops): block_num(block_num), operations(ops) { + }; + + uint32_t block_num; + block_operations operations; +}; + +enum block_applied_callback_result_type { + block = 0, // send signed blocks + header = 1, // send only block headers + virtual_ops = 2, // send only virtual operations + full = 3 // send signed block + virtual operations +}; + struct plugin::api_impl final { public: @@ -58,11 +96,9 @@ struct plugin::api_impl final { } // Subscriptions - // void set_subscribe_callback(std::function cb, bool clear_filter); void set_pending_transaction_callback(std::function cb); void set_block_applied_callback(block_applied_callback cb); void clear_block_applied_callback(); - // void cancel_all_subscriptions(); void op_applied_callback(const operation_notification& o); // Blocks and transactions @@ -89,49 +125,17 @@ struct plugin::api_impl final { std::vector get_withdraw_routes(std::string account, withdraw_route_type type) const; std::vector get_proposed_transactions(const std::string&, uint32_t, uint32_t) const; - // template - // void subscribe_to_item(const T &i) const { - // auto vec = fc::raw::pack(i); - // if (!_subscribe_callback) { - // return; - // } - - // if (!is_subscribed_to_item(i)) { - // idump((i)); - // _subscribe_filter.insert(vec.data(), vec.size()); - // } - // } - - // template - // bool is_subscribed_to_item(const T &i) const { - // if (!_subscribe_callback) { - // return false; - // } - // return _subscribe_filter.contains(i); - // } - - // mutable fc::bloom_filter _subscribe_filter; - std::function _subscribe_callback; std::function _pending_trx_callback; - golos::chain::database &database() const { return _db; } - - std::map, std::function> _market_subscriptions; - block_applied_callback_info::cont active_block_applied_callback; block_applied_callback_info::cont free_block_applied_callback; - block_operations& get_block_vops(uint32_t block_num) { - if (block_num == _block_virtual_ops_block_num) { - return _block_virtual_ops; - } else { - elog("Trying get operations for wrong block: ${b}", ("b", block_num)("_block", _block_virtual_ops_block_num)); - return _block_virtual_ops; //!!! TODO: return empty or assert - } + block_operations& get_block_vops() { + return _block_virtual_ops; } private: @@ -148,27 +152,6 @@ struct plugin::api_impl final { // // ////////////////////////////////////////////////////////////////////// -// void plugin::set_subscribe_callback(std::function cb, bool clear_filter) { -// my->database().with_weak_read_lock([&]() { -// my->set_subscribe_callback(cb, clear_filter); -// }); -// } - -// void plugin::api_impl::set_subscribe_callback( -// std::function cb, -// bool clear_filter -// ) { -// _subscribe_callback = cb; -// if (clear_filter || !cb) { -// static fc::bloom_parameters param; -// param.projected_element_count = 10000; -// param.false_positive_probability = 1.0 / 10000; -// param.maximum_size = 1024 * 8 * 8 * 2; -// param.compute_optimal_parameters(); -// _subscribe_filter = fc::bloom_filter(param); -// } -// } - void plugin::set_pending_transaction_callback(std::function cb) { my->database().with_weak_read_lock([&]() { my->set_pending_transaction_callback(cb); @@ -179,16 +162,6 @@ void plugin::api_impl::set_pending_transaction_callback(std::functiondatabase().with_weak_read_lock([&]() { -// my->cancel_all_subscriptions(); -// }); -// } - -// void plugin::api_impl::cancel_all_subscriptions() { -// set_subscribe_callback(std::function(), true); -// } - ////////////////////////////////////////////////////////////////////// // // // Constructors // @@ -201,8 +174,7 @@ plugin::plugin() { plugin::~plugin() { } -plugin::api_impl::api_impl() : _db(appbase::app().get_plugin().db()) -{ +plugin::api_impl::api_impl() : _db(appbase::app().get_plugin().db()) { wlog("creating database plugin ${x}", ("x", int64_t(this))); } @@ -242,28 +214,39 @@ optional plugin::api_impl::get_block(uint32_t block_num) const { return database().fetch_block_by_number(block_num); } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -struct block_with_vops : public signed_block { - block_with_vops(signed_block b, block_operations ops): signed_block(b), _virtual_operations(ops) { - }; - - // name field starting with _ coz it's not directly related to block - block_operations _virtual_operations; -}; - DEFINE_API(plugin, set_block_applied_callback) { - CHECK_ARG_SIZE(1); // argument not used now + CHECK_ARG_SIZE(1); + block_applied_callback_result_type type = block; + auto arg = args.args->at(0); + try { + type = arg.as(); + } catch (...) { + ilog("Bad argument passed to set_block_applied_callback, use default", ("arg", arg)); + } // Delegate connection handlers to callback msg_pack_transfer transfer(args); my->database().with_weak_read_lock([&]{ - my->set_block_applied_callback([this,msg = transfer.msg()](const signed_block& block) { - auto ops = my->get_block_vops(block.block_num()); - msg->unsafe_result( - ops.size() ? fc::variant(block_with_vops(block, ops)) : fc::variant(block) - ); + my->set_block_applied_callback([this,type,msg = transfer.msg()](const signed_block& block) { + fc::variant r; + switch (type) { + case block_applied_callback_result_type::block: + r = fc::variant(block); + break; + case header: + r = fc::variant(block_header(block)); + break; + case virtual_ops: + r = fc::variant(virtual_operations(block.block_num(), my->get_block_vops())); + break; + case full: + r = fc::variant(block_with_vops(block, my->get_block_vops())); + break; + default: + break; + } + msg->unsafe_result(r); }); }); @@ -274,10 +257,8 @@ DEFINE_API(plugin, set_block_applied_callback) { void plugin::api_impl::set_block_applied_callback(block_applied_callback callback) { auto info_ptr = std::make_shared(); - active_block_applied_callback.push_back(info_ptr); info_ptr->it = std::prev(active_block_applied_callback.end()); - info_ptr->connect(database().applied_block, free_block_applied_callback, callback); } @@ -298,7 +279,7 @@ void plugin::api_impl::op_applied_callback(const operation_notification& o) { _block_virtual_ops_block_num = o.block; } if (is_virtual_operation(o.op)) { - _block_virtual_ops.push_back(o.op); + _block_virtual_ops.push_back(o); } } @@ -893,5 +874,10 @@ void plugin::plugin_startup() { } } } // golos::plugins::database_api +FC_REFLECT((golos::plugins::database_api::virtual_operations), (block_num)(operations)) +FC_REFLECT((golos::plugins::database_api::block_operation), + (trx_in_block)(op_in_trx)(virtual_op)(op)) FC_REFLECT_DERIVED((golos::plugins::database_api::block_with_vops), ((golos::protocol::signed_block)), (_virtual_operations)) +FC_REFLECT_ENUM(golos::plugins::database_api::block_applied_callback_result_type, + (block)(header)(virtual_ops)(full)) From 916cdbe041b68b5e8e0e8e30080755360774c6b8 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 13 Jul 2018 12:07:46 +0300 Subject: [PATCH 060/250] Add set_pending_transaction_callback #743 --- plugins/database_api/api.cpp | 108 +++++++++++------- .../golos/plugins/database_api/plugin.hpp | 53 +++------ 2 files changed, 79 insertions(+), 82 deletions(-) diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index 1a8e0c7540..fa91ea6026 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -10,7 +10,6 @@ #include #include -#define GET_REQUIRED_FEES_MAX_RECURSION 4 #define CHECK_ARG_SIZE(s) \ FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); @@ -20,23 +19,26 @@ namespace golos { namespace plugins { namespace database_api { -struct block_applied_callback_info { - using ptr = std::shared_ptr; + +template +struct callback_info { + using callback_t = std::function; + using ptr = std::shared_ptr; using cont = std::list; - block_applied_callback callback; + callback_t callback; boost::signals2::connection connection; - cont::iterator it; + typename cont::iterator it; void connect( - boost::signals2::signal& sig, + boost::signals2::signal& sig, cont& free_cont, - block_applied_callback cb + callback_t cb ) { callback = cb; - connection = sig.connect([this, &free_cont](const signed_block& block) { + connection = sig.connect([this, &free_cont](arg item) { try { - this->callback(block); + this->callback(item); } catch (...) { free_cont.push_back(*this->it); this->connection.disconnect(); @@ -45,10 +47,15 @@ struct block_applied_callback_info { } }; +using block_applied_callback_info = callback_info; +using block_applied_callback = block_applied_callback_info::callback_t; +using pending_tx_callback_info = callback_info; +using pending_tx_callback = pending_tx_callback_info::callback_t; + + // block_operation used in block_applied_callback to represent virtual operations. -// default operation type have no position info (trx, on_in_trx) +// default operation type have no position info (trx, op_in_trx) struct block_operation { - block_operation() = default; block_operation(const operation_notification& o) : trx_in_block(o.trx_in_block), op_in_trx(o.op_in_trx), @@ -96,9 +103,9 @@ struct plugin::api_impl final { } // Subscriptions - void set_pending_transaction_callback(std::function cb); void set_block_applied_callback(block_applied_callback cb); - void clear_block_applied_callback(); + void set_pending_tx_callback(pending_tx_callback cb); + void clear_outdated_callbacks(bool clear_blocks); void op_applied_callback(const operation_notification& o); // Blocks and transactions @@ -125,14 +132,15 @@ struct plugin::api_impl final { std::vector get_withdraw_routes(std::string account, withdraw_route_type type) const; std::vector get_proposed_transactions(const std::string&, uint32_t, uint32_t) const; - std::function _pending_trx_callback; - - golos::chain::database &database() const { + golos::chain::database& database() const { return _db; } + // Callbacks block_applied_callback_info::cont active_block_applied_callback; block_applied_callback_info::cont free_block_applied_callback; + pending_tx_callback_info::cont active_pending_tx_callback; + pending_tx_callback_info::cont free_pending_tx_callback; block_operations& get_block_vops() { return _block_virtual_ops; @@ -146,22 +154,6 @@ struct plugin::api_impl final { }; -////////////////////////////////////////////////////////////////////// -// // -// Subscriptions // -// // -////////////////////////////////////////////////////////////////////// - -void plugin::set_pending_transaction_callback(std::function cb) { - my->database().with_weak_read_lock([&]() { - my->set_pending_transaction_callback(cb); - }); -} - -void plugin::api_impl::set_pending_transaction_callback(std::function cb) { - _pending_trx_callback = cb; -} - ////////////////////////////////////////////////////////////////////// // // // Constructors // @@ -214,6 +206,12 @@ optional plugin::api_impl::get_block(uint32_t block_num) const { return database().fetch_block_by_number(block_num); } +////////////////////////////////////////////////////////////////////// +// // +// Subscriptions // +// // +////////////////////////////////////////////////////////////////////// + DEFINE_API(plugin, set_block_applied_callback) { CHECK_ARG_SIZE(1); block_applied_callback_result_type type = block; @@ -221,7 +219,7 @@ DEFINE_API(plugin, set_block_applied_callback) { try { type = arg.as(); } catch (...) { - ilog("Bad argument passed to set_block_applied_callback, use default", ("arg", arg)); + ilog("Bad argument (${a}) passed to set_block_applied_callback, using default", ("a",arg)); } // Delegate connection handlers to callback @@ -255,6 +253,19 @@ DEFINE_API(plugin, set_block_applied_callback) { return {}; } +DEFINE_API(plugin, set_pending_transaction_callback) { + // CHECK_ARG_SIZE(1); // not used + // Delegate connection handlers to callback + msg_pack_transfer transfer(args); + my->database().with_weak_read_lock([&]{ + my->set_pending_tx_callback([this,msg = transfer.msg()](const signed_transaction& tx) { + msg->unsafe_result(fc::variant(tx)); + }); + }); + transfer.complete(); + return {}; +} + void plugin::api_impl::set_block_applied_callback(block_applied_callback callback) { auto info_ptr = std::make_shared(); active_block_applied_callback.push_back(info_ptr); @@ -262,15 +273,25 @@ void plugin::api_impl::set_block_applied_callback(block_applied_callback callbac info_ptr->connect(database().applied_block, free_block_applied_callback, callback); } -void plugin::api_impl::clear_block_applied_callback() { - for (auto &info: free_block_applied_callback) { - active_block_applied_callback.erase(info->it); - } - free_block_applied_callback.clear(); +void plugin::api_impl::set_pending_tx_callback(pending_tx_callback callback) { + auto info_ptr = std::make_shared(); + active_pending_tx_callback.push_back(info_ptr); + info_ptr->it = std::prev(active_pending_tx_callback.end()); + info_ptr->connect(database().on_pending_transaction, free_pending_tx_callback, callback); } -void plugin::clear_block_applied_callback() { - my->clear_block_applied_callback(); +void plugin::api_impl::clear_outdated_callbacks(bool clear_blocks) { + auto clear_bad = [&](auto& free_list, auto& active_list) { + for (auto& info: free_list) { + active_list.erase(info->it); + } + free_list.clear(); + }; + if (clear_blocks) { + clear_bad(free_block_applied_callback, active_block_applied_callback); + } else { + clear_bad(free_pending_tx_callback, active_pending_tx_callback); + } } void plugin::api_impl::op_applied_callback(const operation_notification& o) { @@ -859,8 +880,11 @@ void plugin::plugin_initialize(const boost::program_options::variables_map& opti my = std::make_unique(); JSON_RPC_REGISTER_API(plugin_name) auto& db = my->database(); - db.applied_block.connect([this](const protocol::signed_block&) { - this->clear_block_applied_callback(); + db.applied_block.connect([&](const signed_block&) { + my->clear_outdated_callbacks(true); + }); + db.on_pending_transaction.connect([&](const signed_transaction& tx) { + my->clear_outdated_callbacks(false); }); db.pre_apply_operation.connect([&](const operation_notification& o) { my->op_applied_callback(o); diff --git a/plugins/database_api/include/golos/plugins/database_api/plugin.hpp b/plugins/database_api/include/golos/plugins/database_api/plugin.hpp index f734670a80..d997db5567 100755 --- a/plugins/database_api/include/golos/plugins/database_api/plugin.hpp +++ b/plugins/database_api/include/golos/plugins/database_api/plugin.hpp @@ -94,12 +94,11 @@ struct signed_block_api_object : public signed_block { }; -using block_applied_callback = std::function; - /// API, args, return DEFINE_API_ARGS(get_block_header, msg_pack, optional) DEFINE_API_ARGS(get_block, msg_pack, optional) DEFINE_API_ARGS(set_block_applied_callback, msg_pack, void_type) +DEFINE_API_ARGS(set_pending_transaction_callback, msg_pack, void_type) DEFINE_API_ARGS(get_config, msg_pack, variant_object) DEFINE_API_ARGS(get_dynamic_global_properties, msg_pack, dynamic_global_property_api_object) DEFINE_API_ARGS(get_chain_properties, msg_pack, chain_api_properties) @@ -139,52 +138,26 @@ DEFINE_API_ARGS(get_proposed_transactions, msg_pack, std::vector { public: - constexpr static const char *plugin_name = "database_api"; + constexpr static const char* plugin_name = "database_api"; - static const std::string &name() { + static const std::string& name() { static std::string name = plugin_name; return name; } APPBASE_PLUGIN_REQUIRES( - (json_rpc::plugin) - (chain::plugin) + (json_rpc::plugin) + (chain::plugin) ) - void set_program_options(boost::program_options::options_description &cli, boost::program_options::options_description &cfg) override{} - - void plugin_initialize(const boost::program_options::variables_map &options) override; - + void set_program_options(boost::program_options::options_description& cli, boost::program_options::options_description& cfg) override{} + void plugin_initialize(const boost::program_options::variables_map& options) override; void plugin_startup() override; - void plugin_shutdown() override{} plugin(); - ~plugin(); - /////////////////// - // Subscriptions // - /////////////////// - - void set_subscribe_callback(std::function cb, bool clear_filter); - - void set_pending_transaction_callback(std::function cb); - - /** - * @brief Stop receiving any notifications - * - * This unsubscribes from all subscribed markets and objects. - */ - void cancel_all_subscriptions(); - - - /** - * @brief Clear disconnected callbacks on applied block - */ - - void clear_block_applied_callback(); - DECLARE_API( /** * This API is a short-cut for returning all of the state required for a particular URL @@ -212,10 +185,15 @@ class plugin final : public appbase::plugin { /** * @brief Set callback which is triggered on each generated block - * @param callback function which should be called + * @param type of data, callback will send (block, header, virtual_ops, full) */ (set_block_applied_callback) + /** + * @brief Set callback which is triggered on each received transaction (before applying) + */ + (set_pending_transaction_callback) + ///////////// // Globals // ///////////// @@ -292,11 +270,6 @@ class plugin final : public appbase::plugin { (get_vesting_delegations) (get_expiring_vesting_delegations) - // (list_vesting_delegations) - // (find_vesting_delegations) - // (list_vesting_delegation_expirations) - // (find_vesting_delegation_expirations) - (get_conversion_requests) From abd97585dce2eed174d011d9243138a8954f0cb9 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Fri, 13 Jul 2018 17:00:59 +0300 Subject: [PATCH 061/250] Fixed few bugs in logic expressions. Removed commented lines. #796 --- libraries/chain/database.cpp | 12 ----- libraries/chain/steem_evaluator.cpp | 62 +---------------------- plugins/social_network/social_network.cpp | 8 +-- 3 files changed, 6 insertions(+), 76 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 28e7bea8e6..e8245ab742 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -643,17 +643,6 @@ namespace golos { namespace chain { return find(boost::make_tuple(author, permlink)); } - - // const comment_content_object &database::get_comment_content(const comment_id_type &comment) const { - // try { - // return get(comment); - // } FC_CAPTURE_AND_RETHROW((comment)) - // } - - // const comment_content_object *database::find_comment_content(const comment_id_type &comment) const { - // return find(comment); - // } - const escrow_object &database::get_escrow(const account_name_type &name, uint32_t escrow_id) const { try { return get(boost::make_tuple(name, escrow_id)); @@ -2956,7 +2945,6 @@ namespace golos { namespace chain { add_core_index(*this); add_core_index(*this); add_core_index(*this); - // add_core_index(*this); add_core_index(*this); add_core_index(*this); add_core_index(*this); diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index a600a68001..2679445851 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -449,20 +449,14 @@ namespace golos { namespace chain { p.children--; p.active = now; }); -// #ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -// #endif { parent = nullptr; } } } -// #ifndef IS_LOW_MEM - // auto& content = _db.get_comment_content(comment.id); - // _db.remove(content); -// #endif _db.remove(comment); } @@ -679,34 +673,17 @@ namespace golos { namespace chain { } }); - // id = new_comment.id; -// #ifndef IS_LOW_MEM -// _db.create([&](comment_content_object& con) { -// con.comment = id; -// from_string(con.title, o.title); -// if (o.body.size() < 1024*1024*128) { -// from_string(con.body, o.body); -// } -// if (fc::is_utf8(o.json_metadata)) { -// from_string(con.json_metadata, o.json_metadata); -// } else { -// wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", -// ("a", o.author)("p", o.permlink)); -// } -// }); -// #endif -/// this loop can be skiped for validate-only nodes as it is merely gathering stats for indicies + auto now = _db.head_block_time(); while (parent) { _db.modify(*parent, [&](comment_object &p) { p.children++; p.active = now; }); -// #ifndef IS_LOW_MEM + if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -// #endif { parent = nullptr; } @@ -738,41 +715,6 @@ namespace golos { namespace chain { "The parent permlink of a comment cannot change."); }); -// #ifndef IS_LOW_MEM -// _db.modify(_db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { -// if (o.title.size()) -// from_string(con.title, o.title); -// if (o.json_metadata.size()) { -// if (fc::is_utf8(o.json_metadata)) -// from_string(con.json_metadata, o.json_metadata ); -// else -// wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); -// } -// if (o.body.size()) { -// try { -// diff_match_patch dmp; -// auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); -// if (patch.size()) { -// auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); -// auto patched_body = wstring_to_utf8(result.first); -// if(!fc::is_utf8(patched_body)) { -// idump(("invalid utf8")(patched_body)); -// from_string(con.body, fc::prune_invalid_utf8(patched_body)); -// } -// else { -// from_string(con.body, patched_body); -// } -// } -// else { // replace -// from_string(con.body, o.body); -// } -// } catch ( ... ) { -// from_string(con.body, o.body); -// } -// } -// }); -// #endif - } // end EDIT case } FC_CAPTURE_AND_RETHROW((o)) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 0660f71204..c9ccfc39e5 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -54,11 +54,11 @@ struct content_depth_params { } inline bool should_delete_whole_content_object(const uint32_t & delta) const { - return comment_title_depth > delta && comment_body_depth > delta && comment_json_metadata_depth > delta; + return delta > comment_title_depth && delta > comment_body_depth && delta > comment_json_metadata_depth; } inline bool should_delete_part_of_content_object(const uint32_t & delta) const { - return comment_title_depth > delta || comment_body_depth > delta || comment_json_metadata_depth > delta; + return delta > comment_title_depth || delta > comment_body_depth || delta > comment_json_metadata_depth; } @@ -354,7 +354,7 @@ namespace golos { namespace plugins { namespace social_network { auto time_delta = db.head_block_time() - comment->created; auto delta = db.head_block_num() - content.block_number; - if (time_delta > fc::microseconds(cash_window_sec) && depth_parameters.should_delete_part_of_content_object(delta)) { + if (time_delta.to_seconds() > fc::microseconds(cash_window_sec * 1000000).to_seconds() && depth_parameters.should_delete_part_of_content_object(delta)) { if (depth_parameters.should_delete_whole_content_object(delta)) { db.remove(content); continue; @@ -397,7 +397,7 @@ namespace golos { namespace plugins { namespace social_network { boost::program_options::options_description& cfg, boost::program_options::options_description& config_file_options ) { - cfg.add_options() + config_file_options.add_options() ( // Depth of comment_content information storage history. "comment-title-depth", boost::program_options::value(), "max count of storing records of comment.title" From afda359321db415eb45db3be98eabbafa9bc941c Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sat, 14 Jul 2018 09:59:21 +0300 Subject: [PATCH 062/250] Fixed PR requested changes. #796 --- libraries/api/discussion_helper.cpp | 34 ++++---- .../include/golos/api/discussion_helper.hpp | 14 +--- plugins/follow/plugin.cpp | 2 +- .../social_network/comment_content_object.hpp | 1 - .../plugins/social_network/social_network.hpp | 3 +- plugins/social_network/social_network.cpp | 83 +++++++++---------- .../golos/plugins/tags/tag_visitor.hpp | 4 +- plugins/tags/plugin.cpp | 4 +- plugins/tags/tag_visitor.cpp | 2 +- 9 files changed, 65 insertions(+), 82 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index d86766dc62..adda2d5375 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -66,17 +66,17 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function get_comment_content_callback) + std::function fill_comment_content) : database_(db), fill_reputation_(fill_reputation), fill_promoted_(fill_promoted), - get_comment_content_callback(get_comment_content_callback) { + fill_comment_content_(fill_comment_content) { } impl( golos::chain::database& db, - std::function get_comment_content_callback) + std::function fill_comment_content) : database_(db), - get_comment_content_callback(get_comment_content_callback) { + fill_comment_content_(fill_comment_content) { } ~impl() = default; @@ -105,13 +105,13 @@ namespace golos { namespace api { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; - get_comment_content_res get_comment_content(const golos::chain::database & db, const comment_object & o); + void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); private: golos::chain::database& database_; std::function&)> fill_reputation_; std::function fill_promoted_; - std::function get_comment_content_callback; + std::function fill_comment_content_; }; // create_comment_api_object @@ -159,12 +159,8 @@ namespace golos { namespace api { result.beneficiaries.push_back(route); } - if ( get_comment_content_callback ) { - auto content = get_comment_content_callback(database(), o); - - result.title = content.title; - result.body = content.body; - result.json_metadata = content.json_metadata; + if ( fill_comment_content_ ) { + fill_comment_content_(database(), o, result); } if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { @@ -178,8 +174,8 @@ namespace golos { namespace api { // get_comment_content - get_comment_content_res discussion_helper::impl::get_comment_content(const golos::chain::database & db, const comment_object & o) { - return get_comment_content_callback(db, o); + void discussion_helper::impl::fill_comment_content(const golos::chain::database & db, const comment_object & co, comment_api_object & con) { + fill_comment_content_(db, co, con); } // get_discussion discussion discussion_helper::impl::get_discussion(const comment_object& c, uint32_t vote_limit) const { @@ -327,16 +323,16 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function get_comment_content_callback + std::function fill_comment_content ) { - pimpl = std::make_unique(db, fill_reputation, fill_promoted, get_comment_content_callback); + pimpl = std::make_unique(db, fill_reputation, fill_promoted, fill_comment_content); } discussion_helper::discussion_helper( golos::chain::database& db, - std::function get_comment_content_callback - ) { - pimpl = std::make_unique(db, get_comment_content_callback); + std::function fill_comment_content + ) { + pimpl = std::make_unique(db, fill_comment_content); } discussion_helper::~discussion_helper() = default; diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 0eac1caf79..33df4d665e 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -12,12 +12,6 @@ namespace golos { namespace api { comment_metadata get_metadata(const comment_api_object &c); - struct get_comment_content_res { - std::string title; - std::string body; - std::string json_metadata; - }; - class discussion_helper { public: discussion_helper() = delete; @@ -29,11 +23,11 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function get_comment_content_callback + std::function fill_comment_content ); discussion_helper( golos::chain::database& db, - std::function get_comment_content_callback + std::function fill_comment_content ); ~discussion_helper(); @@ -64,7 +58,3 @@ namespace golos { namespace api { } } // golos::api FC_REFLECT((golos::api::comment_metadata), (tags)(language)) - -FC_REFLECT((golos::api::get_comment_content_res), - (title)(body)(json_metadata) - ) diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index 1efdcd09c4..db48f75411 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -290,7 +290,7 @@ namespace golos { impl() : database_(appbase::app().get_plugin().db()) { helper = std::make_unique( database_, - golos::plugins::social_network::get_comment_content_callback + golos::plugins::social_network::fill_comment_content ); } diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index d9d1ef4e44..ac59700fa8 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -9,7 +9,6 @@ namespace golos { namespace plugins { namespace social_network { using golos::api::discussion; using golos::api::account_vote; using golos::api::vote_state; - using golos::api::get_comment_content_res; using namespace golos::chain; #ifndef SOCIAL_NETWORK_SPACE_ID diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index ae7ffb6ea6..3386ecc5f6 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -14,7 +14,6 @@ namespace golos { namespace plugins { namespace social_network { using golos::api::discussion; using golos::api::account_vote; using golos::api::vote_state; - using golos::api::get_comment_content_res; using namespace golos::chain; using golos::api::comment_api_object; @@ -68,6 +67,6 @@ namespace golos { namespace plugins { namespace social_network { }; // Callback which is needed for correct work of discussion_helper - get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o); + void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); } } } // golos::plugins::social_network diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index c9ccfc39e5..db687bc599 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -81,7 +81,7 @@ namespace golos { namespace plugins { namespace social_network { struct social_network::impl final { impl(): database_(appbase::app().get_plugin().db()) { - helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted, get_comment_content_callback); + helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted, fill_comment_content); } ~impl() = default; @@ -332,49 +332,53 @@ namespace golos { namespace plugins { namespace social_network { }; void social_network::impl::post_operation(const operation_notification &o) { - auto& db = database(); + try { + auto& db = database(); - operation_visitor ovisit(db, depth_parameters); + operation_visitor ovisit(db, depth_parameters); - o.op.visit(ovisit); + o.op.visit(ovisit); + } FC_CAPTURE_AND_RETHROW() } void social_network::impl::on_block(const signed_block &b) { - auto & db = database(); + try { + auto & db = database(); - const auto &idx = db.get_index().indices().get(); + const auto &idx = db.get_index().indices().get(); - for (auto itr = idx.begin(); itr != idx.end(); ++itr) { - auto & content = *itr; + for (auto itr = idx.begin(); itr != idx.end(); ++itr) { + auto & content = *itr; - const auto &cidx = db.get_index().indices().get(); - - auto comment = cidx.find(content.comment); + const auto &cidx = db.get_index().indices().get(); + + auto comment = cidx.find(content.comment); - int64_t cash_window_sec = STEEMIT_CASHOUT_WINDOW_SECONDS; - auto time_delta = db.head_block_time() - comment->created; - auto delta = db.head_block_num() - content.block_number; + int64_t cash_window_sec = STEEMIT_CASHOUT_WINDOW_SECONDS; + auto time_delta = db.head_block_time() - comment->created; + auto delta = db.head_block_num() - content.block_number; - if (time_delta.to_seconds() > fc::microseconds(cash_window_sec * 1000000).to_seconds() && depth_parameters.should_delete_part_of_content_object(delta)) { - if (depth_parameters.should_delete_whole_content_object(delta)) { - db.remove(content); - continue; - } - db.modify(content, [&](comment_content_object& con) { - if (delta > depth_parameters.comment_title_depth) { - con.title.clear(); + if (time_delta.to_seconds() > fc::microseconds(cash_window_sec * 1000000).to_seconds() && depth_parameters.should_delete_part_of_content_object(delta)) { + if (depth_parameters.should_delete_whole_content_object(delta)) { + db.remove(content); + continue; } + db.modify(content, [&](comment_content_object& con) { + if (delta > depth_parameters.comment_title_depth) { + con.title.clear(); + } - if (delta > depth_parameters.comment_body_depth) { - con.body.clear(); - } + if (delta > depth_parameters.comment_body_depth) { + con.body.clear(); + } - if (delta > depth_parameters.comment_json_metadata_depth) { - con.json_metadata.clear(); - } - }); + if (delta > depth_parameters.comment_json_metadata_depth) { + con.json_metadata.clear(); + } + }); + } } - } + } FC_CAPTURE_AND_RETHROW() } @@ -566,7 +570,7 @@ namespace golos { namespace plugins { namespace social_network { if (itr != by_permlink_idx.end()) { return get_discussion(*itr, limit); } - return helper->create_discussion(*itr); + return helper->create_discussion(author); } DEFINE_API(social_network, get_content) { @@ -641,20 +645,15 @@ namespace golos { namespace plugins { namespace social_network { }); } - - get_comment_content_res get_comment_content_callback(const golos::chain::database & db, const comment_object & o) { + void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& con) { if (!db.has_index()) { - return get_comment_content_res(); + return; } - auto & content = db.get(o.id); + auto & content = db.get(co.id); - get_comment_content_res result; - - result.title = std::string(content.title.begin(), content.title.end()); - result.body = std::string(content.body.begin(), content.body.end()); - result.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); - - return result; + con.title = std::string(content.title.begin(), content.title.end()); + con.body = std::string(content.body.begin(), content.body.end()); + con.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); } } } } // golos::plugins::social_network diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 433a644715..a66ec6b800 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -11,11 +11,11 @@ namespace golos { namespace plugins { namespace tags { using golos::api::discussion_helper; struct operation_visitor { - operation_visitor(database& db, const std::shared_ptr &helper); + operation_visitor(database& db, const std::unique_ptr &helper); using result_type = void; database& db_; - std::shared_ptr helper_; + const std::unique_ptr & helper_; void remove_stats(const tag_object& tag) const; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 7aa1104084..dc1d07ae47 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -34,7 +34,7 @@ namespace golos { namespace plugins { namespace tags { struct tags_plugin::impl final { impl(): database_(appbase::app().get_plugin().db()) { - helper = std::make_shared( + helper = std::make_unique( database_, follow::fill_account_reputation, fill_promoted); @@ -118,7 +118,7 @@ namespace golos { namespace plugins { namespace tags { private: golos::chain::database& database_; - std::shared_ptr helper; + std::unique_ptr helper; }; void tags_plugin::impl::select_active_votes( diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index 9a6f8a139f..cd57939d41 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -3,7 +3,7 @@ namespace golos { namespace plugins { namespace tags { - operation_visitor::operation_visitor(database& db, const std::shared_ptr &helper) + operation_visitor::operation_visitor(database& db, const std::unique_ptr &helper) : db_(db), helper_(helper) { } From 7ae8661fce9dd2921aabcb918916e149647a101d Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sat, 14 Jul 2018 11:18:38 +0300 Subject: [PATCH 063/250] Fixed some more requsested changed for PR. #796 --- libraries/api/comment_api_object.cpp | 1 + .../include/golos/api/comment_api_object.hpp | 2 +- .../include/golos/api/discussion_helper.hpp | 6 +-- .../include/golos/chain/comment_object.hpp | 32 ------------ .../chain/include/golos/chain/database.hpp | 4 -- .../golos/chain/steem_object_types.hpp | 4 -- libraries/chain/steem_evaluator.cpp | 6 ++- .../social_network/comment_content_object.hpp | 7 ++- .../plugins/social_network/social_network.hpp | 6 +-- plugins/social_network/social_network.cpp | 50 ++++++++++++------- 10 files changed, 46 insertions(+), 72 deletions(-) diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp index 2b9500c225..f6a043088c 100644 --- a/libraries/api/comment_api_object.cpp +++ b/libraries/api/comment_api_object.cpp @@ -3,6 +3,7 @@ namespace golos { namespace api { using namespace golos::chain; + comment_api_object::comment_api_object() = default; comment_api_object::comment_api_object(const comment_api_object& o ) { id = o.id; parent_author = o.parent_author; diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 051cc581e5..334b96c730 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -10,7 +10,7 @@ namespace golos { namespace api { using namespace golos::chain; struct comment_api_object { - comment_api_object() = default; + comment_api_object(); comment_api_object(const comment_api_object& o ); comment_object::id_type id; diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 33df4d665e..bda37c05ce 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -23,11 +23,11 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function fill_comment_content + std::function fill_comment_content ); discussion_helper( golos::chain::database& db, - std::function fill_comment_content + std::function fill_comment_content ); ~discussion_helper(); @@ -47,7 +47,7 @@ namespace golos { namespace api { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; - comment_api_object create_comment_api_object(const comment_object & o) const; + comment_api_object create_comment_api_object(const comment_object& o) const; private: diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index ed0dfc8e8d..62758c0706 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -40,25 +40,6 @@ namespace golos { archived }; - // class comment_content_object - // : public object { - // public: - // comment_content_object() = delete; - - // template - // comment_content_object(Constructor &&c, allocator a) - // :title(a), body(a), json_metadata(a) { - // c(*this); - // } - - // id_type id; - - // comment_id_type comment; - - // shared_string title; - // shared_string body; - // shared_string json_metadata; - // }; class comment_object : public object { @@ -262,17 +243,6 @@ namespace golos { > comment_index; - - // struct by_comment; - - // typedef multi_index_container< - // comment_content_object, - // indexed_by< - // ordered_unique< tag< by_id >, member< comment_content_object, comment_content_id_type, &comment_content_object::id > >, - // ordered_unique< tag< by_comment >, member< comment_content_object, comment_id_type, &comment_content_object::comment > > >, - // allocator< comment_content_object > - // > comment_content_index; - } } // golos::chain @@ -280,7 +250,5 @@ FC_REFLECT_ENUM(golos::chain::comment_mode, (not_set)(first_payout)(second_payou CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_object, golos::chain::comment_index) -// CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_content_object, golos::chain::comment_content_index) - CHAINBASE_SET_INDEX_TYPE(golos::chain::comment_vote_object, golos::chain::comment_vote_index) diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index ad24a4ab63..8279c41247 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -172,10 +172,6 @@ namespace golos { namespace chain { const comment_object *find_comment(const account_name_type &author, const string &permlink) const; - // const comment_content_object &get_comment_content(const comment_id_type &comment) const; - - // const comment_content_object *find_comment_content(const comment_id_type &comment) const; - const escrow_object &get_escrow(const account_name_type &name, uint32_t escrow_id) const; const escrow_object *find_escrow(const account_name_type &name, uint32_t escrow_id) const; diff --git a/libraries/chain/include/golos/chain/steem_object_types.hpp b/libraries/chain/include/golos/chain/steem_object_types.hpp index ef4708c484..481f38efb7 100644 --- a/libraries/chain/include/golos/chain/steem_object_types.hpp +++ b/libraries/chain/include/golos/chain/steem_object_types.hpp @@ -51,7 +51,6 @@ namespace golos { namespace chain { block_summary_object_type, witness_schedule_object_type, comment_object_type, - // comment_content_object_type, comment_vote_object_type, witness_vote_object_type, limit_order_object_type, @@ -85,7 +84,6 @@ namespace golos { namespace chain { class proposal_object; class required_approval_object; class comment_object; - // class comment_content_object; class comment_vote_object; class witness_vote_object; class limit_order_object; @@ -115,7 +113,6 @@ namespace golos { namespace chain { typedef object_id block_summary_id_type; typedef object_id witness_schedule_id_type; typedef object_id comment_id_type; - // typedef object_id comment_content_id_type; typedef object_id comment_vote_id_type; typedef object_id witness_vote_id_type; typedef object_id limit_order_id_type; @@ -216,7 +213,6 @@ FC_REFLECT_ENUM(golos::chain::object_type, (block_summary_object_type) (witness_schedule_object_type) (comment_object_type) - // (comment_content_object_type) (comment_vote_object_type) (witness_vote_object_type) (limit_order_object_type) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 2679445851..efa3c40a7d 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -6,7 +6,6 @@ #ifndef IS_LOW_MEM -// #include #include using boost::locale::conv::utf_to_utf; @@ -449,9 +448,11 @@ namespace golos { namespace chain { p.children--; p.active = now; }); +#ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else +#endif { parent = nullptr; } @@ -680,10 +681,11 @@ namespace golos { namespace chain { p.children++; p.active = now; }); - +#ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else +#endif { parent = nullptr; } diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index ac59700fa8..e8bfdc4436 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -16,7 +16,7 @@ namespace golos { namespace plugins { namespace social_network { #endif enum social_network_types { - comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 + comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) }; @@ -26,7 +26,7 @@ namespace golos { namespace plugins { namespace social_network { comment_content_object() = delete; template - comment_content_object(Constructor &&c, allocator a) + comment_content_object(Constructor&& c, allocator a) :title(a), body(a), json_metadata(a) { c(*this); } @@ -53,8 +53,7 @@ namespace golos { namespace plugins { namespace social_network { indexed_by< ordered_unique, member>, ordered_unique, member>, - ordered_unique, member> - >, // TODO fix code style!! + ordered_unique, member>>, allocator > comment_content_index; } } } diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 3386ecc5f6..63fe3437c4 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -55,10 +55,10 @@ namespace golos { namespace plugins { namespace social_network { void plugin_startup() override; void plugin_shutdown() override; - comment_api_object create_comment_api_object(const comment_object & o) const; + comment_api_object create_comment_api_object(const comment_object& o) const; - const comment_content_object &get_comment_content(const comment_id_type &comment) const ; - const comment_content_object *find_comment_content(const comment_id_type &comment) const ; + const comment_content_object &get_comment_content(const comment_id_type& comment) const ; + const comment_content_object *find_comment_content(const comment_id_type& comment) const ; private: diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index db687bc599..77fd7c4458 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -53,11 +53,11 @@ struct content_depth_params { return has_comment_title_depth || has_comment_body_depth || has_comment_json_metadata_depth; } - inline bool should_delete_whole_content_object(const uint32_t & delta) const { + inline bool should_delete_whole_content_object(const uint32_t delta) const { return delta > comment_title_depth && delta > comment_body_depth && delta > comment_json_metadata_depth; } - inline bool should_delete_part_of_content_object(const uint32_t & delta) const { + inline bool should_delete_part_of_content_object(const uint32_t delta) const { return delta > comment_title_depth || delta > comment_body_depth || delta > comment_json_metadata_depth; } @@ -120,18 +120,18 @@ namespace golos { namespace plugins { namespace social_network { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const ; - void set_depth_parameters(const content_depth_params ¶ms); + void set_depth_parameters(const content_depth_params& params); // Looks for a comment_operation, fills the comment_content state objects. - void post_operation(const operation_notification &o); + void post_operation(const operation_notification& o); - void on_block(const signed_block &b); + void on_block(const signed_block& b); - comment_api_object create_comment_api_object(const comment_object & o) const ; + comment_api_object create_comment_api_object(const comment_object& o) const ; - const comment_content_object &get_comment_content(const comment_id_type &comment) const ; + const comment_content_object &get_comment_content(const comment_id_type& comment) const ; - const comment_content_object *find_comment_content(const comment_id_type &comment) const ; + const comment_content_object *find_comment_content(const comment_id_type& comment) const ; private: @@ -141,22 +141,22 @@ namespace golos { namespace plugins { namespace social_network { }; - const comment_content_object &social_network::impl::get_comment_content(const comment_id_type &comment) const { + const comment_content_object& social_network::impl::get_comment_content(const comment_id_type& comment) const { try { return database().get(comment); } FC_CAPTURE_AND_RETHROW((comment)) } - const comment_content_object &social_network::get_comment_content(const comment_id_type &comment) const { + const comment_content_object& social_network::get_comment_content(const comment_id_type& comment) const { return pimpl->get_comment_content(comment); } - const comment_content_object *social_network::impl::find_comment_content(const comment_id_type &comment) const { + const comment_content_object* social_network::impl::find_comment_content(const comment_id_type& comment) const { return database().find(comment); } - const comment_content_object *social_network::find_comment_content(const comment_id_type &comment) const { + const comment_content_object* social_network::find_comment_content(const comment_id_type& comment) const { return pimpl->find_comment_content(comment); } @@ -171,7 +171,7 @@ namespace golos { namespace plugins { namespace social_network { helper->select_active_votes(result, total_count, author, permlink, limit); } - void social_network::impl::set_depth_parameters(const content_depth_params ¶ms) { + void social_network::impl::set_depth_parameters(const content_depth_params& params) { depth_parameters = params; } @@ -181,24 +181,24 @@ namespace golos { namespace plugins { namespace social_network { golos::chain::database &db; content_depth_params depth_parameters; - operation_visitor(golos::chain::database &db, const content_depth_params ¶ms) : db(db), depth_parameters(params) { + operation_visitor(golos::chain::database& db, const content_depth_params& params) : db(db), depth_parameters(params) { } - std::wstring utf8_to_wstring(const std::string &str) const { + std::wstring utf8_to_wstring(const std::string& str) const { return utf_to_utf(str.c_str(), str.c_str() + str.size()); } - std::string wstring_to_utf8(const std::wstring &str) const { + std::string wstring_to_utf8(const std::wstring& str) const { return utf_to_utf(str.c_str(), str.c_str() + str.size()); } - const comment_content_object &get_comment_content(const comment_id_type &comment) const { + const comment_content_object& get_comment_content(const comment_id_type& comment) const { try { return db.get(comment); } FC_CAPTURE_AND_RETHROW((comment)) } - const comment_content_object *find_comment_content(const comment_id_type &comment) const { + const comment_content_object* find_comment_content(const comment_id_type& comment) const { return db.find(comment); } @@ -208,6 +208,9 @@ namespace golos { namespace plugins { namespace social_network { void operator()(const delete_comment_operation& o) const { const auto &comment = db.get_comment(o.author, o.permlink); + if (find_comment_content(comment.id) == nullptr) { + return; + } auto& content = get_comment_content(comment.id); db.remove(content); } @@ -221,6 +224,9 @@ namespace golos { namespace plugins { namespace social_network { if (comment.created != db.head_block_time()) { // Edit case + if (find_comment_content(comment.id) == nullptr) { + return; + } db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { from_string(con.title, o.title); @@ -302,7 +308,13 @@ namespace golos { namespace plugins { namespace social_network { } const auto &comment = db.get_comment(o.author, o.permlink); - auto& content = get_comment_content(comment.id); + + if (find_comment_content(comment.id) == nullptr) { + return; + } + + auto &content = get_comment_content(comment.id); + auto delta = db.head_block_num() - content.block_number; if (depth_parameters.should_delete_whole_content_object(delta)) { From fa79ab00cb5e78ec5ba4898a55a13616619d983d Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sun, 15 Jul 2018 11:26:20 +0300 Subject: [PATCH 064/250] Added fill_comment_api_object to discussion helper. Fixed some codestyle errors. #796 --- libraries/api/discussion_helper.cpp | 61 ++++++++++++++++++- .../include/golos/api/discussion_helper.hpp | 2 + plugins/social_network/social_network.cpp | 13 +--- .../golos/plugins/tags/tag_visitor.hpp | 2 +- plugins/tags/plugin.cpp | 9 ++- 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index adda2d5375..c52055b961 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -101,12 +101,14 @@ namespace golos { namespace api { return database_; } - comment_api_object create_comment_api_object(const comment_object & o) const; + comment_api_object create_comment_api_object(const comment_object& o) const; discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); + void fill_comment_api_object(const comment_object& o, discussion& d) const; + private: golos::chain::database& database_; std::function&)> fill_reputation_; @@ -121,7 +123,6 @@ namespace golos { namespace api { comment_api_object discussion_helper::impl::create_comment_api_object(const comment_object & o) const { comment_api_object result; - auto & db = database_; result.id = o.id; result.parent_author = o.parent_author; @@ -166,12 +167,66 @@ namespace golos { namespace api { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { result.category = to_string(o.parent_permlink); } else { - result.category = to_string(db.get(o.root_comment).parent_permlink); + result.category = to_string(database().get(o.root_comment).parent_permlink); } return result; } +// fill_comment_api_object + + void discussion_helper::fill_comment_api_object(const comment_object& o, discussion& d) const { + pimpl->fill_comment_api_object(o, d); + } + + void discussion_helper::impl::fill_comment_api_object(const comment_object& o, discussion& d) const { + d.id = o.id; + d.parent_author = o.parent_author; + d.parent_permlink = to_string(o.parent_permlink); + d.author = o.author; + d.permlink = to_string(o.permlink); + d.last_update = o.last_update; + d.created = o.created; + d.active = o.active; + d.last_payout = o.last_payout; + d.depth = o.depth; + d.children = o.children; + d.children_rshares2 = o.children_rshares2; + d.net_rshares = o.net_rshares; + d.abs_rshares = o.abs_rshares; + d.vote_rshares = o.vote_rshares; + d.children_abs_rshares = o.children_abs_rshares; + d.cashout_time = o.cashout_time; + d.max_cashout_time = o.max_cashout_time; + d.total_vote_weight = o.total_vote_weight; + d.reward_weight = o.reward_weight; + d.total_payout_value = o.total_payout_value; + d.curator_payout_value = o.curator_payout_value; + d.author_rewards = o.author_rewards; + d.net_votes = o.net_votes; + d.mode = o.mode; + d.root_comment = o.root_comment; + d.max_accepted_payout = o.max_accepted_payout; + d.percent_steem_dollars = o.percent_steem_dollars; + d.allow_replies = o.allow_replies; + d.allow_votes = o.allow_votes; + d.allow_curation_rewards = o.allow_curation_rewards; + + for (auto& route : o.beneficiaries) { + d.beneficiaries.push_back(route); + } + + if ( fill_comment_content_ ) { + fill_comment_content_(database(), o, d); + } + + if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { + d.category = to_string(o.parent_permlink); + } else { + d.category = to_string(database().get(o.root_comment).parent_permlink); + } + } + // get_comment_content void discussion_helper::impl::fill_comment_content(const golos::chain::database & db, const comment_object & co, comment_api_object & con) { diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index bda37c05ce..863755c576 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -49,6 +49,8 @@ namespace golos { namespace api { comment_api_object create_comment_api_object(const comment_object& o) const; + void fill_comment_api_object(const comment_object& o, discussion& d) const; + private: struct impl; diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 77fd7c4458..a420e158f6 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -178,7 +178,7 @@ namespace golos { namespace plugins { namespace social_network { struct operation_visitor { using result_type = void; - golos::chain::database &db; + golos::chain::database& db; content_depth_params depth_parameters; operation_visitor(golos::chain::database& db, const content_depth_params& params) : db(db), depth_parameters(params) { @@ -237,9 +237,6 @@ namespace golos { namespace plugins { namespace social_network { ) { from_string(con.json_metadata, o.json_metadata ); } - else { - wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", ("a", o.author)("p", o.permlink)); - } } if (o.body.size() && (!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0)) { try { @@ -273,7 +270,7 @@ namespace golos { namespace plugins { namespace social_network { else { // Creation case - const auto &new_comment = db.get_comment(o.author, o.permlink); + const auto& new_comment = db.get_comment(o.author, o.permlink); comment_id_type id = new_comment.id; db.create([&](comment_content_object& con) { @@ -291,10 +288,6 @@ namespace golos { namespace plugins { namespace social_network { ) { from_string(con.json_metadata, o.json_metadata); } - else { - wlog("Comment ${a}/${p} contains invalid UTF-8 metadata", - ("a", o.author)("p", o.permlink)); - } con.block_number = db.head_block_num(); }); @@ -307,7 +300,7 @@ namespace golos { namespace plugins { namespace social_network { return; } - const auto &comment = db.get_comment(o.author, o.permlink); + const auto& comment = db.get_comment(o.author, o.permlink); if (find_comment_content(comment.id) == nullptr) { return; diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index a66ec6b800..8820898906 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -15,7 +15,7 @@ namespace golos { namespace plugins { namespace tags { using result_type = void; database& db_; - const std::unique_ptr & helper_; + const std::unique_ptr& helper_; void remove_stats(const tag_object& tag) const; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index dc1d07ae47..dcf4dd80d5 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -111,6 +111,7 @@ namespace golos { namespace plugins { namespace tags { discussion create_discussion(const comment_object& o) const; discussion create_discussion(const comment_object& o, const discussion_query& query) const; void fill_discussion(discussion& d, const discussion_query& query) const; + void fill_comment_api_object(const comment_object& o, discussion& d) const; comment_api_object create_comment_api_object(const comment_object & o) const; @@ -145,6 +146,10 @@ namespace golos { namespace plugins { namespace tags { return helper->create_discussion(o); } + void tags_plugin::impl::fill_comment_api_object(const comment_object& o, discussion& d) const { + helper->fill_comment_api_object(o, d); + } + void tags_plugin::impl::fill_discussion(discussion& d, const discussion_query& query) const { set_url(d); set_pending_payout(d); @@ -624,7 +629,9 @@ namespace golos { namespace plugins { namespace tags { if (!query.is_good_tags(p) || !query.is_good_author(p.author)) { continue; } - result.emplace_back(pimpl->create_comment_api_object(*itr)); + discussion d; + pimpl->fill_comment_api_object(*itr, d); + result.emplace_back(d); pimpl->fill_discussion(result.back(), query); } } From 83fe6f3e00af72c063995489fc11b53e3423745a Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sun, 15 Jul 2018 11:34:18 +0300 Subject: [PATCH 065/250] Removed extra calls of create_comment_api_object. #796 --- libraries/api/discussion_helper.cpp | 5 +++-- plugins/tags/plugin.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index c52055b961..6be4f91cef 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -354,8 +354,9 @@ namespace golos { namespace api { } discussion discussion_helper::impl::create_discussion(const comment_object& o) const { - auto x = create_comment_api_object(o); - return discussion(x); + discussion d; + fill_comment_api_object(o, d); + return d; } discussion discussion_helper::create_discussion(const std::string& author) const { diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index dcf4dd80d5..9b1f78365f 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -625,7 +625,8 @@ namespace golos { namespace plugins { namespace tags { for (; itr != idx.end() && itr->author == *query.start_author && result.size() < query.limit; ++itr) { if (itr->parent_author.size() > 0) { - discussion p( pimpl->create_comment_api_object(db.get(itr->root_comment) ) ); + discussion p; + pimpl->fill_comment_api_object(db.get(itr->root_comment), p); if (!query.is_good_tags(p) || !query.is_good_author(p.author)) { continue; } From c110826242e35350824da7bbcdcace6f364248d3 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sun, 15 Jul 2018 12:14:56 +0300 Subject: [PATCH 066/250] Some minor fixes. #796 --- libraries/api/discussion_helper.cpp | 21 ++++++++++++++++----- plugins/social_network/social_network.cpp | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 6be4f91cef..4c4116a2ef 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -332,13 +332,24 @@ namespace golos { namespace api { void discussion_helper::impl::set_url(discussion& d) const { comment_object cm = database().get(d.root_comment); - comment_api_object root = create_comment_api_object( cm ); + comment_api_object con; - d.root_title = root.title; - d.url = "/" + root.category + "/@" + root.author + "/" + root.permlink; + if (fill_comment_content_) { + fill_comment_content(database(), cm, con); + } + + d.root_title = con.title; + + if (cm.parent_author == STEEMIT_ROOT_POST_PARENT) { + d.category = to_string(cm.parent_permlink); + } else { + d.category = to_string(cm.parent_permlink); + } + + d.url = "/" + d.category + "/@" + cm.author + "/" + cm.permlink; - if (root.id != d.id) { - d.url += "#@" + d.author + "/" + d.permlink; + if (cm.id != d.id) { + d.url += "#@" + cm.author + "/" + cm.permlink; } } diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index a420e158f6..fc2320fe21 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -207,7 +207,7 @@ namespace golos { namespace plugins { namespace social_network { } void operator()(const delete_comment_operation& o) const { - const auto &comment = db.get_comment(o.author, o.permlink); + const auto& comment = db.get_comment(o.author, o.permlink); if (find_comment_content(comment.id) == nullptr) { return; } From e630103b44ec95a05ad4231e24f37388cea1f424 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Sun, 15 Jul 2018 23:43:00 +0700 Subject: [PATCH 067/250] Add producer_reward_operation to mongodb. #743 --- .../include/golos/plugins/mongo_db/mongo_db_operations.hpp | 1 + .../include/golos/plugins/mongo_db/mongo_db_state.hpp | 1 + plugins/mongo_db/mongo_db_operations.cpp | 4 ++++ plugins/mongo_db/mongo_db_state.cpp | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp index cb91c15420..c24d9c5af2 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp @@ -74,6 +74,7 @@ namespace mongo_db { result_type operator()(const shutdown_witness_operation& op); result_type operator()(const fill_transfer_from_savings_operation& op); result_type operator()(const hardfork_operation& op); + result_type operator()(const producer_reward_operation& op); result_type operator()(const comment_payout_update_operation& op); result_type operator()(const comment_benefactor_reward_operation& op); // diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp index e8a7aa4ec9..122e6ee301 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp @@ -78,6 +78,7 @@ namespace mongo_db { result_type operator()(const shutdown_witness_operation& op); result_type operator()(const fill_transfer_from_savings_operation& op); result_type operator()(const hardfork_operation& op); + result_type operator()(const producer_reward_operation& op); result_type operator()(const comment_payout_update_operation& op); result_type operator()(const comment_benefactor_reward_operation& op); result_type operator()(const return_vesting_delegation_operation& op); diff --git a/plugins/mongo_db/mongo_db_operations.cpp b/plugins/mongo_db/mongo_db_operations.cpp index 4e4bd6a324..bbed9ead64 100644 --- a/plugins/mongo_db/mongo_db_operations.cpp +++ b/plugins/mongo_db/mongo_db_operations.cpp @@ -694,6 +694,10 @@ namespace mongo_db { return body; } + auto operation_writer::operator()(const producer_reward_operation& op) -> result_type { + + } + auto operation_writer::operator()(const comment_payout_update_operation& op) -> result_type { result_type body; diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index d02c303198..f7897f7d1a 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -1552,6 +1552,10 @@ namespace mongo_db { } + auto state_writer::operator()(const producer_reward_operation& op) -> result_type { + + } + auto state_writer::operator()(const comment_payout_update_operation& op) -> result_type { format_comment(op.author, op.permlink); } From f3e3e80e94111c082513107e49479e50cab4590a Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sun, 15 Jul 2018 22:02:36 +0300 Subject: [PATCH 068/250] Removed extra comment_api_object creating to improve the performance. #796 --- libraries/api/discussion_helper.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 4c4116a2ef..27d0369462 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -334,22 +334,16 @@ namespace golos { namespace api { comment_api_object con; - if (fill_comment_content_) { - fill_comment_content(database(), cm, con); - } - - d.root_title = con.title; - if (cm.parent_author == STEEMIT_ROOT_POST_PARENT) { d.category = to_string(cm.parent_permlink); } else { d.category = to_string(cm.parent_permlink); } - d.url = "/" + d.category + "/@" + cm.author + "/" + cm.permlink; + d.url = "/" + d.category + "/@" + cm.author + "/" + to_string(cm.permlink); if (cm.id != d.id) { - d.url += "#@" + cm.author + "/" + cm.permlink; + d.url += "#@" + cm.author + "/" + to_string(cm.permlink); } } From da128da3bffdaa9b43abb65f5957a4ab2da8d53e Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Sun, 15 Jul 2018 22:07:27 +0300 Subject: [PATCH 069/250] Changed social_network space_id number to 6. #796 --- .../golos/plugins/social_network/comment_content_object.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index e8bfdc4436..224762e96e 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -12,7 +12,7 @@ namespace golos { namespace plugins { namespace social_network { using namespace golos::chain; #ifndef SOCIAL_NETWORK_SPACE_ID - #define SOCIAL_NETWORK_SPACE_ID 23 + #define SOCIAL_NETWORK_SPACE_ID 6 #endif enum social_network_types { From 01140f34dc688a45a2f32e7e189561cbcb486fcd Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 16 Jul 2018 07:51:53 +0700 Subject: [PATCH 070/250] Remove usage of internal boost test macros #786 --- tests/common/database_fixture.hpp | 57 ++++++++----------------------- tests/tests/operation_tests.cpp | 3 +- 2 files changed, 17 insertions(+), 43 deletions(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index f2e95edaf5..2908b63978 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -82,32 +82,30 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); try { \ BOOST_TEST_PASSPOINT(); \ S; \ - BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected", TL, CHECK_MSG ); } \ + BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected" ); } \ catch( E const& ex ) { \ - ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ - BOOST_CHECK_IMPL( true, "exception '" BOOST_STRINGIZE( E ) "' is caught", TL, CHECK_MSG ); \ const fc::variant_object &props = ex.get_log().at(0).get_data(); \ try { \ C; \ } catch (const fc::exception& err) { \ - BOOST_CHECK_IMPL( false, "caught exception '" << err.name() << "' while check props:" << \ - err.to_detail_string(), TL, CHECK_MSG); \ + BOOST_##TL( "caught exception '" << err.name() << "' while check props:" << \ + err.to_detail_string()); \ } \ } catch ( ... ) { \ try { \ throw; \ } catch (const fc::exception& ex) { \ - BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ - "but '" << ex.name() << "' is caught", TL, CHECK_MSG); \ + BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ + "but '" << ex.name() << "' is caught"); \ } catch (...) { \ - BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) " is expected, " \ - "but unknown is caught", TL, CHECK_MSG); \ + BOOST_##TL( "exception " BOOST_STRINGIZE( E ) " is expected, " \ + "but unknown is caught"); \ } \ } \ #define GOLOS_WARN_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, WARN) -#define GOLOS_CHECK_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, CHECK) -#define GOLOS_REQUIRE_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, REQUIRE) +#define GOLOS_CHECK_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, ERROR) +#define GOLOS_REQUIRE_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, FAIL) template struct ErrorValidator {}; @@ -145,7 +143,7 @@ struct ErrorValidator { void validate(const std::string& name, const fc::variant& props, int index, ErrorValidateFunc validator = NULL) { BOOST_CHECK_EQUAL(name, "tx_invalid_operation"); - BOOST_CHECK_EQUAL(props["index"].as_uint64(), index); + BOOST_CHECK_EQUAL(props["index"].as_int64(), index); if(validator) { validator(props["error"]["name"].get_string(), props["error"]["stack"][(size_t)0]["data"]); } @@ -192,37 +190,12 @@ struct ErrorValidator { } }; -#define GOLOS_CHECK_ERROR_PROPS_IMPL( S, E, C, TL ) \ - try { \ - BOOST_TEST_PASSPOINT(); \ - S; \ - BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected", TL, CHECK_MSG ); } \ - catch( E const& ex ) { \ - ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ - BOOST_CHECK_IMPL( true, "exception '" BOOST_STRINGIZE( E ) "' is caught", TL, CHECK_MSG ); \ - const std::string name = ex.name(); \ - const fc::variant_object &props = ex.get_log().at(0).get_data(); \ - try { \ - C(name, props); \ - } catch (const fc::exception& err) { \ - BOOST_CHECK_IMPL( false, "caught exception '" << err.name() << "' while check props:" << \ - err.to_detail_string(), TL, CHECK_MSG); \ - } \ - } catch ( ... ) { \ - try { \ - throw; \ - } catch (const fc::exception& ex) { \ - BOOST_CHECK_IMPL( false, "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ - "but '" << ex.name() << "' is caught", TL, CHECK_MSG); \ - } catch (...) { \ - BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) " is expected, " \ - "but unknown is caught", TL, CHECK_MSG); \ - } \ - } \ +#define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ + GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) -#define GOLOS_WARN_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, WARN) -#define GOLOS_CHECK_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, CHECK) -#define GOLOS_REQUIRE_ERROR_PROPS(S, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C, REQUIRE) +#define GOLOS_WARN_ERROR_PROPS(S, C) GOLOS_CHECK_ERROR_PROPS_IMPL(S, C, WARN) +#define GOLOS_CHECK_ERROR_PROPS(S, C) GOLOS_CHECK_ERROR_PROPS_IMPL(S, C, ERROR) +#define GOLOS_REQUIRE_ERROR_PROPS(S, C) GOLOS_CHECK_ERROR_PROPS_IMPL(S, C, FAIL) ///This simply resets v back to its default-constructed value. Requires v to have a working assingment operator and diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 19302570c1..44fad6db4f 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -590,7 +590,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.sign(sam_private_key, db->get_chain_id()); GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_invalid_operation, 0, - CHECK_ERROR(bandwidth_exception, golos::bandwidth_exception::comment_bandwidth))); + CHECK_ERROR(bandwidth_exception, golos::bandwidth_exception::post_bandwidth))); validate_database(); @@ -5332,6 +5332,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("failure when memo too large"); + op.amount = ASSET("1.000 GOLOS"); op.memo = string(STEEMIT_MAX_MEMO_SIZE, ' '); GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "memo")); From 607066ce88cd5b8a986a586721ceea209bf85ade Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 16 Jul 2018 12:35:21 +0300 Subject: [PATCH 071/250] Fixed logic in social_network::on_block. Refactored discussion_helper a bit. #796 --- libraries/api/CMakeLists.txt | 1 - libraries/api/comment_api_object.cpp | 46 -------------- libraries/api/discussion_helper.cpp | 60 ++----------------- .../include/golos/api/comment_api_object.hpp | 3 - .../include/golos/api/discussion_helper.hpp | 2 +- plugins/social_network/social_network.cpp | 9 ++- 6 files changed, 13 insertions(+), 108 deletions(-) delete mode 100644 libraries/api/comment_api_object.cpp diff --git a/libraries/api/CMakeLists.txt b/libraries/api/CMakeLists.txt index 972a068b78..b7efed09ef 100644 --- a/libraries/api/CMakeLists.txt +++ b/libraries/api/CMakeLists.txt @@ -16,7 +16,6 @@ list(APPEND CURRENT_TARGET_SOURCES discussion_helper.cpp chain_api_properties.cpp witness_api_object.cpp - comment_api_object.cpp ) if(BUILD_SHARED_LIBRARIES) diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp deleted file mode 100644 index f6a043088c..0000000000 --- a/libraries/api/comment_api_object.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include - -namespace golos { namespace api { - - using namespace golos::chain; - comment_api_object::comment_api_object() = default; - comment_api_object::comment_api_object(const comment_api_object& o ) { - id = o.id; - parent_author = o.parent_author; - parent_permlink = o.parent_permlink; - author = o.author; - permlink = o.permlink; - last_update = o.last_update; - created = o.created; - active = o.active; - last_payout = o.last_payout; - depth = o.depth; - children = o.children; - children_rshares2 = o.children_rshares2; - net_rshares = o.net_rshares; - abs_rshares = o.abs_rshares; - vote_rshares = o.vote_rshares; - children_abs_rshares = o.children_abs_rshares; - cashout_time = o.cashout_time; - max_cashout_time = o.max_cashout_time; - total_vote_weight = o.total_vote_weight; - reward_weight = o.reward_weight; - total_payout_value = o.total_payout_value; - curator_payout_value = o.curator_payout_value; - author_rewards = o.author_rewards; - net_votes = o.net_votes; - mode = o.mode; - root_comment = o.root_comment; - max_accepted_payout = o.max_accepted_payout; - percent_steem_dollars = o.percent_steem_dollars; - allow_replies = o.allow_replies; - allow_votes = o.allow_votes; - allow_curation_rewards = o.allow_curation_rewards; - beneficiaries = o.beneficiaries; - title = o.title; - body = o.body; - json_metadata = o.json_metadata; - category = o.category; - } - -} } //golos::api \ No newline at end of file diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 27d0369462..6936ea5cb0 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -107,7 +107,7 @@ namespace golos { namespace api { void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); - void fill_comment_api_object(const comment_object& o, discussion& d) const; + void fill_comment_api_object(const comment_object& o, comment_api_object& d) const; private: golos::chain::database& database_; @@ -124,62 +124,18 @@ namespace golos { namespace api { comment_api_object discussion_helper::impl::create_comment_api_object(const comment_object & o) const { comment_api_object result; - result.id = o.id; - result.parent_author = o.parent_author; - result.parent_permlink = to_string(o.parent_permlink); - result.author = o.author; - result.permlink = to_string(o.permlink); - result.last_update = o.last_update; - result.created = o.created; - result.active = o.active; - result.last_payout = o.last_payout; - result.depth = o.depth; - result.children = o.children; - result.children_rshares2 = o.children_rshares2; - result.net_rshares = o.net_rshares; - result.abs_rshares = o.abs_rshares; - result.vote_rshares = o.vote_rshares; - result.children_abs_rshares = o.children_abs_rshares; - result.cashout_time = o.cashout_time; - result.max_cashout_time = o.max_cashout_time; - result.total_vote_weight = o.total_vote_weight; - result.reward_weight = o.reward_weight; - result.total_payout_value = o.total_payout_value; - result.curator_payout_value = o.curator_payout_value; - result.author_rewards = o.author_rewards; - result.net_votes = o.net_votes; - result.mode = o.mode; - result.root_comment = o.root_comment; - result.max_accepted_payout = o.max_accepted_payout; - result.percent_steem_dollars = o.percent_steem_dollars; - result.allow_replies = o.allow_replies; - result.allow_votes = o.allow_votes; - result.allow_curation_rewards = o.allow_curation_rewards; - - for (auto& route : o.beneficiaries) { - result.beneficiaries.push_back(route); - } - - if ( fill_comment_content_ ) { - fill_comment_content_(database(), o, result); - } - - if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { - result.category = to_string(o.parent_permlink); - } else { - result.category = to_string(database().get(o.root_comment).parent_permlink); - } + fill_comment_api_object(o, result); return result; } // fill_comment_api_object - void discussion_helper::fill_comment_api_object(const comment_object& o, discussion& d) const { + void discussion_helper::fill_comment_api_object(const comment_object& o, comment_api_object& d) const { pimpl->fill_comment_api_object(o, d); } - void discussion_helper::impl::fill_comment_api_object(const comment_object& o, discussion& d) const { + void discussion_helper::impl::fill_comment_api_object(const comment_object& o, comment_api_object& d) const { d.id = o.id; d.parent_author = o.parent_author; d.parent_permlink = to_string(o.parent_permlink); @@ -332,13 +288,7 @@ namespace golos { namespace api { void discussion_helper::impl::set_url(discussion& d) const { comment_object cm = database().get(d.root_comment); - comment_api_object con; - - if (cm.parent_author == STEEMIT_ROOT_POST_PARENT) { - d.category = to_string(cm.parent_permlink); - } else { - d.category = to_string(cm.parent_permlink); - } + d.root_title = d.title; d.url = "/" + d.category + "/@" + cm.author + "/" + to_string(cm.permlink); diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 334b96c730..4d511cc5df 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -10,9 +10,6 @@ namespace golos { namespace api { using namespace golos::chain; struct comment_api_object { - comment_api_object(); - comment_api_object(const comment_api_object& o ); - comment_object::id_type id; std::string title; diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 863755c576..cda56afc81 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -49,7 +49,7 @@ namespace golos { namespace api { comment_api_object create_comment_api_object(const comment_object& o) const; - void fill_comment_api_object(const comment_object& o, discussion& d) const; + void fill_comment_api_object(const comment_object& o, comment_api_object& d) const; private: diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index fc2320fe21..c28e419636 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -351,7 +351,7 @@ namespace golos { namespace plugins { namespace social_network { const auto &idx = db.get_index().indices().get(); - for (auto itr = idx.begin(); itr != idx.end(); ++itr) { + for (auto itr = idx.begin(); itr != idx.end();) { auto & content = *itr; const auto &cidx = db.get_index().indices().get(); @@ -362,9 +362,10 @@ namespace golos { namespace plugins { namespace social_network { auto time_delta = db.head_block_time() - comment->created; auto delta = db.head_block_num() - content.block_number; - if (time_delta.to_seconds() > fc::microseconds(cash_window_sec * 1000000).to_seconds() && depth_parameters.should_delete_part_of_content_object(delta)) { + if (time_delta.to_seconds() > cash_window_sec && depth_parameters.should_delete_part_of_content_object(delta)) { if (depth_parameters.should_delete_whole_content_object(delta)) { db.remove(content); + ++itr; continue; } db.modify(content, [&](comment_content_object& con) { @@ -379,9 +380,13 @@ namespace golos { namespace plugins { namespace social_network { if (delta > depth_parameters.comment_json_metadata_depth) { con.json_metadata.clear(); } + ++itr; }); } + else { + break; + } } } FC_CAPTURE_AND_RETHROW() } From d16065d5af5ae3e84655dd83184e433eda3884b0 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 16 Jul 2018 13:01:00 +0300 Subject: [PATCH 072/250] Fixed condition. #796 --- plugins/social_network/social_network.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index c28e419636..d935d8bc4e 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -222,11 +222,8 @@ namespace golos { namespace plugins { namespace social_network { const auto& comment = db.get_comment(o.author, o.permlink); - if (comment.created != db.head_block_time()) { + if (find_comment_content(comment.id) != nullptr) { // Edit case - if (find_comment_content(comment.id) == nullptr) { - return; - } db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { from_string(con.title, o.title); From d7089ea3bb8e4814cfbf033382d1e4b58a6d3a8c Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 16 Jul 2018 17:34:46 +0700 Subject: [PATCH 073/250] Fix build CHECK_ERROR macros by clang #786 --- tests/common/database_fixture.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 2908b63978..caf8362386 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -110,7 +110,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); template struct ErrorValidator {}; -typedef void (*ErrorValidateFunc)(const std::string&, const fc::variant& props); +using ErrorValidateFunc = std::function; #define CHECK_ERROR(exception, ...) [&](const std::string& name, const fc::variant& props) \ {\ From 42141a3c46594b30c7762d40a77a8673947ac272 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 16 Jul 2018 14:43:17 +0300 Subject: [PATCH 074/250] Fixed few perfomance bugs. #796 --- libraries/api/discussion_helper.cpp | 2 -- .../include/golos/api/comment_api_object.hpp | 2 ++ plugins/social_network/social_network.cpp | 19 +++++++++---------- plugins/tags/plugin.cpp | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 6936ea5cb0..438810d5a4 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -288,8 +288,6 @@ namespace golos { namespace api { void discussion_helper::impl::set_url(discussion& d) const { comment_object cm = database().get(d.root_comment); - d.root_title = d.title; - d.url = "/" + d.category + "/@" + cm.author + "/" + to_string(cm.permlink); if (cm.id != d.id) { diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 4d511cc5df..6a6bd94742 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -54,6 +54,8 @@ namespace golos { namespace api { comment_mode mode = not_set; comment_object::id_type root_comment; + + string root_title; protocol::asset max_accepted_payout; uint16_t percent_steem_dollars = 0; diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index d935d8bc4e..1984c4926b 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -220,11 +220,11 @@ namespace golos { namespace plugins { namespace social_network { return; } - const auto& comment = db.get_comment(o.author, o.permlink); + const auto comment = db.find_comment(o.author, o.permlink); - if (find_comment_content(comment.id) != nullptr) { + if ( comment != nullptr) { // Edit case - db.modify(db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { + db.modify(db.get< comment_content_object, by_comment >( comment->id ), [&]( comment_content_object& con ) { if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { from_string(con.title, o.title); } @@ -266,9 +266,7 @@ namespace golos { namespace plugins { namespace social_network { } else { // Creation case - - const auto& new_comment = db.get_comment(o.author, o.permlink); - comment_id_type id = new_comment.id; + comment_id_type id = comment->id; db.create([&](comment_content_object& con) { con.comment = id; @@ -299,11 +297,12 @@ namespace golos { namespace plugins { namespace social_network { const auto& comment = db.get_comment(o.author, o.permlink); - if (find_comment_content(comment.id) == nullptr) { + auto* content_ptr = find_comment_content(comment.id); + if (content_ptr == nullptr) { return; } + auto& content = *content_ptr; - auto &content = get_comment_content(comment.id); auto delta = db.head_block_num() - content.block_number; @@ -350,6 +349,7 @@ namespace golos { namespace plugins { namespace social_network { for (auto itr = idx.begin(); itr != idx.end();) { auto & content = *itr; + ++itr; const auto &cidx = db.get_index().indices().get(); @@ -362,7 +362,6 @@ namespace golos { namespace plugins { namespace social_network { if (time_delta.to_seconds() > cash_window_sec && depth_parameters.should_delete_part_of_content_object(delta)) { if (depth_parameters.should_delete_whole_content_object(delta)) { db.remove(content); - ++itr; continue; } db.modify(content, [&](comment_content_object& con) { @@ -377,7 +376,6 @@ namespace golos { namespace plugins { namespace social_network { if (delta > depth_parameters.comment_json_metadata_depth) { con.json_metadata.clear(); } - ++itr; }); } @@ -659,6 +657,7 @@ namespace golos { namespace plugins { namespace social_network { auto & content = db.get(co.id); con.title = std::string(content.title.begin(), content.title.end()); + con.root_title = con.title; con.body = std::string(content.body.begin(), content.body.end()); con.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); } diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 9b1f78365f..162a7f1f65 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -632,7 +632,7 @@ namespace golos { namespace plugins { namespace tags { } discussion d; pimpl->fill_comment_api_object(*itr, d); - result.emplace_back(d); + result.push_back(std::move(d)); pimpl->fill_discussion(result.back(), query); } } From 9dc1a30ef53c718bb83ab7e7c3f6f8144dfca619 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Wed, 11 Jul 2018 18:50:17 +0300 Subject: [PATCH 075/250] Remove IS_LOW_MEM around comment_object::parent #799 --- libraries/chain/database.cpp | 9 ++------- libraries/chain/steem_evaluator.cpp | 4 ---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 76ba212e48..7a4624c906 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -4812,12 +4812,7 @@ namespace golos { namespace chain { for (auto itr = cidx.begin(); itr != cidx.end(); ++itr) { if (itr->parent_author != STEEMIT_ROOT_POST_PARENT) { -// Low memory nodes only need immediate child count, full nodes track total children -#ifdef IS_LOW_MEM - modify(get_comment(itr->parent_author, itr->parent_permlink), [&](comment_object &c) { - c.children++; - }); -#else + const comment_object *parent = &get_comment(itr->parent_author, itr->parent_permlink); while (parent) { modify(*parent, [&](comment_object &c) { @@ -4830,7 +4825,7 @@ namespace golos { namespace chain { parent = nullptr; } } -#endif + } } } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 721931df58..5c8b10731d 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -377,11 +377,9 @@ namespace golos { namespace chain { p.children--; p.active = now; }); -#ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -#endif { parent = nullptr; } @@ -628,11 +626,9 @@ namespace golos { namespace chain { p.children++; p.active = now; }); -#ifndef IS_LOW_MEM if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); } else -#endif { parent = nullptr; } From aef06bf892a3c691c7852c5a8fa3dab260b330f8 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 16 Jul 2018 17:03:00 +0300 Subject: [PATCH 076/250] Fixed root_title filling. #796 --- plugins/social_network/social_network.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 1984c4926b..9a942f5601 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -654,10 +654,12 @@ namespace golos { namespace plugins { namespace social_network { if (!db.has_index()) { return; } - auto & content = db.get(co.id); + const auto & content = db.get(co.id); + const auto root_content = db.find(co.root_comment); + con.root_title = std::string(root_content->title.begin(), root_content->title.end()); + con.title = std::string(content.title.begin(), content.title.end()); - con.root_title = con.title; con.body = std::string(content.body.begin(), content.body.end()); con.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); } From 7b4ff21e043c015ebfddc3222cdf71c5aa3d8832 Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Mon, 16 Jul 2018 17:46:40 +0300 Subject: [PATCH 077/250] Made some more PR requested changes. #796 --- .../api/include/golos/api/comment_api_object.hpp | 2 +- libraries/api/include/golos/api/discussion.hpp | 3 +-- plugins/social_network/social_network.cpp | 15 +++++++++------ .../include/golos/plugins/tags/tag_visitor.hpp | 4 ++-- plugins/tags/plugin.cpp | 4 ++-- plugins/tags/tag_visitor.cpp | 6 +++--- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 6a6bd94742..248a151b83 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -74,7 +74,7 @@ FC_REFLECT( (created)(active)(last_payout)(depth)(children)(children_rshares2)(net_rshares)(abs_rshares) (vote_rshares)(children_abs_rshares)(cashout_time)(max_cashout_time)(total_vote_weight) (reward_weight)(total_payout_value)(curator_payout_value)(author_rewards)(net_votes) - (mode)(root_comment)(max_accepted_payout)(percent_steem_dollars)(allow_replies)(allow_votes) + (mode)(root_comment)(root_title)(max_accepted_payout)(percent_steem_dollars)(allow_replies)(allow_votes) (allow_curation_rewards)(beneficiaries)) #endif //GOLOS_COMMENT_API_OBJ_H diff --git a/libraries/api/include/golos/api/discussion.hpp b/libraries/api/include/golos/api/discussion.hpp index 691d92016a..c62534084a 100644 --- a/libraries/api/include/golos/api/discussion.hpp +++ b/libraries/api/include/golos/api/discussion.hpp @@ -16,7 +16,6 @@ namespace golos { namespace api { } string url; /// /category/@rootauthor/root_permlink#author/permlink - string root_title; asset pending_payout_value = asset(0, SBD_SYMBOL); ///< sbd asset total_pending_payout_value = asset(0, SBD_SYMBOL); ///< sbd including replies std::vector active_votes; @@ -35,5 +34,5 @@ namespace golos { namespace api { } } // golos::api FC_REFLECT_DERIVED( (golos::api::discussion), ((golos::api::comment_api_object)), - (url)(root_title)(pending_payout_value)(total_pending_payout_value)(active_votes)(active_votes_count)(replies) + (url)(pending_payout_value)(total_pending_payout_value)(active_votes)(active_votes_count)(replies) (author_reputation)(promoted)(body_length)(reblogged_by)(first_reblogged_by)(first_reblogged_on)) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 9a942f5601..4243c7ebf9 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -654,14 +654,17 @@ namespace golos { namespace plugins { namespace social_network { if (!db.has_index()) { return; } - const auto & content = db.get(co.id); + const auto content = db.find(co.id); + if (content != nullptr) { + con.title = std::string(content->title.begin(), content->title.end()); + con.body = std::string(content->body.begin(), content->body.end()); + con.json_metadata = std::string(content->json_metadata.begin(), content->json_metadata.end()); + } const auto root_content = db.find(co.root_comment); - con.root_title = std::string(root_content->title.begin(), root_content->title.end()); - - con.title = std::string(content.title.begin(), content.title.end()); - con.body = std::string(content.body.begin(), content.body.end()); - con.json_metadata = std::string(content.json_metadata.begin(), content.json_metadata.end()); + if (root_content != nullptr) { + con.root_title = std::string(root_content->title.begin(), root_content->title.end()); + } } } } } // golos::plugins::social_network diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 8820898906..f10cc6dd93 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -11,11 +11,11 @@ namespace golos { namespace plugins { namespace tags { using golos::api::discussion_helper; struct operation_visitor { - operation_visitor(database& db, const std::unique_ptr &helper); + operation_visitor(database& db, const discussion_helper &helper); using result_type = void; database& db_; - const std::unique_ptr& helper_; + const discussion_helper& helper_; void remove_stats(const tag_object& tag) const; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 162a7f1f65..8857d619e0 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -45,7 +45,7 @@ namespace golos { namespace plugins { namespace tags { void on_operation(const operation_notification& note) { try { /// plugins shouldn't ever throw - note.op.visit(tags::operation_visitor(database(), helper)); + note.op.visit(tags::operation_visitor(database(), *helper)); } catch (const fc::exception& e) { edump((e.to_detail_string())); } catch (...) { @@ -290,7 +290,7 @@ namespace golos { namespace plugins { namespace tags { query.start_comment = create_discussion(*comment, query); auto& d = query.start_comment; - operation_visitor v(database_, helper); + operation_visitor v(database_, *helper); d.hot = v.calculate_hot(d.net_rshares, d.created); d.trending = v.calculate_trending(d.net_rshares, d.created); diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index cd57939d41..0a1af4412f 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -3,7 +3,7 @@ namespace golos { namespace plugins { namespace tags { - operation_visitor::operation_visitor(database& db, const std::unique_ptr &helper) + operation_visitor::operation_visitor(database& db, const discussion_helper &helper) : db_(db), helper_(helper) { } @@ -174,7 +174,7 @@ namespace golos { namespace plugins { namespace tags { auto trending = calculate_trending(comment.net_rshares, comment.created); const auto& comment_idx = db_.get_index().indices().get(); - auto meta = get_metadata(helper_->create_comment_api_object(comment)); + auto meta = get_metadata(helper_.create_comment_api_object(comment)); auto citr = comment_idx.lower_bound(comment.id); const tag_object* language_tag = nullptr; @@ -307,7 +307,7 @@ namespace golos { namespace plugins { namespace tags { const auto& comment = db_.get_comment(op.author, op.permlink); const auto& author = db_.get_account(op.author).id; - auto meta = get_metadata(helper_->create_comment_api_object(comment)); + auto meta = get_metadata(helper_.create_comment_api_object(comment)); const auto& stats_idx = db_.get_index().indices().get(); const auto& auth_idx = db_.get_index().indices().get(); From 16172d2f3265e5ebc70a73f39b330d64a94b5adb Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Tue, 17 Jul 2018 10:02:02 +0300 Subject: [PATCH 078/250] Fixed convertation to std::string in set_url. Changed space_id number. #796 --- libraries/api/discussion_helper.cpp | 4 ++-- .../golos/plugins/social_network/comment_content_object.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 438810d5a4..63af4e6e37 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -288,10 +288,10 @@ namespace golos { namespace api { void discussion_helper::impl::set_url(discussion& d) const { comment_object cm = database().get(d.root_comment); - d.url = "/" + d.category + "/@" + cm.author + "/" + to_string(cm.permlink); + d.url = "/" + d.category + "/@" + std::string(cm.author) + "/" + to_string(cm.permlink); if (cm.id != d.id) { - d.url += "#@" + cm.author + "/" + to_string(cm.permlink); + d.url += "#@" + d.author + "/" + d.permlink; } } diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index 224762e96e..e49af99c47 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -12,7 +12,7 @@ namespace golos { namespace plugins { namespace social_network { using namespace golos::chain; #ifndef SOCIAL_NETWORK_SPACE_ID - #define SOCIAL_NETWORK_SPACE_ID 6 + #define SOCIAL_NETWORK_SPACE_ID 10 #endif enum social_network_types { From 815dbe376d5c4c3ba7582b99cea908cca4a2bff7 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 17 Jul 2018 00:28:08 +0700 Subject: [PATCH 079/250] Thrown missing_object on get database object which missing #787 --- libraries/api/account_api_object.cpp | 2 +- libraries/api/comment_api_object.cpp | 4 +- libraries/api/discussion_helper.cpp | 4 +- libraries/chain/database.cpp | 74 +++++++++++++++---- libraries/chain/database_proposal_object.cpp | 5 +- .../chain/include/golos/chain/database.hpp | 6 ++ libraries/chain/proposal_object.cpp | 8 +- libraries/chain/steem_evaluator.cpp | 6 +- .../include/golos/protocol/exceptions.hpp | 8 ++ plugins/auth_util/plugin.cpp | 4 +- plugins/database_api/api.cpp | 18 ++--- plugins/tags/plugin.cpp | 2 +- 12 files changed, 101 insertions(+), 40 deletions(-) diff --git a/libraries/api/account_api_object.cpp b/libraries/api/account_api_object.cpp index b5bfe56591..9e1b344980 100644 --- a/libraries/api/account_api_object.cpp +++ b/libraries/api/account_api_object.cpp @@ -38,7 +38,7 @@ account_api_object::account_api_object(const account_object& a, const golos::cha proxied_vsf_votes.push_back(a.proxied_vsf_votes[i]); } - const auto& auth = db.get(name); + const auto& auth = db.get_authority(name); owner = authority(auth.owner); active = authority(auth.active); posting = authority(auth.posting); diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp index 68fdb27ee1..927e72fd30 100644 --- a/libraries/api/comment_api_object.cpp +++ b/libraries/api/comment_api_object.cpp @@ -50,10 +50,10 @@ namespace golos { namespace api { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { category = to_string(o.parent_permlink); } else { - category = to_string(db.get(o.root_comment).parent_permlink); + category = to_string(db.get_comment(o.root_comment).parent_permlink); } } comment_api_object::comment_api_object() = default; -} } // golos::api \ No newline at end of file +} } // golos::api diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 6e71939570..01ace5f930 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -172,7 +172,7 @@ namespace golos { namespace api { fill_reputation_(db, d.author, d.author_reputation); if (d.parent_author != STEEMIT_ROOT_POST_PARENT) { - d.cashout_time = db.calculate_discussion_payout_time(db.get(d.id)); + d.cashout_time = db.calculate_discussion_payout_time(db.get_comment(d.id)); } if (d.body.size() > 1024 * 128) { @@ -191,7 +191,7 @@ namespace golos { namespace api { // // set_url void discussion_helper::impl::set_url(discussion& d) const { - const comment_api_object root(database().get(d.root_comment), database()); + const comment_api_object root(database().get_comment(d.root_comment), database()); d.root_title = root.title; d.url = "/" + root.category + "/@" + root.author + "/" + root.permlink; diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 09038d86cd..b1ff2d20a6 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -601,6 +601,8 @@ namespace golos { namespace chain { const witness_object &database::get_witness(const account_name_type &name) const { try { return get(name); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("witness", name); } FC_CAPTURE_AND_RETHROW((name)) } @@ -612,9 +614,7 @@ namespace golos { namespace chain { try { return get(name); } catch(const std::out_of_range &e) { - //GOLOS_THROW_MISSING_OBJECT("account", name); - GOLOS_ASSERT(false, missing_object, "Missing ${type} with id \"${id}\"", - ("type","account")("id",name)); + GOLOS_THROW_MISSING_OBJECT("account", name); } FC_CAPTURE_AND_RETHROW((name)) } @@ -626,6 +626,8 @@ namespace golos { namespace chain { const comment_object &database::get_comment(const account_name_type &author, const shared_string &permlink) const { try { return get(boost::make_tuple(author, permlink)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("comment", fc::mutable_variant_object()("account", author)("permlink", permlink)); } FC_CAPTURE_AND_RETHROW((author)(permlink)) } @@ -636,6 +638,8 @@ namespace golos { namespace chain { const comment_object &database::get_comment(const account_name_type &author, const string &permlink) const { try { return get(boost::make_tuple(author, permlink)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("comment", fc::mutable_variant_object()("account", author)("permlink", permlink)); } FC_CAPTURE_AND_RETHROW((author)(permlink)) } @@ -643,10 +647,20 @@ namespace golos { namespace chain { return find(boost::make_tuple(author, permlink)); } + const comment_object &database::get_comment(const comment_id_type &comment_id) const { + try { + return get(comment_id); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("comment", comment_id); + } FC_CAPTURE_AND_RETHROW((comment_id)) + } + const comment_content_object &database::get_comment_content(const comment_id_type &comment) const { try { return get(comment); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("comment_content", comment); } FC_CAPTURE_AND_RETHROW((comment)) } @@ -657,6 +671,8 @@ namespace golos { namespace chain { const escrow_object &database::get_escrow(const account_name_type &name, uint32_t escrow_id) const { try { return get(boost::make_tuple(name, escrow_id)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("escrow", fc::mutable_variant_object()("account", name)("escrow", escrow_id)); } FC_CAPTURE_AND_RETHROW((name)(escrow_id)) } @@ -671,6 +687,8 @@ namespace golos { namespace chain { } return get(boost::make_tuple(name, orderid)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("limit_order", fc::mutable_variant_object()("account",name)("order_id", orderid)); } FC_CAPTURE_AND_RETHROW((name)(orderid)) } @@ -685,9 +703,19 @@ namespace golos { namespace chain { const savings_withdraw_object &database::get_savings_withdraw(const account_name_type &owner, uint32_t request_id) const { try { return get(boost::make_tuple(owner, request_id)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("savings_withdraw", fc::mutable_variant_object()("account",owner)("request_id", request_id)); } FC_CAPTURE_AND_RETHROW((owner)(request_id)) } + const account_authority_object &database::get_authority(const account_name_type &name) const { + try { + return get(name); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("authority", name); + } FC_CAPTURE_AND_RETHROW((name)) + } + const savings_withdraw_object *database::find_savings_withdraw(const account_name_type &owner, uint32_t request_id) const { return find(boost::make_tuple(owner, request_id)); } @@ -695,24 +723,40 @@ namespace golos { namespace chain { const dynamic_global_property_object &database::get_dynamic_global_properties() const { try { return get(); + } catch(const std::out_of_range &e) { + GOLOS_THROW_INTERNAL_ERROR("Missing dynamic_global_properties"); } FC_CAPTURE_AND_RETHROW() } const feed_history_object &database::get_feed_history() const { try { return get(); + } catch(const std::out_of_range &e) { + GOLOS_THROW_INTERNAL_ERROR("Missing feed_history"); } FC_CAPTURE_AND_RETHROW() } const witness_schedule_object &database::get_witness_schedule_object() const { try { return get(); + } catch(const std::out_of_range &e) { + GOLOS_THROW_INTERNAL_ERROR("Missing witness_schedule"); } FC_CAPTURE_AND_RETHROW() } const hardfork_property_object &database::get_hardfork_property_object() const { try { return get(); + } catch(const std::out_of_range &e) { + GOLOS_THROW_INTERNAL_ERROR("Missing hardfork_property"); + } FC_CAPTURE_AND_RETHROW() + } + + const block_summary_object &database::get_block_summary(const block_summary_id_type &ref_block_num) const { + try { + return get(ref_block_num); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("block_summary", ref_block_num); } FC_CAPTURE_AND_RETHROW() } @@ -720,7 +764,7 @@ namespace golos { namespace chain { if (has_hardfork(STEEMIT_HARDFORK_0_17__431) || comment.parent_author == STEEMIT_ROOT_POST_PARENT) { return comment.cashout_time; } else { - return get(comment.root_comment).cashout_time; + return get_comment(comment.root_comment).cashout_time; } } @@ -2029,12 +2073,12 @@ namespace golos { namespace chain { STEEMIT_OWNER_AUTH_HISTORY_TRACKING_START_BLOCK_NUM) { create([&](owner_authority_history_object &hist) { hist.account = account.name; - hist.previous_owner_authority = get(account.name).owner; + hist.previous_owner_authority = get_authority(account.name).owner; hist.last_valid_time = head_block_time(); }); } - modify(get(account.name), [&](account_authority_object &auth) { + modify(get_authority(account.name), [&](account_authority_object &auth) { auth.owner = owner_authority; auth.last_owner_update = head_block_time(); }); @@ -3241,15 +3285,15 @@ namespace golos { namespace chain { const chain_id_type &chain_id = STEEMIT_CHAIN_ID; auto get_active = [&](const account_name_type& name) { - return authority(get(name).active); + return authority(get_authority(name).active); }; auto get_owner = [&](const account_name_type& name) { - return authority(get(name).owner); + return authority(get_authority(name).owner); }; auto get_posting = [&](const account_name_type& name) { - return authority(get(name).posting); + return authority(get_authority(name).posting); }; try { @@ -3266,7 +3310,7 @@ namespace golos { namespace chain { // It's impossible that the transaction is expired, and TaPoS makes no sense as no blocks exist. if (BOOST_LIKELY(head_block_num() > 0)) { if (!(skip & skip_tapos_check)) { - const auto &tapos_block_summary = get(trx.ref_block_num); + const auto &tapos_block_summary = get_block_summary(trx.ref_block_num); //Verify TaPoS block summary has correct ID prefix, // and that this block's time is not past the expiration FC_ASSERT( @@ -3703,7 +3747,7 @@ namespace golos { namespace chain { void database::create_block_summary(const signed_block &next_block) { try { block_summary_id_type sid(next_block.block_num() & 0xffff); - modify(get(sid), [&](block_summary_object &p) { + modify(get_block_summary(sid), [&](block_summary_object &p) { p.block_id = next_block.id(); }); } FC_CAPTURE_AND_RETHROW() @@ -4496,17 +4540,17 @@ namespace golos { namespace chain { } } - modify(get(STEEMIT_MINER_ACCOUNT), [&](account_authority_object &auth) { + modify(get_authority(STEEMIT_MINER_ACCOUNT), [&](account_authority_object &auth) { auth.posting = authority(); auth.posting.weight_threshold = 1; }); - modify(get(STEEMIT_NULL_ACCOUNT), [&](account_authority_object &auth) { + modify(get_authority(STEEMIT_NULL_ACCOUNT), [&](account_authority_object &auth) { auth.posting = authority(); auth.posting.weight_threshold = 1; }); - modify(get(STEEMIT_TEMP_ACCOUNT), [&](account_authority_object &auth) { + modify(get_authority(STEEMIT_TEMP_ACCOUNT), [&](account_authority_object &auth) { auth.posting = authority(); auth.posting.weight_threshold = 1; }); @@ -4534,7 +4578,7 @@ namespace golos { namespace chain { update_owner_authority(*account, authority(1, public_key_type("GLS8hLtc7rC59Ed7uNVVTXtF578pJKQwMfdTvuzYLwUi8GkNTh5F6"), 1)); - modify(get(account->name), [&](account_authority_object &auth) { + modify(get_authority(account->name), [&](account_authority_object &auth) { auth.active = authority(1, public_key_type("GLS8hLtc7rC59Ed7uNVVTXtF578pJKQwMfdTvuzYLwUi8GkNTh5F6"), 1); auth.posting = authority(1, public_key_type("GLS8hLtc7rC59Ed7uNVVTXtF578pJKQwMfdTvuzYLwUi8GkNTh5F6"), 1); }); diff --git a/libraries/chain/database_proposal_object.cpp b/libraries/chain/database_proposal_object.cpp index 94e3d0c493..5fb1e099f4 100644 --- a/libraries/chain/database_proposal_object.cpp +++ b/libraries/chain/database_proposal_object.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace golos { namespace chain { @@ -9,6 +10,8 @@ namespace golos { namespace chain { const std::string& title ) const { try { return get(std::make_tuple(author, title)); + } catch (const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("proposal", fc::mutable_variant_object()("account",author)("proposal",title)); } FC_CAPTURE_AND_RETHROW((author)(title)) } const proposal_object *database::find_proposal( @@ -68,4 +71,4 @@ namespace golos { namespace chain { } } -} } // golos::chain \ No newline at end of file +} } // golos::chain diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 6aa9d91026..968b4e64b3 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -172,6 +172,8 @@ namespace golos { namespace chain { const comment_object *find_comment(const account_name_type &author, const string &permlink) const; + const comment_object &get_comment(const comment_id_type &comment) const; + const comment_content_object &get_comment_content(const comment_id_type &comment) const; const comment_content_object *find_comment_content(const comment_id_type &comment) const; @@ -188,6 +190,8 @@ namespace golos { namespace chain { const savings_withdraw_object *find_savings_withdraw(const account_name_type &owner, uint32_t request_id) const; + const account_authority_object &get_authority(const account_name_type &name) const; + const dynamic_global_property_object &get_dynamic_global_properties() const; const feed_history_object &get_feed_history() const; @@ -196,6 +200,8 @@ namespace golos { namespace chain { const hardfork_property_object &get_hardfork_property_object() const; + const block_summary_object &get_block_summary(const block_summary_id_type &ref_block_num) const; + const time_point_sec calculate_discussion_payout_time(const comment_object &comment) const; diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index 25d67bc465..bf185bea3a 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -59,15 +59,15 @@ namespace golos { namespace chain { auto ops = operations(); auto get_active = [&](const account_name_type& name) { - return authority(db.get(name).active); + return authority(db.get_authority(name).active); }; auto get_owner = [&](const account_name_type& name) { - return authority(db.get(name).owner); + return authority(db.get_authority(name).owner); }; auto get_posting = [&](const account_name_type& name) { - return authority(db.get(name).posting); + return authority(db.get_authority(name).posting); }; golos::protocol::verify_authority( @@ -76,4 +76,4 @@ namespace golos { namespace chain { active_approvals, owner_approvals, posting_approvals); } -} } // golos::chain \ No newline at end of file +} } // golos::chain diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index a61c731dec..a489dbd6e7 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -334,7 +334,7 @@ namespace golos { namespace chain { } const auto &account = _db.get_account(o.account); - const auto &account_auth = _db.get(o.account); + const auto &account_auth = _db.get_authority(o.account); if (o.owner) { #ifndef STEEMIT_BUILD_TESTNET @@ -735,7 +735,7 @@ namespace golos { namespace chain { }); #ifndef IS_LOW_MEM - _db.modify(_db.get< comment_content_object, by_comment >( comment.id ), [&]( comment_content_object& con ) { + _db.modify(_db.get_comment_content( comment.id ), [&]( comment_content_object& con ) { if (o.title.size()) from_string(con.title, o.title); if (o.json_metadata.size()) { @@ -1727,7 +1727,7 @@ namespace golos { namespace chain { } const auto &worker_account = db.get_account(name); // verify it exists - const auto &worker_auth = db.get(name); + const auto &worker_auth = db.get_authority(name); FC_ASSERT(worker_auth.active.num_auths() == 1, "Miners can only have one key authority. ${a}", ("a", worker_auth.active)); FC_ASSERT(worker_auth.active.key_auths.size() == diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 91404a421a..fb100dae10 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -110,6 +110,14 @@ "Expected ${min}..${max} argument(s), was ${count}", \ ("count", (args)->size())("min", min)("max", max) ); + +#define GOLOS_THROW_MISSING_OBJECT(type, id, ...) \ + FC_THROW_EXCEPTION(golos::missing_object, "Missing ${type} with id \"${id}\"", \ + ("type",type)("id",id) __VA_ARGS__) + +#define GOLOS_THROW_INTERNAL_ERROR(MSG, ...) \ + FC_THROW_EXCEPTION(golos::internal_error, MSG, __VA_ARGS__) + namespace golos { GOLOS_DECLARE_DERIVED_EXCEPTION( golos_exception, fc::exception, diff --git a/plugins/auth_util/plugin.cpp b/plugins/auth_util/plugin.cpp index c7c165c716..74b531ed49 100644 --- a/plugins/auth_util/plugin.cpp +++ b/plugins/auth_util/plugin.cpp @@ -37,7 +37,7 @@ struct plugin::plugin_impl { std::vector result; const golos::chain::account_authority_object &acct = - db.get(account_name); + db.get_authority(account_name); protocol::authority auth; if ((level == "posting") || (level == "p")) { auth = protocol::authority(acct.posting); @@ -57,7 +57,7 @@ struct plugin::plugin_impl { flat_set avail; protocol::sign_state ss(signing_keys, [&db](const std::string &account_name) -> const protocol::authority { - return protocol::authority(db.get(account_name).active); + return protocol::authority(db.get_authority(account_name).active); }, avail); bool has_authority = ss.check_authority(auth); diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index fa91ea6026..9b4fbb7f74 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -606,13 +606,13 @@ std::set plugin::api_impl::get_required_signatures( auto result = trx.get_required_signatures( STEEMIT_CHAIN_ID, available_keys, [&](std::string account_name) { - return authority(database().get(account_name).active); + return authority(database().get_authority(account_name).active); }, [&](std::string account_name) { - return authority(database().get(account_name).owner); + return authority(database().get_authority(account_name).owner); }, [&](std::string account_name) { - return authority(database().get(account_name).posting); + return authority(database().get_authority(account_name).posting); }, STEEMIT_MAX_SIG_CHECK_DEPTH ); @@ -632,21 +632,21 @@ std::set plugin::api_impl::get_potential_signatures(const signe std::set result; trx.get_required_signatures(STEEMIT_CHAIN_ID, flat_set(), [&](account_name_type account_name) { - const auto &auth = database().get(account_name).active; + const auto &auth = database().get_authority(account_name).active; for (const auto &k : auth.get_keys()) { result.insert(k); } return authority(auth); }, [&](account_name_type account_name) { - const auto &auth = database().get(account_name).owner; + const auto &auth = database().get_authority(account_name).owner; for (const auto &k : auth.get_keys()) { result.insert(k); } return authority(auth); }, [&](account_name_type account_name) { - const auto &auth = database().get(account_name).posting; + const auto &auth = database().get_authority(account_name).posting; for (const auto &k : auth.get_keys()) { result.insert(k); } @@ -668,11 +668,11 @@ DEFINE_API(plugin, verify_authority) { bool plugin::api_impl::verify_authority(const signed_transaction &trx) const { trx.verify_authority(STEEMIT_CHAIN_ID, [&](std::string account_name) { - return authority(database().get(account_name).active); + return authority(database().get_authority(account_name).active); }, [&](std::string account_name) { - return authority(database().get(account_name).owner); + return authority(database().get_authority(account_name).owner); }, [&](std::string account_name) { - return authority(database().get(account_name).posting); + return authority(database().get_authority(account_name).posting); }, STEEMIT_MAX_SIG_CHECK_DEPTH); return true; } diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index cab209651e..9497aaffd3 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -614,7 +614,7 @@ namespace golos { namespace plugins { namespace tags { for (; itr != idx.end() && itr->author == *query.start_author && result.size() < query.limit; ++itr) { if (itr->parent_author.size() > 0) { - discussion p(db.get(itr->root_comment), db); + discussion p(db.get_comment(itr->root_comment), db); if (!query.is_good_tags(p) || !query.is_good_author(p.author)) { continue; } From ccb56815885c341501e2de01b966efbfaa768e9d Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 18 Jul 2018 09:51:48 +0300 Subject: [PATCH 080/250] Made some more changes requested in PR. #796 --- libraries/api/discussion_helper.cpp | 7 +- .../social_network/comment_content_object.hpp | 8 -- plugins/social_network/social_network.cpp | 85 +++++-------------- 3 files changed, 23 insertions(+), 77 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 63af4e6e37..96d9ad1963 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -172,7 +172,7 @@ namespace golos { namespace api { d.beneficiaries.push_back(route); } - if ( fill_comment_content_ ) { + if (fill_comment_content_) { fill_comment_content_(database(), o, d); } @@ -183,11 +183,6 @@ namespace golos { namespace api { } } - -// get_comment_content - void discussion_helper::impl::fill_comment_content(const golos::chain::database & db, const comment_object & co, comment_api_object & con) { - fill_comment_content_(db, co, con); - } // get_discussion discussion discussion_helper::impl::get_discussion(const comment_object& c, uint32_t vote_limit) const { discussion d = create_discussion(c); diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index e49af99c47..80fe141a7d 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -1,14 +1,6 @@ #pragma once -#include -#include -#include - namespace golos { namespace plugins { namespace social_network { - using plugins::json_rpc::msg_pack; - using golos::api::discussion; - using golos::api::account_vote; - using golos::api::vote_state; using namespace golos::chain; #ifndef SOCIAL_NETWORK_SPACE_ID diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 4243c7ebf9..a041f108da 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -14,8 +14,6 @@ #include #include -#include - #define CHECK_ARG_SIZE(_S) \ FC_ASSERT( \ args.args->size() == _S, \ @@ -220,11 +218,12 @@ namespace golos { namespace plugins { namespace social_network { return; } - const auto comment = db.find_comment(o.author, o.permlink); + const auto& comment = db.get_comment(o.author, o.permlink); + const auto comment_content = db.find(comment.id); - if ( comment != nullptr) { + if ( comment_content != nullptr) { // Edit case - db.modify(db.get< comment_content_object, by_comment >( comment->id ), [&]( comment_content_object& con ) { + db.modify(*comment_content, [&]( comment_content_object& con ) { if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { from_string(con.title, o.title); } @@ -243,7 +242,6 @@ namespace golos { namespace plugins { namespace social_network { auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); auto patched_body = wstring_to_utf8(result.first); if(!fc::is_utf8(patched_body)) { - idump(("invalid utf8")(patched_body)); from_string(con.body, fc::prune_invalid_utf8(patched_body)); } else { @@ -266,7 +264,7 @@ namespace golos { namespace plugins { namespace social_network { } else { // Creation case - comment_id_type id = comment->id; + comment_id_type id = comment.id; db.create([&](comment_content_object& con) { con.comment = id; @@ -288,51 +286,10 @@ namespace golos { namespace plugins { namespace social_network { }); } } - - // Checking should we delete comment_content if needed depth has been expired - void operator()(const comment_payout_update_operation& o) const { - if (!depth_parameters.need_clear()) { - return; - } - - const auto& comment = db.get_comment(o.author, o.permlink); - - auto* content_ptr = find_comment_content(comment.id); - if (content_ptr == nullptr) { - return; - } - auto& content = *content_ptr; - - - auto delta = db.head_block_num() - content.block_number; - - if (depth_parameters.should_delete_whole_content_object(delta)) { - db.remove(content); - return; - } - - if (depth_parameters.should_delete_part_of_content_object(delta)) { - db.modify(content, [&](comment_content_object& con) { - if (delta > depth_parameters.comment_title_depth) { - con.title.clear(); - } - - if (delta > depth_parameters.comment_body_depth) { - con.body.clear(); - } - - if (delta > depth_parameters.comment_json_metadata_depth) { - con.json_metadata.clear(); - } - }); - - return; - } - } - + }; - void social_network::impl::post_operation(const operation_notification &o) { + void social_network::impl::post_operation(const operation_notification& o) { try { auto& db = database(); @@ -341,27 +298,29 @@ namespace golos { namespace plugins { namespace social_network { o.op.visit(ovisit); } FC_CAPTURE_AND_RETHROW() } - void social_network::impl::on_block(const signed_block &b) { + void social_network::impl::on_block(const signed_block& b) { try { - auto & db = database(); + auto& db = database(); - const auto &idx = db.get_index().indices().get(); + const auto& idx = db.get_index().indices().get(); for (auto itr = idx.begin(); itr != idx.end();) { - auto & content = *itr; + auto& content = *itr; ++itr; - const auto &cidx = db.get_index().indices().get(); + const auto&cidx = db.get_index().indices().get(); auto comment = cidx.find(content.comment); - - int64_t cash_window_sec = STEEMIT_CASHOUT_WINDOW_SECONDS; - auto time_delta = db.head_block_time() - comment->created; + auto delta = db.head_block_num() - content.block_number; - if (time_delta.to_seconds() > cash_window_sec && depth_parameters.should_delete_part_of_content_object(delta)) { + if (comment->mode == archived && depth_parameters.should_delete_part_of_content_object(delta)) { if (depth_parameters.should_delete_whole_content_object(delta)) { - db.remove(content); + db.modify(content, [&](comment_content_object& con) { + con.title.clear(); + con.body.clear(); + con.json_metadata.clear(); + }); continue; } db.modify(content, [&](comment_content_object& con) { @@ -418,7 +377,7 @@ namespace golos { namespace plugins { namespace social_network { "max count of storing records of comment.json_metadata" ) ( "set-content-storing-depth-null-after-update", boost::program_options::value()->default_value(false), - "max count of storing records of comment.json_metadata" + "should content's depth be set to null after update" ); } @@ -464,11 +423,11 @@ namespace golos { namespace plugins { namespace social_network { social_network::~social_network() = default; - comment_api_object social_network::impl::create_comment_api_object(const comment_object & o) const { + comment_api_object social_network::impl::create_comment_api_object(const comment_object& o) const { return helper->create_comment_api_object(o); } - comment_api_object social_network::create_comment_api_object(const comment_object & o) const { + comment_api_object social_network::create_comment_api_object(const comment_object& o) const { return pimpl->create_comment_api_object(o); } From ddf3d9bf58e1cd028b4b6a6a5834684cfae23ffd Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 18 Jul 2018 10:05:43 +0300 Subject: [PATCH 081/250] Made some code style fixes. #796 --- libraries/api/discussion_helper.cpp | 8 ++++---- libraries/api/include/golos/api/discussion_helper.hpp | 2 +- .../golos/plugins/social_network/social_network.hpp | 4 ++-- plugins/tags/include/golos/plugins/tags/tag_visitor.hpp | 2 +- plugins/tags/tag_visitor.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 96d9ad1963..573f69f731 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -8,7 +8,7 @@ namespace golos { namespace api { - comment_metadata get_metadata(const comment_api_object &c) { + comment_metadata get_metadata(const comment_api_object& c) { comment_metadata meta; @@ -117,11 +117,11 @@ namespace golos { namespace api { }; // create_comment_api_object - comment_api_object discussion_helper::create_comment_api_object(const comment_object & o) const { + comment_api_object discussion_helper::create_comment_api_object(const comment_object& o) const { return pimpl->create_comment_api_object(o); } - comment_api_object discussion_helper::impl::create_comment_api_object(const comment_object & o) const { + comment_api_object discussion_helper::impl::create_comment_api_object(const comment_object& o) const { comment_api_object result; fill_comment_api_object(o, result); @@ -334,7 +334,7 @@ namespace golos { namespace api { discussion_helper::discussion_helper( golos::chain::database& db, - std::function fill_comment_content + std::function fill_comment_content ) { pimpl = std::make_unique(db, fill_comment_content); } diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index cda56afc81..6d68ed2196 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -10,7 +10,7 @@ namespace golos { namespace api { std::string language; }; - comment_metadata get_metadata(const comment_api_object &c); + comment_metadata get_metadata(const comment_api_object& c); class discussion_helper { public: diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 63fe3437c4..7c97e25902 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -57,8 +57,8 @@ namespace golos { namespace plugins { namespace social_network { comment_api_object create_comment_api_object(const comment_object& o) const; - const comment_content_object &get_comment_content(const comment_id_type& comment) const ; - const comment_content_object *find_comment_content(const comment_id_type& comment) const ; + const comment_content_object& get_comment_content(const comment_id_type& comment) const ; + const comment_content_object* find_comment_content(const comment_id_type& comment) const ; private: diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index f10cc6dd93..2ed59778d4 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -11,7 +11,7 @@ namespace golos { namespace plugins { namespace tags { using golos::api::discussion_helper; struct operation_visitor { - operation_visitor(database& db, const discussion_helper &helper); + operation_visitor(database& db, const discussion_helper& helper); using result_type = void; database& db_; diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index 0a1af4412f..a8a0c49f4e 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -3,7 +3,7 @@ namespace golos { namespace plugins { namespace tags { - operation_visitor::operation_visitor(database& db, const discussion_helper &helper) + operation_visitor::operation_visitor(database& db, const discussion_helper& helper) : db_(db), helper_(helper) { } From 7a8cf01f59fa1293b83eb60de974783512f5a9a0 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 17 Jul 2018 23:28:29 +0700 Subject: [PATCH 082/250] Refactor errors: comment_operation #790 --- libraries/chain/steem_evaluator.cpp | 55 +++--- .../include/golos/protocol/exceptions.hpp | 16 ++ tests/common/database_fixture.hpp | 29 ++- tests/tests/operation_tests.cpp | 171 ++++++++++++------ thirdparty/fc | 2 +- 5 files changed, 190 insertions(+), 83 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 35081ce073..59d74603ca 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -540,8 +540,9 @@ namespace golos { namespace chain { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__55)) - FC_ASSERT(o.title.size() + o.body.size() + - o.json_metadata.size(), "Cannot update comment because nothing appears to be changing."); + GOLOS_CHECK_LOGIC(o.title.size() + o.body.size() + o.json_metadata.size(), + logic_exception::cannot_update_comment_because_nothing_changed, + "Cannot update comment because nothing appears to be changing."); const auto &by_permlink_idx = _db.get_index().indices().get(); auto itr = by_permlink_idx.find(boost::make_tuple(o.author, o.permlink)); @@ -549,8 +550,9 @@ namespace golos { namespace chain { const auto &auth = _db.get_account(o.author); /// prove it exists if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) - FC_ASSERT(!(auth.owner_challenged || - auth.active_challenged), "Operation cannot be processed because account is currently challenged."); + GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), + logic_exception::account_is_currently_challenged, + "Operation cannot be processed because account is currently challenged."); comment_id_type id; @@ -563,19 +565,25 @@ namespace golos { namespace chain { } else if (_db.is_producing()) { max_depth = STEEMIT_SOFT_MAX_COMMENT_DEPTH; } - FC_ASSERT(parent->depth < max_depth, - "Comment is nested ${x} posts deep, maximum depth is ${y}.", - ("x", parent->depth)("y", max_depth)); + GOLOS_CHECK_LOGIC(parent->depth < max_depth, + logic_exception::reached_comment_max_depth, + "Comment is nested ${x} posts deep, maximum depth is ${y}.", + ("x", parent->depth)("y", max_depth)); } auto now = _db.head_block_time(); if (itr == by_permlink_idx.end()) { if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { - FC_ASSERT(_db.get(parent->root_comment).allow_replies, "The parent comment has disabled replies."); + GOLOS_CHECK_LOGIC(_db.get(parent->root_comment).allow_replies, + logic_exception::replies_are_not_allowed, + "The parent comment has disabled replies."); + if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && !_db.has_hardfork( STEEMIT_HARDFORK_0_18__536) ) { - FC_ASSERT( + GOLOS_CHECK_LOGIC( _db.calculate_discussion_payout_time(*parent) != - fc::time_point_sec::maximum(), "Discussion is frozen."); + fc::time_point_sec::maximum(), + logic_exception::discussion_is_frozen, + "Discussion is frozen."); } } @@ -590,7 +598,7 @@ namespace golos { namespace chain { if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__176)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) GOLOS_CHECK_BANDWIDTH(now, band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, - golos::bandwidth_exception::post_bandwidth, + bandwidth_exception::post_bandwidth, "You may only post once every 5 minutes."); else GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, @@ -598,14 +606,17 @@ namespace golos { namespace chain { "You may only comment once every 20 seconds."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_6__113)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) - FC_ASSERT((now - auth.last_post) > - STEEMIT_MIN_ROOT_COMMENT_INTERVAL, "You may only post once every 5 minutes.", ("now", now)("auth.last_post", auth.last_post)); + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, + bandwidth_exception::post_bandwidth, + "You may only post once every 5 minutes."); else - FC_ASSERT((now - auth.last_post) > - STEEMIT_MIN_REPLY_INTERVAL, "You may only comment once every 20 seconds.", ("now", now)("auth.last_post", auth.last_post)); + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, + bandwidth_exception::comment_bandwidth, + "You may only comment once every 20 seconds."); } else { - FC_ASSERT((now - auth.last_post) > - fc::seconds(60), "You may only post once per minute.", ("now", now)("auth.last_post", auth.last_post)); + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + 60, + bandwidth_exception::post_bandwidth, + "You may only post once per minute."); } uint16_t reward_weight = STEEMIT_100_PERCENT; @@ -713,11 +724,13 @@ namespace golos { namespace chain { const auto &comment = *itr; if ( !_db.has_hardfork( STEEMIT_HARDFORK_0_18__536 ) ) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__306)) { - FC_ASSERT(_db.calculate_discussion_payout_time(comment) != fc::time_point_sec::maximum(), - "The comment is archived."); + GOLOS_CHECK_LOGIC(_db.calculate_discussion_payout_time(comment) != fc::time_point_sec::maximum(), + logic_exception::comment_is_archived, + "The comment is archived."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) { - FC_ASSERT(comment.last_payout == fc::time_point_sec::min(), - "Can only edit during the first 24 hours."); + GOLOS_CHECK_LOGIC(comment.last_payout == fc::time_point_sec::min(), + logic_exception::comment_editable_during_first_24_hours, + "Can only edit during the first 24 hours."); } } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 004cca1db2..1214e8f0b1 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -192,6 +192,14 @@ namespace golos { cannot_vote_with_zero_rshares, voter_has_used_maximum_vote_changes, already_voted_in_similar_way, + + // Comment operation + cannot_update_comment_because_nothing_changed, + reached_comment_max_depth, + replies_are_not_allowed, + discussion_is_frozen, + comment_is_archived, + comment_editable_during_first_24_hours, }; }; @@ -302,6 +310,14 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (cannot_vote_with_zero_rshares) (voter_has_used_maximum_vote_changes) (already_voted_in_similar_way) + + // Comment operation + (cannot_update_comment_because_nothing_changed) + (reached_comment_max_depth) + (replies_are_not_allowed) + (discussion_is_frozen) + (comment_is_archived) + (comment_editable_during_first_24_hours) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index a9ed2d8462..05489d2e36 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -82,13 +82,13 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); try { \ BOOST_TEST_PASSPOINT(); \ S; \ - BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected" ); } \ + BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected, but no exception thrown" ); } \ catch( E const& ex ) { \ const fc::variant_object &props = ex.get_log().at(0).get_data(); \ try { \ C; \ } catch (const fc::exception& err) { \ - BOOST_##TL( "caught exception '" << err.name() << "' while check props:" << \ + BOOST_##TL( "caught exception '" << err.name() << "' while check props:" << \ err.to_detail_string()); \ } \ } catch ( ... ) { \ @@ -212,6 +212,21 @@ struct ErrorValidator { } }; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_duplicate_sig"); + } +}; + +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_missing_posting_auth"); + } +}; + #define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) @@ -283,6 +298,16 @@ bool operator==(const fc::variant_object &left, const fc::variant_object &right) } // namespace fc +namespace chainbase { + +template +std::ostream& operator<<(std::ostream& out, const object_id &v) { + out << v._id; + return out; +} + +} // namespace chainbase + namespace golos { namespace protocol { std::ostream& operator<<(std::ostream& out, const asset& v); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index f3e215dba4..e2ed3075eb 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -44,6 +44,12 @@ std::ostream &operator<<(std::ostream &out, const flat_set &t) { } } // namespace boost::container +fc::variant_object make_comment_id(const std::string& author, const std::string& permlink) { + auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); + return fc::variant_object(res); +} + + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_validate) { @@ -377,6 +383,52 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: comment_validate"); + comment_operation op; + op.author = "alice"; + op.permlink = "lorem"; + op.parent_author = ""; + op.parent_permlink = "ipsum"; + op.title = "Lorem Ipsum"; + op.body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + op.json_metadata = "{\"foo\":\"bar\"}"; + + BOOST_TEST_MESSAGE("--- success on valid operation"); + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failed when 'title' too large"); + op.title = std::string(256, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "title")); + + BOOST_TEST_MESSAGE("--- failed when 'body' is empty"); + op.title = "Lorem Ipsum"; + op.body = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "body")); + + BOOST_TEST_MESSAGE("--- failed when 'author' is empty"); + op.body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + op.author = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "author")); + + BOOST_TEST_MESSAGE("--- failed when 'permlink' too large"); + op.author = "alice"; + op.permlink = std::string(STEEMIT_MAX_PERMLINK_LENGTH, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "permlink")); + + BOOST_TEST_MESSAGE("--- failed when 'parent_permlink' too large"); + op.permlink = "lorem"; + op.parent_permlink = std::string(STEEMIT_MAX_PERMLINK_LENGTH, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "parent_permlink")); + + BOOST_TEST_MESSAGE("--- failed when 'json_metadata' is not valid json"); + op.parent_permlink = "ipsum"; + op.json_metadata = "{1:\"string\"}"; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "json_metadata")); validate_database(); } @@ -404,26 +456,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_posting_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_posting_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.sign(alice_post_key, db->get_chain_id()); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with post signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the creator's authority"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_posting_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_posting_auth, 0)); validate_database(); } @@ -452,29 +508,29 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test Alice posting a root comment"); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const comment_object &alice_comment = db->get_comment("alice", string("lorem")); const comment_content_object& alice_content = db->get_comment_content(alice_comment.id); - BOOST_REQUIRE(alice_comment.author == op.author); - BOOST_REQUIRE(to_string(alice_comment.permlink) == op.permlink); - BOOST_REQUIRE(to_string(alice_comment.parent_permlink) == op.parent_permlink); - BOOST_REQUIRE(alice_comment.last_update == db->head_block_time()); - BOOST_REQUIRE(alice_comment.created == db->head_block_time()); - BOOST_REQUIRE(alice_comment.net_rshares.value == 0); - BOOST_REQUIRE(alice_comment.abs_rshares.value == 0); - BOOST_REQUIRE(alice_comment.cashout_time == + BOOST_CHECK_EQUAL(alice_comment.author, op.author); + BOOST_CHECK_EQUAL(to_string(alice_comment.permlink), op.permlink); + BOOST_CHECK_EQUAL(to_string(alice_comment.parent_permlink), op.parent_permlink); + BOOST_CHECK_EQUAL(alice_comment.last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_comment.created, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_comment.net_rshares.value, 0); + BOOST_CHECK_EQUAL(alice_comment.abs_rshares.value, 0); + BOOST_CHECK_EQUAL(alice_comment.cashout_time, fc::time_point_sec(db->head_block_time() + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS))); #ifndef IS_LOW_MEM - BOOST_REQUIRE( to_string( alice_content.title ) == op.title ); - BOOST_REQUIRE( to_string( alice_content.body ) == op.body ); - //BOOST_REQUIRE( alice_content.json_metadata == op.json_metadata ); + BOOST_CHECK_EQUAL( to_string( alice_content.title ), op.title ); + BOOST_CHECK_EQUAL( to_string( alice_content.body ), op.body ); + //BOOST_CHECK_EQUAL( alice_content.json_metadata, op.json_metadata ); #else - BOOST_REQUIRE(to_string(alice_content.title) == ""); - BOOST_REQUIRE(to_string(alice_content.body) == ""); - //BOOST_REQUIRE( alice_content.json_metadata == "" ); + BOOST_CHECK_EQUAL(to_string(alice_content.title), ""); + BOOST_CHECK_EQUAL(to_string(alice_content.body), ""); + //BOOST_CHECK_EQUAL( alice_content.json_metadata, "" ); #endif validate_database(); @@ -489,7 +545,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "comment", make_comment_id("alice", "foobar")))); BOOST_TEST_MESSAGE("--- Test Bob posting a comment on Alice's comment"); op.parent_permlink = "lorem"; @@ -498,20 +556,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const comment_object &bob_comment = db->get_comment("bob", string("ipsum")); - BOOST_REQUIRE(bob_comment.author == op.author); - BOOST_REQUIRE(to_string(bob_comment.permlink) == op.permlink); - BOOST_REQUIRE(bob_comment.parent_author == op.parent_author); - BOOST_REQUIRE(to_string(bob_comment.parent_permlink) == op.parent_permlink); - BOOST_REQUIRE(bob_comment.last_update == db->head_block_time()); - BOOST_REQUIRE(bob_comment.created == db->head_block_time()); - BOOST_REQUIRE(bob_comment.net_rshares.value == 0); - BOOST_REQUIRE(bob_comment.abs_rshares.value == 0); - BOOST_REQUIRE(bob_comment.cashout_time == bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(bob_comment.root_comment == alice_comment.id); + BOOST_CHECK_EQUAL(bob_comment.author, op.author); + BOOST_CHECK_EQUAL(to_string(bob_comment.permlink), op.permlink); + BOOST_CHECK_EQUAL(bob_comment.parent_author, op.parent_author); + BOOST_CHECK_EQUAL(to_string(bob_comment.parent_permlink), op.parent_permlink); + BOOST_CHECK_EQUAL(bob_comment.last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(bob_comment.created, db->head_block_time()); + BOOST_CHECK_EQUAL(bob_comment.net_rshares.value, 0); + BOOST_CHECK_EQUAL(bob_comment.abs_rshares.value, 0); + BOOST_CHECK_EQUAL(bob_comment.cashout_time, bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(bob_comment.root_comment, alice_comment.id); validate_database(); BOOST_TEST_MESSAGE("--- Test Sam posting a comment on Bob's comment"); @@ -525,20 +583,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.clear(); tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const comment_object &sam_comment = db->get_comment("sam", string("dolor")); - BOOST_REQUIRE(sam_comment.author == op.author); - BOOST_REQUIRE(to_string(sam_comment.permlink) == op.permlink); - BOOST_REQUIRE(sam_comment.parent_author == op.parent_author); - BOOST_REQUIRE(to_string(sam_comment.parent_permlink) == op.parent_permlink); - BOOST_REQUIRE(sam_comment.last_update == db->head_block_time()); - BOOST_REQUIRE(sam_comment.created == db->head_block_time()); - BOOST_REQUIRE(sam_comment.net_rshares.value == 0); - BOOST_REQUIRE(sam_comment.abs_rshares.value == 0); - BOOST_REQUIRE(sam_comment.cashout_time == sam_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(sam_comment.root_comment == alice_comment.id); + BOOST_CHECK_EQUAL(sam_comment.author, op.author); + BOOST_CHECK_EQUAL(to_string(sam_comment.permlink), op.permlink); + BOOST_CHECK_EQUAL(sam_comment.parent_author, op.parent_author); + BOOST_CHECK_EQUAL(to_string(sam_comment.parent_permlink), op.parent_permlink); + BOOST_CHECK_EQUAL(sam_comment.last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(sam_comment.created, db->head_block_time()); + BOOST_CHECK_EQUAL(sam_comment.net_rshares.value, 0); + BOOST_CHECK_EQUAL(sam_comment.abs_rshares.value, 0); + BOOST_CHECK_EQUAL(sam_comment.cashout_time, sam_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(sam_comment.root_comment, alice_comment.id); validate_database(); generate_blocks(60 * 5 / STEEMIT_BLOCK_INTERVAL + 1); @@ -575,15 +633,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(mod_sam_comment.author == op.author); - BOOST_REQUIRE(to_string(mod_sam_comment.permlink) == op.permlink); - BOOST_REQUIRE(mod_sam_comment.parent_author == op.parent_author); - BOOST_REQUIRE(to_string(mod_sam_comment.parent_permlink) == op.parent_permlink); - BOOST_REQUIRE(mod_sam_comment.last_update == db->head_block_time()); - BOOST_REQUIRE(mod_sam_comment.created == created); - BOOST_REQUIRE(mod_sam_comment.cashout_time == mod_sam_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(mod_sam_comment.author, op.author); + BOOST_CHECK_EQUAL(to_string(mod_sam_comment.permlink), op.permlink); + BOOST_CHECK_EQUAL(mod_sam_comment.parent_author, op.parent_author); + BOOST_CHECK_EQUAL(to_string(mod_sam_comment.parent_permlink), op.parent_permlink); + BOOST_CHECK_EQUAL(mod_sam_comment.last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(mod_sam_comment.created, created); + BOOST_CHECK_EQUAL(mod_sam_comment.cashout_time, mod_sam_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); validate_database(); BOOST_TEST_MESSAGE("--- Test failure posting withing 1 minute"); @@ -596,7 +654,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); generate_blocks(60 * 5 / STEEMIT_BLOCK_INTERVAL); @@ -613,7 +671,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) validate_database(); generate_block(); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); } FC_LOG_AND_RETHROW() @@ -698,11 +756,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) } BOOST_AUTO_TEST_CASE(vote_apply) { - auto make_comment_id = [](const std::string& author, const std::string& permlink) { - auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); - return fc::variant_object(res); - }; - try { BOOST_TEST_MESSAGE("Testing: vote_apply"); @@ -6841,7 +6894,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure when json_metadata is invalid JSON"); op.json_metadata = "{test:fail}"; - STEEMIT_REQUIRE_THROW(op.validate(), fc::parse_error_exception); + STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); BOOST_TEST_MESSAGE("--- Test success under normal conditions"); op.json_metadata = "{}"; diff --git a/thirdparty/fc b/thirdparty/fc index d9e526e6e7..eec4ed2af9 160000 --- a/thirdparty/fc +++ b/thirdparty/fc @@ -1 +1 @@ -Subproject commit d9e526e6e7b8d39fa40adecbf4407fa6fd6366c1 +Subproject commit eec4ed2af95c4a37f4e1bf05c6eb96dfd17d923f From 9e3d3d19aeb5a8f98581424e40c2d627bb0ba60a Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 18 Jul 2018 11:25:04 +0700 Subject: [PATCH 083/250] Refactor errors: transfer_operation #790 --- libraries/chain/database.cpp | 34 ++--- libraries/chain/steem_evaluator.cpp | 19 +-- .../include/golos/protocol/exceptions.hpp | 5 + libraries/protocol/steem_operations.cpp | 19 +-- tests/common/database_fixture.hpp | 16 ++- tests/tests/operation_tests.cpp | 124 ++++++++++++++---- 6 files changed, 157 insertions(+), 60 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index b1ff2d20a6..b472b11a4e 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -3656,9 +3656,11 @@ namespace golos { namespace chain { auto &trx_idx = get_index(); auto trx_id = trx.id(); // idump((trx_id)(skip&skip_transaction_dupe_check)); - FC_ASSERT((skip & skip_transaction_dupe_check) || - trx_idx.indices().get().find(trx_id) == trx_idx.indices().get().end(), + if (!(skip & skip_transaction_dupe_check) && + trx_idx.indices().get().find(trx_id) != trx_idx.indices().get().end()) { + FC_THROW_EXCEPTION(tx_duplicate_transaction, "Duplicate transaction check failed", ("trx_ix", trx_id)); + } _validate_transaction(trx, skip); @@ -3692,14 +3694,16 @@ namespace golos { namespace chain { _current_op_in_trx = 0; for (const auto &op : trx.operations) { try { - apply_operation(op); - ++_current_op_in_trx; - } catch(const fc::exception& e) { - FC_THROW_EXCEPTION(tx_invalid_operation, - "Invalid operation ${index} in transaction: ${errmsg}", - ("index", _current_op_in_trx) - ("errmsg", e.to_string()) - ("error", e)); + try { + apply_operation(op); + ++_current_op_in_trx; + } catch(const fc::exception& e) { + FC_THROW_EXCEPTION(tx_invalid_operation, + "Invalid operation ${index} in transaction: ${errmsg}", + ("index", _current_op_in_trx) + ("errmsg", e.to_string()) + ("error", e)); + } } FC_CAPTURE_AND_RETHROW((op)); } _current_trx_id = transaction_id_type(); @@ -4214,7 +4218,7 @@ namespace golos { namespace chain { acnt.sbd_balance += delta; break; default: - FC_ASSERT(false, "invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } }); } @@ -4260,7 +4264,7 @@ namespace golos { namespace chain { acnt.savings_sbd_balance += delta; break; default: - FC_ASSERT(!"invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } }); } @@ -4292,7 +4296,7 @@ namespace golos { namespace chain { assert(props.current_sbd_supply.amount.value >= 0); break; default: - FC_ASSERT(false, "invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } }); } @@ -4305,7 +4309,7 @@ namespace golos { namespace chain { case SBD_SYMBOL: return a.sbd_balance; default: - FC_ASSERT(false, "invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } } @@ -4316,7 +4320,7 @@ namespace golos { namespace chain { case SBD_SYMBOL: return a.savings_sbd_balance; default: - FC_ASSERT(!"invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 59d74603ca..86ccd23f55 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -58,7 +58,7 @@ namespace golos { namespace chain { case SBD_SYMBOL: return account.sbd_balance; default: - FC_ASSERT(false, "invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } case SAVINGS: switch (symbol) { @@ -67,16 +67,16 @@ namespace golos { namespace chain { case SBD_SYMBOL: return account.savings_sbd_balance; default: - FC_ASSERT(false, "invalid symbol"); + GOLOS_CHECK_VALUE(false, "invalid symbol"); } case VESTING: - FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.vesting_shares; case EFFECTIVE_VESTING: - FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.effective_vesting_shares(); case HAVING_VESTING: - FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.available_vesting_shares(false); case AVAILABLE_VESTING: FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); @@ -974,10 +974,11 @@ namespace golos { namespace chain { }); } - GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); - - _db.adjust_balance(from_account, -o.amount); - _db.adjust_balance(to_account, o.amount); + GOLOS_CHECK_OP_PARAM(o, amount, { + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); + _db.adjust_balance(from_account, -o.amount); + _db.adjust_balance(to_account, o.amount); + }); } void transfer_to_vesting_evaluator::do_apply(const transfer_to_vesting_operation &o) { diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 1214e8f0b1..69a57e51c0 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -292,6 +292,11 @@ namespace golos { namespace protocol { std::vector unused_approvals; }; + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_duplicate_transaction, transaction_exception, + 3080000, "duplicate transaction"); + + } } // golos::protocol FC_REFLECT_ENUM(golos::logic_exception::error_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 59af59e014..fce911133c 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -167,15 +167,16 @@ namespace golos { namespace protocol { void transfer_operation::validate() const { try { - validate_account_name(from); - validate_account_name(to); - FC_ASSERT(amount.symbol != - VESTS_SYMBOL, "transferring of Golos Power (STMP) is not allowed."); - FC_ASSERT(amount.amount > - 0, "Cannot transfer a negative amount (aka: stealing)"); - FC_ASSERT(memo.size() < - STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); - FC_ASSERT(fc::is_utf8(memo), "Memo is not UTF8"); + GOLOS_CHECK_PARAM(from, validate_account_name(from)); + GOLOS_CHECK_PARAM(to, validate_account_name(to)); + GOLOS_CHECK_PARAM(amount, { + GOLOS_CHECK_VALUE(amount.symbol != VESTS_SYMBOL, "transferring of Golos Power (STMP) is not allowed."); + GOLOS_CHECK_VALUE(amount.amount > 0, "Cannot transfer a negative amount (aka: stealing)"); + }); + GOLOS_CHECK_PARAM(memo, { + GOLOS_CHECK_VALUE(memo.size() < STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); + GOLOS_CHECK_VALUE(fc::is_utf8(memo), "Memo is not UTF8"); + }); } FC_CAPTURE_AND_RETHROW((*this)) } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 05489d2e36..9980dfb88b 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -113,7 +113,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); S; \ } catch( fc::exception const& ex ) { \ BOOST_##TL("no exception expected, but '" << ex.name() << "' thrown: \n" << \ - ex.to_string()); \ + ex.to_detail_string()); \ } catch ( ... ) { \ BOOST_##TL("no exception expected, but unknown exception thrown"); \ } @@ -220,6 +220,13 @@ struct ErrorValidator { } }; +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_duplicate_transaction"); + } +}; + template<> struct ErrorValidator { void validate(const std::string& name, const fc::variant& props, int) { @@ -227,6 +234,13 @@ struct ErrorValidator { } }; +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_missing_active_auth"); + } +}; + #define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e2ed3075eb..a1378f3c88 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1159,6 +1159,43 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: transfer_validate"); + transfer_operation op; + op.from = "alice"; + op.to = "bob"; + op.amount = ASSET("10.000 GOLOS"); + op.memo = "memo string"; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failure when 'from' is empty"); + op.from = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "from")); + + BOOST_TEST_MESSAGE("--- failure when 'to' is empty"); + op.from = "alice"; + op.to = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "to")); + + BOOST_TEST_MESSAGE("--- failure when 'amount' is negative"); + op.to = "bob"; + op.amount = ASSET("-10.000 GOLOS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "amount")); + + BOOST_TEST_MESSAGE("--- failure when 'amount' in GESTS"); + op.amount = ASSET("10.000000 GESTS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "amount")); + + BOOST_TEST_MESSAGE("--- failure when 'memo' too large"); + op.amount = ASSET("10.000 GOLOS"); + op.memo = std::string(STEEMIT_MAX_MEMO_SIZE, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "memo")); + validate_database(); } FC_LOG_AND_RETHROW() @@ -1182,28 +1219,32 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); } @@ -1228,7 +1269,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(update_op); tx.sign(corp_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); tx.operations.clear(); tx.signatures.clear(); @@ -1242,22 +1283,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.sign(alice_private_key, db->get_chain_id()); signature_type alice_sig = tx.signatures.back(); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); + tx.sign(bob_private_key, db->get_chain_id()); signature_type bob_sig = tx.signatures.back(); tx.sign(sam_private_key, db->get_chain_id()); signature_type sam_sig = tx.signatures.back(); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); tx.signatures.clear(); tx.signatures.push_back(alice_sig); tx.signatures.push_back(bob_sig); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); tx.signatures.clear(); tx.signatures.push_back(alice_sig); tx.signatures.push_back(sam_sig); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_transaction, 0)); } FC_LOG_AND_RETHROW() } @@ -1269,8 +1314,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ACTORS((alice)(bob)) fund("alice", 10000); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == ASSET(" 0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("10.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET(" 0.000 GOLOS").amount.value); signed_transaction tx; transfer_operation op; @@ -1283,12 +1328,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.balance.amount.value == - ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == - ASSET("5.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("5.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("5.000 GOLOS").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Generating a block"); @@ -1297,20 +1340,36 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) const auto &new_alice = db->get_account("alice"); const auto &new_bob = db->get_account("bob"); - BOOST_REQUIRE(new_alice.balance.amount.value == ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("5.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_alice.balance.amount.value, ASSET("5.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("5.000 GOLOS").amount.value); + validate_database(); + + BOOST_TEST_MESSAGE("--- Test invalid amount (less digits after dot)"); + tx.signatures.clear(); + tx.operations.clear(); + op.amount = ASSET("2.00 GOLOS"); + tx.operations.push_back(op); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.sign(alice_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "amount"))); + + BOOST_CHECK_EQUAL(new_alice.balance.amount.value, ASSET("5.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("5.000 GOLOS").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test emptying an account"); tx.signatures.clear(); tx.operations.clear(); + op.amount = ASSET("5.000 GOLOS"); tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); - BOOST_REQUIRE(new_alice.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("10.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_alice.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("10.000 GOLOS").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test transferring non-existent funds"); @@ -1319,12 +1378,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "5.000 GOLOS"))); - BOOST_REQUIRE(new_alice.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("10.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_alice.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("10.000 GOLOS").amount.value); validate_database(); + BOOST_TEST_MESSAGE("--- Test transferring to non-existent account"); + tx.signatures.clear(); + tx.operations.clear(); + op.to = "sam"; + tx.operations.push_back(op); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.sign(alice_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "sam"))); + } FC_LOG_AND_RETHROW() } @@ -6470,7 +6542,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.extensions.clear(); op.extensions.insert(b); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), fc::assert_exception, {}); + GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_duplicate_transaction, {}); } FC_LOG_AND_RETHROW() } From 9de504c100b6e28af5b18922fc2e0d711014ebe1 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 17 Jul 2018 18:07:25 +0700 Subject: [PATCH 084/250] Refactor errors: vote_operation #790 --- libraries/chain/steem_evaluator.cpp | 62 +++-- .../include/golos/protocol/exceptions.hpp | 26 ++ libraries/protocol/steem_operations.cpp | 17 +- tests/common/database_fixture.cpp | 40 ++- tests/common/database_fixture.hpp | 32 ++- tests/tests/operation_tests.cpp | 231 ++++++++++++------ 6 files changed, 299 insertions(+), 109 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index a489dbd6e7..35081ce073 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1225,13 +1225,16 @@ namespace golos { namespace chain { const auto &voter = _db.get_account(o.voter); if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) - FC_ASSERT(!(voter.owner_challenged || - voter.active_challenged), "Operation cannot be processed because the account is currently challenged."); + GOLOS_CHECK_LOGIC(!(voter.owner_challenged || voter.active_challenged), + logic_exception::account_is_currently_challenged, + "Account \"${account}\" is currently challenged", ("account", voter.name)); - FC_ASSERT(voter.can_vote, "Voter has declined their voting rights."); + GOLOS_CHECK_LOGIC(voter.can_vote, logic_exception::voter_declined_voting_rights, + "Voter has declined their voting rights"); if (o.weight > 0) - FC_ASSERT(comment.allow_votes, "Votes are not allowed on the comment."); + GOLOS_CHECK_LOGIC(comment.allow_votes, logic_exception::votes_are_not_allowed, + "Votes are not allowed on the comment."); if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && _db.calculate_discussion_payout_time(comment) == @@ -1264,16 +1267,16 @@ namespace golos { namespace chain { voter.last_vote_time).to_seconds(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_11)) - FC_ASSERT(elapsed_seconds >= - STEEMIT_MIN_VOTE_INTERVAL_SEC, "Can only vote once every 3 seconds."); + GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), voter.last_vote_time + STEEMIT_MIN_VOTE_INTERVAL_SEC-1, + bandwidth_exception::vote_bandwidth, "Can only vote once every 3 seconds."); int64_t regenerated_power = (STEEMIT_100_PERCENT * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; int64_t current_power = std::min(int64_t(voter.voting_power + regenerated_power), int64_t(STEEMIT_100_PERCENT)); - FC_ASSERT(current_power > - 0, "Account currently does not have voting power."); + GOLOS_CHECK_LOGIC(current_power > 0, logic_exception::does_not_have_voting_power, + "Account currently does not have voting power."); int64_t abs_weight = abs(o.weight); int64_t used_power = @@ -1286,7 +1289,7 @@ namespace golos { namespace chain { int64_t max_vote_denom = dgpo.vote_regeneration_per_day * STEEMIT_VOTE_REGENERATION_SECONDS / (60 * 60 * 24); - FC_ASSERT(max_vote_denom > 0); + GOLOS_ASSERT(max_vote_denom > 0, golos::internal_error, "max_vote_denom is too small"); if (!_db.has_hardfork(STEEMIT_HARDFORK_0_14__259)) { used_power = (used_power / max_vote_denom) + 1; @@ -1294,8 +1297,8 @@ namespace golos { namespace chain { used_power = (used_power + max_vote_denom - 1) / max_vote_denom; } - FC_ASSERT(used_power <= - current_power, "Account does not have enough power to vote."); + GOLOS_CHECK_LOGIC(used_power <= current_power, logic_exception::does_not_have_voting_power, + "Account does not have enough power to vote."); int64_t abs_rshares = ( (uint128_t(voter.effective_vesting_shares().amount.value) * used_power) / @@ -1305,11 +1308,13 @@ namespace golos { namespace chain { } if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__259)) { - FC_ASSERT(abs_rshares > 30000000 || o.weight == - 0, "Voting weight is too small, please accumulate more voting power or steem power."); + GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || o.weight == 0, + logic_exception::voting_weight_is_too_small, + "Voting weight is too small, please accumulate more voting power or steem power."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_13__248)) { - FC_ASSERT(abs_rshares > 30000000 || abs_rshares == - 1, "Voting weight is too small, please accumulate more voting power or steem power."); + GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || abs_rshares == 1, + logic_exception::voting_weight_is_too_small, + "Voting weight is too small, please accumulate more voting power or steem power."); } @@ -1318,21 +1323,23 @@ namespace golos { namespace chain { if (itr != comment_vote_idx.end() && itr->num_changes == -1) { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_12__177)) - FC_ASSERT(false, "Cannot vote again on a comment after payout."); + GOLOS_CHECK_LOGIC(false, logic_exception::cannot_vote_after_payout, + "Cannot vote again on a comment after payout."); _db.remove(*itr); itr = comment_vote_idx.end(); } if (itr == comment_vote_idx.end()) { - FC_ASSERT(o.weight != 0, "Vote weight cannot be 0."); + GOLOS_CHECK_OP_PARAM(o, weight, GOLOS_CHECK_VALUE(o.weight != 0, "Vote weight cannot be 0")); /// this is the rshares voting for or against the post int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; if (rshares > 0) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_7)) { - FC_ASSERT(_db.head_block_time() < + GOLOS_CHECK_LOGIC(_db.head_block_time() < _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, + logic_exception::cannot_vote_within_last_minute_before_payout, "Cannot increase reward of post within the last minute before payout."); } } @@ -1369,7 +1376,8 @@ namespace golos { namespace chain { } - FC_ASSERT(abs_rshares > 0, "Cannot vote with 0 rshares."); + GOLOS_CHECK_LOGIC(abs_rshares > 0, logic_exception::cannot_vote_with_zero_rshares, + "Cannot vote with 0 rshares."); auto old_vote_rshares = comment.vote_rshares; @@ -1386,8 +1394,7 @@ namespace golos { namespace chain { } if (!_db.has_hardfork(STEEMIT_HARDFORK_0_6__114) && c.net_rshares == -c.abs_rshares) - FC_ASSERT(c.net_votes < - 0, "Comment has negative network votes?"); + GOLOS_ASSERT(c.net_votes < 0, golos::internal_error, "Comment has negative network votes?"); }); _db.modify(root, [&](comment_object &c) { @@ -1523,21 +1530,24 @@ namespace golos { namespace chain { _db.adjust_rshares2(comment, old_rshares, new_rshares); } else { - FC_ASSERT(itr->num_changes < - STEEMIT_MAX_VOTE_CHANGES, "Voter has used the maximum number of vote changes on this comment."); + GOLOS_CHECK_LOGIC(itr->num_changes < STEEMIT_MAX_VOTE_CHANGES, + logic_exception::voter_has_used_maximum_vote_changes, + "Voter has used the maximum number of vote changes on this comment."); if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_6__112)) - FC_ASSERT(itr->vote_percent != - o.weight, "You have already voted in a similar way."); + GOLOS_CHECK_LOGIC(itr->vote_percent != o.weight, + logic_exception::already_voted_in_similar_way, + "You have already voted in a similar way."); /// this is the rshares voting for or against the post int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; if (itr->rshares < rshares) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_7)) { - FC_ASSERT(_db.head_block_time() < + GOLOS_CHECK_LOGIC(_db.head_block_time() < _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, + logic_exception::cannot_vote_within_last_minute_before_payout, "Cannot increase reward of post within the last minute before payout."); } } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index fb100dae10..004cca1db2 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -163,6 +163,7 @@ namespace golos { enum bandwidth_types { post_bandwidth, comment_bandwidth, + vote_bandwidth, }; }; @@ -179,6 +180,18 @@ namespace golos { reached_limit_for_pending_withdraw_requests = 1, parent_of_comment_cannot_change, parent_perlink_of_comment_cannot_change, + + // Vote operation + voter_declined_voting_rights, + account_is_currently_challenged, + votes_are_not_allowed, + does_not_have_voting_power, + voting_weight_is_too_small, + cannot_vote_after_payout, + cannot_vote_within_last_minute_before_payout, + cannot_vote_with_zero_rshares, + voter_has_used_maximum_vote_changes, + already_voted_in_similar_way, }; }; @@ -277,9 +290,22 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (reached_limit_for_pending_withdraw_requests) (parent_of_comment_cannot_change) (parent_perlink_of_comment_cannot_change) + + // Vote operation + (voter_declined_voting_rights) + (account_is_currently_challenged) + (votes_are_not_allowed) + (does_not_have_voting_power) + (voting_weight_is_too_small) + (cannot_vote_after_payout) + (cannot_vote_within_last_minute_before_payout) + (cannot_vote_with_zero_rshares) + (voter_has_used_maximum_vote_changes) + (already_voted_in_similar_way) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, (post_bandwidth) (comment_bandwidth) + (vote_bandwidth) ); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index e912ab98b0..59af59e014 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -8,9 +8,8 @@ namespace golos { namespace protocol { /// Issue #56 contains the justificiation for allowing any UTF-8 string to serve as a permlink, content will be grouped by tags /// going forward. inline void validate_permlink(const string &permlink) { - FC_ASSERT(permlink.size() < - STEEMIT_MAX_PERMLINK_LENGTH, "permlink is too long"); - FC_ASSERT(fc::is_utf8(permlink), "permlink not formatted in UTF8"); + GOLOS_CHECK_VALUE(permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH, "permlink is too long"); + GOLOS_CHECK_VALUE(fc::is_utf8(permlink), "permlink not formatted in UTF8"); } static inline void validate_account_name(const string &name) { @@ -157,11 +156,13 @@ namespace golos { namespace protocol { } void vote_operation::validate() const { - validate_account_name(voter); - validate_account_name(author);\ - FC_ASSERT(abs(weight) <= - STEEMIT_100_PERCENT, "Weight is not a STEEMIT percentage"); - validate_permlink(permlink); + GOLOS_CHECK_PARAM(voter, validate_account_name(voter)); + GOLOS_CHECK_PARAM(author, validate_account_name(author)); + GOLOS_CHECK_PARAM(weight, { + GOLOS_CHECK_VALUE(abs(weight) <= STEEMIT_100_PERCENT, + "Weight is not a STEEMIT percentage"); + }); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); } void transfer_operation::validate() const { diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 414cf65515..c58912c403 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -29,21 +29,53 @@ std::ostream& operator<<(std::ostream& out, const fc::time_point& v) { return out; } -std::ostream& operator<<(std::ostream& out, const fc::uint128_t v) { +std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v) { out << static_cast(v); return out; } -std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v) { +std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v) { out << static_cast(v); return out; } -std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v) { - out << static_cast(v); +std::ostream& operator<<(std::ostream& out, const fc::variant_object &v) { + out << fc::json::to_string(v); return out; } +bool compare(const fc::variant &left, const fc::variant &right) { + if (left.get_type() != right.get_type()) return false; + switch (left.get_type()) { + case variant::null_type: return true; + case variant::int64_type: return left.as_int64() == right.as_int64(); + case variant::uint64_type: return left.as_uint64() == right.as_uint64(); + case variant::double_type: return left.as_double() == right.as_double(); + case variant::bool_type: return left.as_bool() == right.as_bool(); + case variant::string_type: return left.get_string() == right.get_string(); + case variant::array_type: + { + const variants &l = left.get_array(); + const variants &r = right.get_array(); + if (l.size() != r.size()) return false; + return std::equal(l.begin(), l.end(), r.begin(), compare); + } + case variant::object_type: return left.get_object() == right.get_object(); + case variant::blob_type: return left.get_string() == right.get_string(); + default: return false; + } +} + +bool operator==(const fc::variant_object &left, const fc::variant_object &right) { + if (left.size() != right.size()) return false; + for (const auto &v: left) { + const auto &ptr = right.find(v.key()); + if (ptr == right.end()) return false; + if (false == compare(v.value(), ptr->value())) return false; + } + return true; +} + } // namespace fc diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index caf8362386..a9ed2d8462 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -107,6 +107,21 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); #define GOLOS_CHECK_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, ERROR) #define GOLOS_REQUIRE_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, FAIL) +#define GOLOS_CHECK_NO_THROW_IMPL( S, TL ) \ + try { \ + BOOST_TEST_PASSPOINT(); \ + S; \ + } catch( fc::exception const& ex ) { \ + BOOST_##TL("no exception expected, but '" << ex.name() << "' thrown: \n" << \ + ex.to_string()); \ + } catch ( ... ) { \ + BOOST_##TL("no exception expected, but unknown exception thrown"); \ + } + +#define GOLOS_WARN_NO_THROW(S) GOLOS_CHECK_NO_THROW_IMPL(S, WARN) +#define GOLOS_CHECK_NO_THROW(S) GOLOS_CHECK_NO_THROW_IMPL(S, ERROR) +#define GOLOS_REQUIRE_NO_THROW(S) GOLOS_CHECK_NO_THROW_IMPL(S, FAIL) + template struct ErrorValidator {}; @@ -158,6 +173,13 @@ struct ErrorValidator { BOOST_CHECK_EQUAL(props["type"].get_string(), type); BOOST_CHECK_EQUAL(props["id"].get_string(), id); } + + void validate(const std::string& name, const fc::variant& props, + const std::string& type, const fc::variant_object& id) { + BOOST_CHECK_EQUAL(name, "missing_object"); + BOOST_CHECK_EQUAL(props["type"].get_string(), type); + BOOST_CHECK_EQUAL(props["id"].get_object(), id); + } }; template<> @@ -246,9 +268,17 @@ namespace fc { std::ostream& operator<<(std::ostream& out, const fc::exception& e); std::ostream& operator<<(std::ostream& out, const fc::time_point& v); -std::ostream& operator<<(std::ostream& out, const fc::uint128_t v); std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v); std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v); +std::ostream& operator<<(std::ostream &out, const fc::variant_object &v); + +template +std::ostream& operator<<(std::ostream& out, const fc::safe &v) { + out << v.value; + return out; +} + +bool operator==(const fc::variant_object &left, const fc::variant_object &right); } // namespace fc diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 44fad6db4f..f3e215dba4 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -12,12 +12,14 @@ #include #include +#include #include "database_fixture.hpp" #include #include #include +#include using namespace golos; using namespace golos::api; @@ -26,6 +28,22 @@ using namespace golos::protocol; using std::string; +namespace boost { namespace container { + +template +std::ostream &operator<<(std::ostream &out, const flat_set &t) { + out << "("; + if (!t.empty()) { + std::for_each(t.begin(), t.end()-1, [&](const T& v) {out << v << ",";}); + out << *t.rbegin(); + } + out << ")"; + return out; +} + +} } // namespace boost::container + + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_validate) { @@ -605,6 +623,48 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: vote_validate"); + vote_operation op; + op.voter = "bob"; + op.author = "alice"; + op.permlink = "test"; + op.weight = 1000; + + BOOST_TEST_MESSAGE("failure when 'voter' is empty"); + op.voter = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "voter")); + + BOOST_TEST_MESSAGE("failure when 'author' is empty"); + op.voter = "bob"; + op.author = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "author")); + + BOOST_TEST_MESSAGE("failure when 'weight' is too small"); + op.author = "alice"; + op.weight = -STEEMIT_100_PERCENT-1; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "weight")); + + BOOST_TEST_MESSAGE("failure when 'weight' is too mush"); + op.weight = STEEMIT_100_PERCENT+1; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "weight")); + + BOOST_TEST_MESSAGE("success with positive 'weight'"); + op.weight = STEEMIT_100_PERCENT; + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("success with negative 'weight'"); + op.weight = -STEEMIT_100_PERCENT; + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("failure when 'perlink' invalid"); + op.weight = 1000; + op.permlink = std::string(STEEMIT_MAX_PERMLINK_LENGTH, ' '); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(golos::invalid_parameter, "permlink")); + validate_database(); } FC_LOG_AND_RETHROW() @@ -614,12 +674,35 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: vote_authorities"); + vote_operation op; + op.voter = "bob"; + op.author = "alice"; + op.permlink = "test"; + op.weight = 1000; + + using account_name_set = flat_set; + account_name_set auths; + + op.get_required_owner_authorities(auths); + BOOST_CHECK_EQUAL(auths, account_name_set()); + + op.get_required_active_authorities(auths); + BOOST_CHECK_EQUAL(auths, account_name_set()); + + op.get_required_posting_authorities(auths); + BOOST_CHECK_EQUAL(auths, account_name_set({"bob"})); + validate_database(); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(vote_apply) { + auto make_comment_id = [](const std::string& author, const std::string& permlink) { + auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); + return fc::variant_object(res); + }; + try { BOOST_TEST_MESSAGE("Testing: vote_apply"); @@ -648,7 +731,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(comment_op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Testing voting on a non-existent comment"); @@ -663,19 +746,24 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "comment", make_comment_id("bob","foo")))); validate_database(); BOOST_TEST_MESSAGE("--- Testing voting with a weight of 0"); + op.author = "alice"; op.weight = (int16_t)0; tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "weight"))); validate_database(); @@ -684,13 +772,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto old_voting_power = alice.voting_power; op.weight = STEEMIT_100_PERCENT; - op.author = "alice"; tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto &alice_comment = db->get_comment("alice", string("foo")); auto itr = vote_idx.find(std::make_tuple(alice_comment.id, alice.id)); @@ -698,18 +785,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) (db->get_dynamic_global_properties().vote_regeneration_per_day * STEEMIT_VOTE_REGENERATION_SECONDS) / (60 * 60 * 24); - BOOST_REQUIRE(alice.voting_power == old_voting_power - - ((old_voting_power + max_vote_denom - 1) / - max_vote_denom)); - BOOST_REQUIRE(alice.last_vote_time == db->head_block_time()); - BOOST_REQUIRE(alice_comment.net_rshares.value == alice.vesting_shares.amount.value * - (old_voting_power - alice.voting_power) / - STEEMIT_100_PERCENT); - BOOST_REQUIRE(alice_comment.cashout_time == alice_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(itr->rshares == alice.vesting_shares.amount.value * - (old_voting_power - alice.voting_power) / - STEEMIT_100_PERCENT); - BOOST_REQUIRE(itr != vote_idx.end()); + BOOST_CHECK_EQUAL(alice.voting_power, old_voting_power - + ((old_voting_power + max_vote_denom - 1) / + max_vote_denom)); + BOOST_CHECK_EQUAL(alice.last_vote_time, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_comment.net_rshares.value, alice.vesting_shares.amount.value * + (old_voting_power - alice.voting_power) / + STEEMIT_100_PERCENT); + BOOST_CHECK_EQUAL(alice_comment.cashout_time, alice_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(itr->rshares, alice.vesting_shares.amount.value * + (old_voting_power - alice.voting_power) / + STEEMIT_100_PERCENT); + BOOST_CHECK(itr != vote_idx.end()); validate_database(); BOOST_TEST_MESSAGE("--- Test reduced power for quick voting"); @@ -726,7 +813,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(comment_op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); op.weight = STEEMIT_100_PERCENT / 2; op.voter = "alice"; @@ -736,23 +823,23 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const auto &bob_comment = db->get_comment("bob", string("foo")); itr = vote_idx.find(std::make_tuple(bob_comment.id, alice.id)); - BOOST_REQUIRE(db->get_account("alice").voting_power == + BOOST_CHECK_EQUAL(db->get_account("alice").voting_power, old_voting_power - ((old_voting_power + max_vote_denom - 1) * STEEMIT_100_PERCENT / (2 * max_vote_denom * STEEMIT_100_PERCENT))); - BOOST_REQUIRE(bob_comment.net_rshares.value == + BOOST_CHECK_EQUAL(bob_comment.net_rshares.value, alice.vesting_shares.amount.value * (old_voting_power - db->get_account("alice").voting_power) / STEEMIT_100_PERCENT); - BOOST_REQUIRE(bob_comment.cashout_time == bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(itr != vote_idx.end()); + BOOST_CHECK_EQUAL(bob_comment.cashout_time, bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK(itr != vote_idx.end()); validate_database(); BOOST_TEST_MESSAGE("--- Test payout time extension on vote"); @@ -774,21 +861,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); itr = vote_idx.find(std::make_tuple(new_alice_comment.id, new_bob.id)); - BOOST_REQUIRE(new_bob.voting_power == STEEMIT_100_PERCENT - + BOOST_CHECK_EQUAL(new_bob.voting_power, STEEMIT_100_PERCENT - ((STEEMIT_100_PERCENT + max_vote_denom - 1) / max_vote_denom)); - BOOST_REQUIRE(new_alice_comment.net_rshares.value == - old_abs_rshares + - new_bob.vesting_shares.amount.value * - (old_voting_power - new_bob.voting_power) / - STEEMIT_100_PERCENT); - BOOST_REQUIRE(new_alice_comment.cashout_time == new_alice_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(itr != vote_idx.end()); + BOOST_CHECK_EQUAL(new_alice_comment.net_rshares.value, + old_abs_rshares + + new_bob.vesting_shares.amount.value * + (old_voting_power - new_bob.voting_power) / + STEEMIT_100_PERCENT); + BOOST_CHECK_EQUAL(new_alice_comment.cashout_time, new_alice_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK(itr != vote_idx.end()); validate_database(); BOOST_TEST_MESSAGE("--- Test negative vote"); @@ -806,7 +893,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); itr = vote_idx.find(std::make_tuple(new_bob_comment.id, new_sam.id)); auto sam_weight /*= ( ( uint128_t( new_sam.vesting_shares.amount.value ) ) / 400 + 1 ).to_uint64();*/ @@ -815,14 +902,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) (2 * max_vote_denom))) / STEEMIT_100_PERCENT).to_uint64(); - BOOST_REQUIRE(new_sam.voting_power == STEEMIT_100_PERCENT - + BOOST_CHECK_EQUAL(new_sam.voting_power, STEEMIT_100_PERCENT - ((STEEMIT_100_PERCENT + max_vote_denom - 1) / (2 * max_vote_denom))); - BOOST_REQUIRE(new_bob_comment.net_rshares.value == (int64_t)(old_abs_rshares - sam_weight)); - BOOST_REQUIRE(new_bob_comment.abs_rshares.value == (int64_t)(old_abs_rshares + sam_weight)); - BOOST_REQUIRE(new_bob_comment.cashout_time == new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(itr != vote_idx.end()); + BOOST_CHECK_EQUAL(new_bob_comment.net_rshares.value, (int64_t)(old_abs_rshares - sam_weight)); + BOOST_CHECK_EQUAL(new_bob_comment.abs_rshares.value, (int64_t)(old_abs_rshares + sam_weight)); + BOOST_CHECK_EQUAL(new_bob_comment.cashout_time, new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK(itr != vote_idx.end()); validate_database(); BOOST_TEST_MESSAGE("--- Test nested voting on nested comments"); @@ -846,7 +933,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(comment_op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto old_rshares2 = db->get_comment("alice", string("foo")).children_rshares2; @@ -864,11 +951,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) (fc::uint128_t(db->get_account("alice").vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); - BOOST_REQUIRE( - db->get_comment("alice", string("foo")).children_rshares2 == + BOOST_CHECK_EQUAL( + db->get_comment("alice", string("foo")).children_rshares2, db->get_comment("sam", string("foo")).children_rshares2 + old_rshares2); - BOOST_REQUIRE( - db->get_comment("alice", string( "foo" )).cashout_time == + BOOST_CHECK_EQUAL( + db->get_comment("alice", string( "foo" )).cashout_time, db->get_comment("alice", string( "foo" )).created + STEEMIT_CASHOUT_WINDOW_SECONDS); validate_database(); @@ -896,20 +983,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); alice_bob_vote = vote_idx.find(std::make_tuple(new_bob_comment.id, new_alice.id)); new_rshares = ( (fc::uint128_t(new_alice.vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); - BOOST_REQUIRE(new_bob_comment.net_rshares == old_net_rshares - old_vote_rshares + new_rshares); - BOOST_REQUIRE(new_bob_comment.abs_rshares == old_abs_rshares + new_rshares); - BOOST_REQUIRE(new_bob_comment.cashout_time == new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(alice_bob_vote->rshares == (int64_t)new_rshares); - BOOST_REQUIRE(alice_bob_vote->last_update == db->head_block_time()); - BOOST_REQUIRE(alice_bob_vote->vote_percent == op.weight); - BOOST_REQUIRE(db->get_account("alice").voting_power == alice_voting_power); + BOOST_CHECK_EQUAL(new_bob_comment.net_rshares, old_net_rshares - old_vote_rshares + new_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.abs_rshares, old_abs_rshares + new_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.cashout_time, new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(alice_bob_vote->rshares, (int64_t)new_rshares); + BOOST_CHECK_EQUAL(alice_bob_vote->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_bob_vote->vote_percent, op.weight); + BOOST_CHECK_EQUAL(db->get_account("alice").voting_power, alice_voting_power); validate_database(); BOOST_TEST_MESSAGE("--- Test decreasing vote rshares"); @@ -930,20 +1017,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); alice_bob_vote = vote_idx.find(std::make_tuple(new_bob_comment.id, new_alice.id)); new_rshares = ( (fc::uint128_t(new_alice.vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); - BOOST_REQUIRE(new_bob_comment.net_rshares == old_net_rshares - old_vote_rshares - new_rshares); - BOOST_REQUIRE(new_bob_comment.abs_rshares == old_abs_rshares + new_rshares); - BOOST_REQUIRE(new_bob_comment.cashout_time == new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(alice_bob_vote->rshares == -1 * (int64_t)new_rshares); - BOOST_REQUIRE(alice_bob_vote->last_update == db->head_block_time()); - BOOST_REQUIRE(alice_bob_vote->vote_percent == op.weight); - BOOST_REQUIRE(db->get_account("alice").voting_power == alice_voting_power); + BOOST_CHECK_EQUAL(new_bob_comment.net_rshares, old_net_rshares - old_vote_rshares - new_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.abs_rshares, old_abs_rshares + new_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.cashout_time, new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(alice_bob_vote->rshares, -1 * (int64_t)new_rshares); + BOOST_CHECK_EQUAL(alice_bob_vote->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_bob_vote->vote_percent, op.weight); + BOOST_CHECK_EQUAL(db->get_account("alice").voting_power, alice_voting_power); validate_database(); BOOST_TEST_MESSAGE("--- Test changing a vote to 0 weight (aka: removing a vote)"); @@ -959,16 +1046,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); alice_bob_vote = vote_idx.find(std::make_tuple(new_bob_comment.id, new_alice.id)); - BOOST_REQUIRE(new_bob_comment.net_rshares == old_net_rshares - old_vote_rshares); - BOOST_REQUIRE(new_bob_comment.abs_rshares == old_abs_rshares); - BOOST_REQUIRE(new_bob_comment.cashout_time == new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(alice_bob_vote->rshares == 0); - BOOST_REQUIRE(alice_bob_vote->last_update == db->head_block_time()); - BOOST_REQUIRE(alice_bob_vote->vote_percent == op.weight); - BOOST_REQUIRE(db->get_account("alice").voting_power == alice_voting_power); + BOOST_CHECK_EQUAL(new_bob_comment.net_rshares, old_net_rshares - old_vote_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.abs_rshares, old_abs_rshares); + BOOST_CHECK_EQUAL(new_bob_comment.cashout_time, new_bob_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(alice_bob_vote->rshares, 0); + BOOST_CHECK_EQUAL(alice_bob_vote->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_bob_vote->vote_percent, op.weight); + BOOST_CHECK_EQUAL(db->get_account("alice").voting_power, alice_voting_power); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when increasing rshares within lockout period"); @@ -983,7 +1070,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_vote_within_last_minute_before_payout))); validate_database(); BOOST_TEST_MESSAGE("--- Test success when reducing rshares within lockout period"); @@ -993,7 +1082,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); BOOST_TEST_MESSAGE("--- Test failure with a new vote within lockout period"); @@ -1004,7 +1093,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_vote_within_last_minute_before_payout))); validate_database(); } } From c34f1a6c736ec354ef6f3fcc1f73a82e2674c1da Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 18 Jul 2018 12:19:30 +0700 Subject: [PATCH 085/250] Refactor errors: transfer_to_vesting_operation #790 --- libraries/chain/steem_evaluator.cpp | 13 ++-- libraries/protocol/steem_operations.cpp | 17 +++-- tests/tests/operation_tests.cpp | 88 +++++++++++++++++-------- 3 files changed, 79 insertions(+), 39 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 86ccd23f55..1d2a933627 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -27,7 +27,7 @@ std::string wstring_to_utf8(const std::wstring &str) { asset exist = get_balance(ACCOUNT, TYPE, (REQUIRED).symbol); \ if( UNLIKELY( exist < (REQUIRED) )) { \ FC_THROW_EXCEPTION( golos::insufficient_funds, \ - "Account \"${account}\" does not have enough ${balance}: exist ${exist}, required ${required}", \ + "Account \"${account}\" does not have enough ${balance}: required ${required}", \ ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("required",REQUIRED)); \ } \ FC_MULTILINE_MACRO_END \ @@ -987,11 +987,12 @@ namespace golos { namespace chain { const auto &from_account = _db.get_account(o.from); const auto &to_account = o.to.size() ? _db.get_account(o.to) : from_account; - - FC_ASSERT(_db.get_balance(from_account, STEEM_SYMBOL) >= - o.amount, "Account does not have sufficient GOLOS for transfer."); - _db.adjust_balance(from_account, -o.amount); - _db.create_vesting(to_account, o.amount); + + GOLOS_CHECK_OP_PARAM(o, amount, { + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); + _db.adjust_balance(from_account, -o.amount); + _db.create_vesting(to_account, o.amount); + }); } void withdraw_vesting_evaluator::do_apply(const withdraw_vesting_operation &o) { diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index fce911133c..ea5209b2f3 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -181,13 +181,16 @@ namespace golos { namespace protocol { } void transfer_to_vesting_operation::validate() const { - validate_account_name(from); - FC_ASSERT(is_asset_type(amount, STEEM_SYMBOL), "Amount must be GOLOS"); - if (to != account_name_type()) { - validate_account_name(to); - } - FC_ASSERT(amount > - asset(0, STEEM_SYMBOL), "Must transfer a nonzero amount"); + GOLOS_CHECK_PARAM(from, validate_account_name(from)); + GOLOS_CHECK_PARAM(amount, { + GOLOS_CHECK_VALUE(is_asset_type(amount, STEEM_SYMBOL), "Amount must be GOLOS"); + GOLOS_CHECK_VALUE(amount > asset(0, STEEM_SYMBOL), "Must transfer a nonzero amount"); + }); + GOLOS_CHECK_PARAM(to, { + if (to != account_name_type()) { + validate_account_name(to); + } + }); } void withdraw_vesting_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index a1378f3c88..32ad7ea6c3 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1405,6 +1405,36 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: transfer_to_vesting_validate"); + transfer_to_vesting_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.from = "alice"; + op.to = ""; + op.amount = ASSET("5.000 GOLOS"); + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failed when 'from' is empty"); + op.from = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "from")); + + BOOST_TEST_MESSAGE("--- failed when 'amount' is negative"); + op.from = "alice"; + op.amount = ASSET("-2.000 GOLOS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "amount")); + + BOOST_TEST_MESSAGE("--- failed when 'amount' have invalid symbol"); + op.amount = ASSET("2.000000 GESTS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "amount")); + + BOOST_TEST_MESSAGE("--- failed when 'to' is invalid"); + op.amount = ASSET("5.000 GOLOS"); + op.to = "a"; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "to")); + validate_database(); } FC_LOG_AND_RETHROW() @@ -1427,28 +1457,32 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with from signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); } @@ -1464,7 +1498,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) const auto &gpo = db->get_dynamic_global_properties(); - BOOST_REQUIRE(alice.balance == ASSET("10.000 GOLOS")); + BOOST_CHECK_EQUAL(alice.balance, ASSET("10.000 GOLOS")); auto shares = asset(gpo.total_vesting_shares.amount, VESTS_SYMBOL); auto vests = asset(gpo.total_vesting_fund_steem.amount, STEEM_SYMBOL); @@ -1480,17 +1514,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto new_vest = op.amount * (shares / vests); shares += new_vest; vests += op.amount; alice_shares += new_vest; - BOOST_REQUIRE(alice.balance.amount.value == ASSET("2.500 GOLOS").amount.value); - BOOST_REQUIRE(alice.vesting_shares.amount.value == alice_shares.amount.value); - BOOST_REQUIRE(gpo.total_vesting_fund_steem.amount.value == vests.amount.value); - BOOST_REQUIRE(gpo.total_vesting_shares.amount.value == shares.amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("2.500 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, alice_shares.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_fund_steem.amount.value, vests.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_shares.amount.value, shares.amount.value); validate_database(); op.to = "bob"; @@ -1500,29 +1534,31 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); new_vest = asset((op.amount * (shares / vests)).amount, VESTS_SYMBOL); shares += new_vest; vests += op.amount; bob_shares += new_vest; - BOOST_REQUIRE(alice.balance.amount.value == ASSET("0.500 GOLOS").amount.value); - BOOST_REQUIRE(alice.vesting_shares.amount.value == alice_shares.amount.value); - BOOST_REQUIRE(bob.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.vesting_shares.amount.value == bob_shares.amount.value); - BOOST_REQUIRE(gpo.total_vesting_fund_steem.amount.value == vests.amount.value); - BOOST_REQUIRE(gpo.total_vesting_shares.amount.value == shares.amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("0.500 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, alice_shares.amount.value); + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(bob.vesting_shares.amount.value, bob_shares.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_fund_steem.amount.value, vests.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_shares.amount.value, shares.amount.value); validate_database(); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); - - BOOST_REQUIRE(alice.balance.amount.value == ASSET("0.500 GOLOS").amount.value); - BOOST_REQUIRE(alice.vesting_shares.amount.value == alice_shares.amount.value); - BOOST_REQUIRE(bob.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.vesting_shares.amount.value == bob_shares.amount.value); - BOOST_REQUIRE(gpo.total_vesting_fund_steem.amount.value == vests.amount.value); - BOOST_REQUIRE(gpo.total_vesting_shares.amount.value == shares.amount.value); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "2.000 GOLOS"))); + + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("0.500 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, alice_shares.amount.value); + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(bob.vesting_shares.amount.value, bob_shares.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_fund_steem.amount.value, vests.amount.value); + BOOST_CHECK_EQUAL(gpo.total_vesting_shares.amount.value, shares.amount.value); validate_database(); } FC_LOG_AND_RETHROW() From 95f67e36e8446d89e7991ba1787a53b889aed19b Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 18 Jul 2018 13:00:07 +0700 Subject: [PATCH 086/250] Refactor errors: withdraw_vesting_operation #790 --- libraries/chain/steem_evaluator.cpp | 19 +++-- .../include/golos/protocol/exceptions.hpp | 8 ++ libraries/protocol/steem_operations.cpp | 11 ++- tests/tests/operation_tests.cpp | 83 +++++++++++++------ 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 1d2a933627..47d0a6fc1e 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1000,10 +1000,8 @@ namespace golos { namespace chain { const auto &account = _db.get_account(o.account); - FC_ASSERT(account.vesting_shares.amount >= 0, - "Account does not have sufficient Golos Power for withdraw."); - FC_ASSERT(account.available_vesting_shares() >= o.vesting_shares, - "Account does not have sufficient Golos Power for withdraw."); + GOLOS_CHECK_BALANCE(account, VESTING, asset(0, VESTS_SYMBOL)); + GOLOS_CHECK_BALANCE(account, HAVING_VESTING, o.vesting_shares); if (!account.mined && _db.has_hardfork(STEEMIT_HARDFORK_0_1)) { const auto &props = _db.get_dynamic_global_properties(); @@ -1013,17 +1011,19 @@ namespace golos { namespace chain { props.get_vesting_share_price(); min_vests.amount.value *= 10; - FC_ASSERT(account.vesting_shares.amount > min_vests.amount || + GOLOS_CHECK_LOGIC(account.vesting_shares.amount > min_vests.amount || (_db.has_hardfork(STEEMIT_HARDFORK_0_16__562) && o.vesting_shares.amount == 0), + logic_exception::insufficient_fee_for_powerdown_registered_account, "Account registered by another account requires 10x account creation fee worth of Golos Power before it can be powered down."); } if (o.vesting_shares.amount == 0) { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__57)) - FC_ASSERT(account.vesting_withdraw_rate.amount != - 0, "This operation would not change the vesting withdraw rate."); + GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate.amount != 0, + logic_exception::operation_would_not_change_vesting_withdraw_rate, + "This operation would not change the vesting withdraw rate."); _db.modify(account, [&](account_object &a) { a.vesting_withdraw_rate = asset(0, VESTS_SYMBOL); @@ -1047,8 +1047,9 @@ namespace golos { namespace chain { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__57)) - FC_ASSERT(account.vesting_withdraw_rate != - new_vesting_withdraw_rate, "This operation would not change the vesting withdraw rate."); + GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate != new_vesting_withdraw_rate, + logic_exception::operation_would_not_change_vesting_withdraw_rate, + "This operation would not change the vesting withdraw rate."); a.vesting_withdraw_rate = new_vesting_withdraw_rate; a.next_vesting_withdrawal = _db.head_block_time() + diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 69a57e51c0..563cdddcfa 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -200,6 +200,10 @@ namespace golos { discussion_is_frozen, comment_is_archived, comment_editable_during_first_24_hours, + + // withdraw_vesting + insufficient_fee_for_powerdown_registered_account, + operation_would_not_change_vesting_withdraw_rate, }; }; @@ -323,6 +327,10 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (discussion_is_frozen) (comment_is_archived) (comment_editable_during_first_24_hours) + + // withdraw_vesting + (insufficient_fee_for_powerdown_registered_account) + (operation_would_not_change_vesting_withdraw_rate) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index ea5209b2f3..7254d45cf7 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -194,12 +194,11 @@ namespace golos { namespace protocol { } void withdraw_vesting_operation::validate() const { - validate_account_name(account); - FC_ASSERT(is_asset_type(vesting_shares, VESTS_SYMBOL), "Amount must be GESTS"); - FC_ASSERT( - vesting_shares.amount >= 0, - "Cannot withdraw negative GESTS. account: ${account}, vests:${vests}", - ("account", account)("vests", vesting_shares)); + GOLOS_CHECK_PARAM(account, validate_account_name(account)); + GOLOS_CHECK_PARAM(vesting_shares, { + GOLOS_CHECK_VALUE(is_asset_type(vesting_shares, VESTS_SYMBOL), "Amount must be GESTS"); + GOLOS_CHECK_VALUE(vesting_shares.amount >= 0, "Cannot withdraw negative GESTS"); + }); } void set_withdraw_vesting_route_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 32ad7ea6c3..448b0ccf9b 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1568,6 +1568,29 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: withdraw_vesting_validate"); + withdraw_vesting_operation op; + + BOOST_TEST_MESSAGE("--- success with valid parameters"); + op.account = "alice"; + op.vesting_shares = ASSET("0.001000 GESTS"); + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failed when 'account' is empty"); + op.account = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "account")); + + BOOST_TEST_MESSAGE("--- failed when 'vesting_shares' not in GESTS"); + op.account = "alice"; + op.vesting_shares = ASSET("1.000 GOLOS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "vesting_shares")); + + BOOST_TEST_MESSAGE("--- failed when 'vesting_shares' is negative"); + op.vesting_shares = ASSET("-1.000000 GESTS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "vesting_shares")); + validate_database(); } FC_LOG_AND_RETHROW() @@ -1590,26 +1613,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -1639,14 +1666,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.vesting_shares.amount.value == old_vesting_shares.amount.value); - BOOST_REQUIRE(alice.vesting_withdraw_rate.amount.value == + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, old_vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.vesting_withdraw_rate.amount.value, (old_vesting_shares.amount / (STEEMIT_VESTING_WITHDRAW_INTERVALS * 2)).value); - BOOST_REQUIRE(alice.to_withdraw.value == op.vesting_shares.amount.value); - BOOST_REQUIRE(alice.next_vesting_withdrawal == db->head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS); + BOOST_CHECK_EQUAL(alice.to_withdraw.value, op.vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.next_vesting_withdrawal, db->head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS); validate_database(); BOOST_TEST_MESSAGE("--- Test changing vesting withdrawal"); @@ -1657,14 +1684,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.vesting_shares.amount.value == old_vesting_shares.amount.value); - BOOST_REQUIRE(alice.vesting_withdraw_rate.amount.value == + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, old_vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.vesting_withdraw_rate.amount.value, (old_vesting_shares.amount / (STEEMIT_VESTING_WITHDRAW_INTERVALS * 3)).value); - BOOST_REQUIRE(alice.to_withdraw.value == op.vesting_shares.amount.value); - BOOST_REQUIRE(alice.next_vesting_withdrawal == + BOOST_CHECK_EQUAL(alice.to_withdraw.value, op.vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.next_vesting_withdrawal, db->head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS); validate_database(); @@ -1677,13 +1704,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "having vesting shares", asset(alice.vesting_shares.amount * 2, VESTS_SYMBOL).to_string()))); - BOOST_REQUIRE(alice.vesting_shares.amount.value == old_vesting_shares.amount.value); - BOOST_REQUIRE(alice.vesting_withdraw_rate.amount.value == + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, old_vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.vesting_withdraw_rate.amount.value, (old_vesting_shares.amount / (STEEMIT_VESTING_WITHDRAW_INTERVALS * 3)).value); - BOOST_REQUIRE(alice.next_vesting_withdrawal == + BOOST_CHECK_EQUAL(alice.next_vesting_withdrawal, db->head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS); validate_database(); @@ -1696,19 +1725,19 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.vesting_shares.amount.value == old_vesting_shares.amount.value); - BOOST_REQUIRE(alice.vesting_withdraw_rate.amount.value == 0); - BOOST_REQUIRE(alice.to_withdraw.value == 0); - BOOST_REQUIRE(alice.next_vesting_withdrawal == fc::time_point_sec::maximum()); + BOOST_CHECK_EQUAL(alice.vesting_shares.amount.value, old_vesting_shares.amount.value); + BOOST_CHECK_EQUAL(alice.vesting_withdraw_rate.amount.value, 0); + BOOST_CHECK_EQUAL(alice.to_withdraw.value, 0); + BOOST_CHECK_EQUAL(alice.next_vesting_withdrawal, fc::time_point_sec::maximum()); BOOST_TEST_MESSAGE("--- Test cancelling a withdraw when below the account creation fee"); op.vesting_shares = alice.vesting_shares; tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); generate_block(); } @@ -1738,9 +1767,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_account("alice").vesting_withdraw_rate == + BOOST_CHECK_EQUAL(db->get_account("alice").vesting_withdraw_rate, ASSET("0.000000 GESTS")); validate_database(); } From d8d2fadbc917444913a4f61ee7e6786da294f35b Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 18 Jul 2018 15:10:11 +0300 Subject: [PATCH 087/250] Fixed order_non_unique in content_index. Added exception. Removed extra method declaration in api::discussion_helper. #796 --- libraries/api/discussion_helper.cpp | 2 -- .../golos/plugins/social_network/comment_content_object.hpp | 2 +- plugins/social_network/social_network.cpp | 3 +++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 99033b8f2e..2c691531a1 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -105,8 +105,6 @@ namespace golos { namespace api { discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; - void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); - void fill_comment_api_object(const comment_object& o, comment_api_object& d) const; private: diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp index 80fe141a7d..bd9f5e8892 100644 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp @@ -45,7 +45,7 @@ namespace golos { namespace plugins { namespace social_network { indexed_by< ordered_unique, member>, ordered_unique, member>, - ordered_unique, member>>, + ordered_non_unique, member>>, allocator > comment_content_index; } } } diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index a041f108da..d70b4ed026 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,8 @@ namespace golos { namespace plugins { namespace social_network { const comment_content_object& social_network::impl::get_comment_content(const comment_id_type& comment) const { try { return database().get(comment); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("comment_content", comment); } FC_CAPTURE_AND_RETHROW((comment)) } From 859dabc732eb9996269c82e2717ac2bd499bdc7e Mon Sep 17 00:00:00 2001 From: AKorpusenko Date: Wed, 18 Jul 2018 15:31:44 +0300 Subject: [PATCH 088/250] Removed extra try catch from social_network plugin. #796 --- plugins/social_network/social_network.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index d70b4ed026..81378901a2 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -194,9 +194,7 @@ namespace golos { namespace plugins { namespace social_network { } const comment_content_object& get_comment_content(const comment_id_type& comment) const { - try { - return db.get(comment); - } FC_CAPTURE_AND_RETHROW((comment)) + return db.get(comment); } const comment_content_object* find_comment_content(const comment_id_type& comment) const { From 5c16b3a51bd49e2440f08409b5ca3627b38931fc Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 19:26:52 +0700 Subject: [PATCH 089/250] Refactor erros: comment_operation (review fixes) #790 --- tests/tests/operation_tests.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e2ed3075eb..b5035e18d8 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -523,15 +523,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(alice_comment.cashout_time, fc::time_point_sec(db->head_block_time() + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS))); -#ifndef IS_LOW_MEM BOOST_CHECK_EQUAL( to_string( alice_content.title ), op.title ); BOOST_CHECK_EQUAL( to_string( alice_content.body ), op.body ); //BOOST_CHECK_EQUAL( alice_content.json_metadata, op.json_metadata ); -#else - BOOST_CHECK_EQUAL(to_string(alice_content.title), ""); - BOOST_CHECK_EQUAL(to_string(alice_content.body), ""); - //BOOST_CHECK_EQUAL( alice_content.json_metadata, "" ); -#endif validate_database(); From 6d183583a703aca925f6f383604f22eb3f6be255 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 20:50:39 +0700 Subject: [PATCH 090/250] Refactor errors: transfer_operation (review fixes) #790 --- libraries/protocol/steem_operations.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index fce911133c..a91d2964a0 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -170,7 +170,7 @@ namespace golos { namespace protocol { GOLOS_CHECK_PARAM(from, validate_account_name(from)); GOLOS_CHECK_PARAM(to, validate_account_name(to)); GOLOS_CHECK_PARAM(amount, { - GOLOS_CHECK_VALUE(amount.symbol != VESTS_SYMBOL, "transferring of Golos Power (STMP) is not allowed."); + GOLOS_CHECK_VALUE(amount.symbol != VESTS_SYMBOL, "transferring of Golos Power (GESTS) is not allowed."); GOLOS_CHECK_VALUE(amount.amount > 0, "Cannot transfer a negative amount (aka: stealing)"); }); GOLOS_CHECK_PARAM(memo, { From d0c4ff8ca1211741641fb2872019839cd64a27c0 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 21:27:39 +0700 Subject: [PATCH 091/250] Refactor errors: transfer_to_vesting_operation (review fixes) #790 --- libraries/chain/steem_evaluator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 1d2a933627..1b8caf0d9f 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -27,8 +27,8 @@ std::string wstring_to_utf8(const std::wstring &str) { asset exist = get_balance(ACCOUNT, TYPE, (REQUIRED).symbol); \ if( UNLIKELY( exist < (REQUIRED) )) { \ FC_THROW_EXCEPTION( golos::insufficient_funds, \ - "Account \"${account}\" does not have enough ${balance}: required ${required}", \ - ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("required",REQUIRED)); \ + "Account \"${account}\" does not have enough ${balance}: required ${required}, exist ${exist}", \ + ("account",ACCOUNT.name)("balance",get_balance_name(TYPE))("required",REQUIRED)("exist",exist)); \ } \ FC_MULTILINE_MACRO_END \ ) From f31d450b7efdb3d2afdf0837a14f421e8ea8d2a4 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 02:34:45 +0300 Subject: [PATCH 092/250] Refactor errors: witness_update & chain_properties_update #790 --- .../chain/chain_properties_evaluators.cpp | 43 ++-- libraries/chain/steem_evaluator.cpp | 14 +- .../include/golos/protocol/exceptions.hpp | 24 +- .../golos/protocol/steem_operations.hpp | 19 +- .../golos/protocol/validate_helper.hpp | 75 ++++++ libraries/protocol/steem_operations.cpp | 36 ++- tests/common/database_fixture.hpp | 6 + tests/common/helpers.hpp | 90 +++++++ tests/tests/operation_tests.cpp | 223 ++++++++---------- 9 files changed, 332 insertions(+), 198 deletions(-) create mode 100644 libraries/protocol/include/golos/protocol/validate_helper.hpp create mode 100644 tests/common/helpers.hpp diff --git a/libraries/chain/chain_properties_evaluators.cpp b/libraries/chain/chain_properties_evaluators.cpp index 073505ad62..37f20bea46 100644 --- a/libraries/chain/chain_properties_evaluators.cpp +++ b/libraries/chain/chain_properties_evaluators.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace golos { namespace chain { @@ -8,19 +9,14 @@ namespace golos { namespace chain { _db.get_account(o.owner); // verify owner exists if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) { - FC_ASSERT(o.url.size() <= STEEMIT_MAX_WITNESS_URL_LENGTH, "URL is too long"); + GOLOS_CHECK_OP_PARAM(o, url, { + GOLOS_CHECK_VALUE_MAX_SIZE(o.url, STEEMIT_MAX_WITNESS_URL_LENGTH); + }); } else if (o.url.size() > STEEMIT_MAX_WITNESS_URL_LENGTH) { // after HF, above check can be moved to validate() if reindex doesn't show this warning wlog("URL is too long in block ${b}", ("b", _db.head_block_num() + 1)); } - if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__410)) { - FC_ASSERT(o.props.account_creation_fee.symbol == STEEM_SYMBOL); - } else if (o.props.account_creation_fee.symbol != STEEM_SYMBOL) { - // after HF, above check can be moved to validate() if reindex doesn't show this warning - wlog("Wrong fee symbol in block ${b}", ("b", _db.head_block_num() + 1)); - } - const bool has_hf18 = _db.has_hardfork(STEEMIT_HARDFORK_0_18__673); // TODO: remove this after HF 18 @@ -36,25 +32,23 @@ namespace golos { namespace chain { } } - const auto &idx = _db.get_index().indices().get(); + auto update_witness = [&](witness_object& w) { + from_string(w.url, o.url); + w.signing_key = o.block_signing_key; + if (!has_hf18) { + w.props = o.props; + } + }; + + const auto& idx = _db.get_index().indices().get(); auto itr = idx.find(o.owner); if (itr != idx.end()) { - _db.modify(*itr, [&](witness_object& w) { - from_string(w.url, o.url); - w.signing_key = o.block_signing_key; - if (!has_hf18) { - w.props = o.props; - } - }); + _db.modify(*itr, update_witness); } else { _db.create([&](witness_object& w) { w.owner = o.owner; - from_string(w.url, o.url); - w.signing_key = o.block_signing_key; w.created = _db.head_block_time(); - if (!has_hf18) { - w.props = o.props; - } + update_witness(w); }); } } @@ -62,7 +56,7 @@ namespace golos { namespace chain { struct chain_properties_convert { using result_type = chain_properties_18; - template + template result_type operator()(Props&& p) const { result_type r; r = p; @@ -71,10 +65,9 @@ namespace golos { namespace chain { }; void chain_properties_update_evaluator::do_apply(const chain_properties_update_operation& o) { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__673, "Chain properties"); // remove after hf _db.get_account(o.owner); // verify owner exists - const auto &idx = _db.get_index().indices().get(); + const auto& idx = _db.get_index().indices().get(); auto itr = idx.find(o.owner); if (itr != idx.end()) { _db.modify(*itr, [&](witness_object& w) { @@ -89,4 +82,4 @@ namespace golos { namespace chain { } } -} } // golos::chain \ No newline at end of file +} } // golos::chain diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 47d0a6fc1e..6e7f0f3d2f 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -21,7 +21,7 @@ std::string wstring_to_utf8(const std::wstring &str) { #endif -#define GOLOS_CHECK_BALANCE( ACCOUNT, TYPE, REQUIRED ...) \ +#define GOLOS_CHECK_BALANCE(ACCOUNT, TYPE, REQUIRED ...) \ FC_EXPAND_MACRO( \ FC_MULTILINE_MACRO_BEGIN \ asset exist = get_balance(ACCOUNT, TYPE, (REQUIRED).symbol); \ @@ -69,16 +69,16 @@ namespace golos { namespace chain { default: GOLOS_CHECK_VALUE(false, "invalid symbol"); } - case VESTING: + case VESTING: GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.vesting_shares; - case EFFECTIVE_VESTING: + case EFFECTIVE_VESTING: GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.effective_vesting_shares(); - case HAVING_VESTING: + case HAVING_VESTING: GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.available_vesting_shares(false); - case AVAILABLE_VESTING: + case AVAILABLE_VESTING: FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); return account.available_vesting_shares(true); default: FC_ASSERT(false, "invalid balance type"); @@ -975,7 +975,7 @@ namespace golos { namespace chain { } GOLOS_CHECK_OP_PARAM(o, amount, { - GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); _db.adjust_balance(from_account, -o.amount); _db.adjust_balance(to_account, o.amount); }); @@ -987,7 +987,7 @@ namespace golos { namespace chain { const auto &from_account = _db.get_account(o.from); const auto &to_account = o.to.size() ? _db.get_account(o.to) : from_account; - + GOLOS_CHECK_OP_PARAM(o, amount, { GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, o.amount); _db.adjust_balance(from_account, -o.amount); diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 563cdddcfa..d74d12d2cb 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -67,27 +67,17 @@ } \ }() -#define GOLOS_CHECK_PARAM(PARAM, VALIDATOR) \ - FC_MULTILINE_MACRO_BEGIN \ - try { \ - VALIDATOR; \ - } catch (const golos::invalid_value& e) { \ - FC_THROW_EXCEPTION(golos::invalid_parameter, "Invalid value \"${value}\" for parameter \"${param}\": ${errmsg}", \ - ("param", FC_STRINGIZE(PARAM)) \ - ("value", PARAM) \ - ("errmsg", e.to_string()) \ - ("error", static_cast(e))); \ - } \ - FC_MULTILINE_MACRO_END +#define GOLOS_CHECK_PARAM(PARAM, VALIDATOR) GOLOS_CHECK_PARAM_I(PARAM, PARAM, VALIDATOR, "") +#define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) GOLOS_CHECK_PARAM_I(PARAM, OP.PARAM, VALIDATOR, "operation ") -#define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) \ +#define GOLOS_CHECK_PARAM_I(PARAM, VALUE, VALIDATOR, TYPE) \ FC_MULTILINE_MACRO_BEGIN \ try { \ VALIDATOR; \ } catch (const golos::invalid_value& e) { \ - FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for operation parameter \"${param}\": ${errmsg}", \ + FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for " TYPE "parameter \"${param}\": ${errmsg}", \ ("param", FC_STRINGIZE(PARAM)) \ - ("value", OP.PARAM) \ + ("value", VALUE) \ ("errmsg", e.to_string()) \ ("error", static_cast(e))); \ } \ @@ -206,7 +196,7 @@ namespace golos { operation_would_not_change_vesting_withdraw_rate, }; }; - + GOLOS_DECLARE_DERIVED_EXCEPTION( internal_error, golos_exception, 4000000, "internal error"); @@ -303,7 +293,7 @@ namespace golos { namespace protocol { } } // golos::protocol -FC_REFLECT_ENUM(golos::logic_exception::error_types, +FC_REFLECT_ENUM(golos::logic_exception::error_types, (reached_limit_for_pending_withdraw_requests) (parent_of_comment_cannot_change) (parent_perlink_of_comment_cannot_change) diff --git a/libraries/protocol/include/golos/protocol/steem_operations.hpp b/libraries/protocol/include/golos/protocol/steem_operations.hpp index 483eb09698..1f0b73168e 100644 --- a/libraries/protocol/include/golos/protocol/steem_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_operations.hpp @@ -442,13 +442,7 @@ namespace golos { namespace protocol { uint32_t maximum_block_size = STEEMIT_MIN_BLOCK_SIZE_LIMIT * 2; uint16_t sbd_interest_rate = STEEMIT_DEFAULT_SBD_INTEREST_RATE; - void validate() const { - FC_ASSERT(account_creation_fee.symbol == STEEM_SYMBOL); - FC_ASSERT(account_creation_fee.amount >= STEEMIT_MIN_ACCOUNT_CREATION_FEE); - FC_ASSERT(maximum_block_size >= STEEMIT_MIN_BLOCK_SIZE_LIMIT); - FC_ASSERT(sbd_interest_rate >= 0); - FC_ASSERT(sbd_interest_rate <= STEEMIT_100_PERCENT); - } + void validate() const; chain_properties_17& operator=(const chain_properties_17&) = default; @@ -490,16 +484,7 @@ namespace golos { namespace protocol { asset(STEEMIT_MIN_ACCOUNT_CREATION_FEE * GOLOS_MIN_DELEGATION_MULTIPLIER, STEEM_SYMBOL); - void validate() const { - chain_properties_17::validate(); - FC_ASSERT(create_account_min_golos_fee.amount > 0); - FC_ASSERT(create_account_min_golos_fee.symbol == STEEM_SYMBOL); - FC_ASSERT(create_account_min_delegation.amount > 0); - FC_ASSERT(create_account_min_delegation.symbol == STEEM_SYMBOL); - FC_ASSERT(min_delegation.amount > 0); - FC_ASSERT(min_delegation.symbol == STEEM_SYMBOL); - FC_ASSERT(create_account_delegation_time > (GOLOS_CREATE_ACCOUNT_DELEGATION_TIME).to_seconds() / 2); - } + void validate() const; chain_properties_18& operator=(const chain_properties_17& src) { account_creation_fee = src.account_creation_fee; diff --git a/libraries/protocol/include/golos/protocol/validate_helper.hpp b/libraries/protocol/include/golos/protocol/validate_helper.hpp new file mode 100644 index 0000000000..cd98373ec4 --- /dev/null +++ b/libraries/protocol/include/golos/protocol/validate_helper.hpp @@ -0,0 +1,75 @@ +#pragma once + +// macro helpers on GOLOS_CHECK_VALUE and GOLOS_CHECK_PARAM +// to check common cases and autogenerate message text + +// Common abbreviations: +// EQ, NE, LT, GT, LE, GE — like in asm conditions +// (Equal, Not Equal, Less Than, Greather Than, Less or Equal, Greater or Equal) + + +// GOLOS_CHECK_PARAM helpers +//------------------------------------------------------------- + +// check if account parameter valid +#define GOLOS_CHECK_PARAM_ACCOUNT(A) GOLOS_CHECK_PARAM(A, validate_account_name(A)) +// call param internal validate +#define GOLOS_CHECK_PARAM_VALIDATE(P) GOLOS_CHECK_PARAM(P, P.validate()) + +// GOLOS_CHECK_VALUE helpers +//------------------------------------------------------------- + +// size +#define GOLOS_CHECK_VALUE_MAX_SIZE(F, M) \ + GOLOS_CHECK_VALUE(F.size() <= M, MUST_BE2(F, "is too long", "<= " FC_STRINGIZE(M))); +#define GOLOS_CHECK_VALUE_NOT_EMPTY(F) \ + GOLOS_CHECK_VALUE(!F.empty(), CANNOT_BE(F, "empty")); +// utf-8 +#define GOLOS_CHECK_VALUE_UTF8(F) \ + GOLOS_CHECK_VALUE(fc::is_utf8(F), MUST_BE(F, "valid UTF8 string")); + + +// compare field with value +#define GOLOS_CHECK_FIELD_EQ(F, X) GOLOS_CHECK_FIELD_I(F, ==, X) +#define GOLOS_CHECK_FIELD_GT(F, X) GOLOS_CHECK_FIELD_I(F, > , X) +#define GOLOS_CHECK_FIELD_LT(F, X) GOLOS_CHECK_FIELD_I(F, < , X) +#define GOLOS_CHECK_FIELD_GE(F, X) GOLOS_CHECK_FIELD_I(F, >=, X) +#define GOLOS_CHECK_FIELD_LE(F, X) GOLOS_CHECK_FIELD_I(F, <=, X) +#define GOLOS_CHECK_FIELD_LEGE(F, L, H) \ + GOLOS_CHECK_VALUE(L <= F && F <= H , MUST_BE(F, "between " FC_STRINGIZE(L) " and" FC_STRINGIZE(H))) + +// check asset type +#define GOLOS_CHECK_ASSET_TYPE(X, NAME) GOLOS_CHECK_ASSET_##NAME(X); +#define GOLOS_CHECK_ASSET_GESTS(X) GOLOS_CHECK_ASSET_TYPE_I(X, VESTS_SYMBOL, "GESTS") +#define GOLOS_CHECK_ASSET_GOLOS(X) GOLOS_CHECK_ASSET_TYPE_I(X, STEEM_SYMBOL, "GOLOS") +#define GOLOS_CHECK_ASSET_GBG(X) GOLOS_CHECK_ASSET_TYPE_I(X, SBD_SYMBOL, "GBG") + +#define GOLOS_CHECK_ASSET_GOLOS_OR_GBG(X) \ + GOLOS_CHECK_VALUE(X.symbol == STEEM_SYMBOL || X.symbol == SBD_SYMBOL, MUST_BE(X, "GOLOS or GBG")) + +// check asset type and value +#define GOLOS_CHECK_ASSET_GT0(X, NAME) GOLOS_CHECK_ASSET_VAL(X, >, 0, NAME) +#define GOLOS_CHECK_ASSET_GE0(X, NAME) GOLOS_CHECK_ASSET_VAL(X, >=, 0, NAME) +#define GOLOS_CHECK_ASSET_GE(X, NAME, V) GOLOS_CHECK_ASSET_VAL(X, >=, V, NAME) + + +// internals +//------------------------------------------------------------- + +// fields +#define GOLOS_CHECK_FIELD_I(F, OP, X) GOLOS_CHECK_FIELD_II(F, OP, X, F) +#define GOLOS_CHECK_FIELD_II(F, OP, X, N) GOLOS_CHECK_VALUE(F OP X, MUST_BE(N, "" #OP FC_STRINGIZE(X))) + +// asset type +#define GOLOS_CHECK_ASSET_TYPE_I(X, SYMBOL, SNAME) GOLOS_CHECK_VALUE(X.symbol == SYMBOL, MUST_BE(X, SNAME)) + +// asset value +#define GOLOS_CHECK_ASSET_VAL(X, OP, V, N) { \ + GOLOS_CHECK_ASSET_TYPE(X, N); \ + GOLOS_CHECK_FIELD_II(X.amount, OP, V, X); \ +} + +// utils +#define MUST_BE(NAME, REQ) #NAME " must be " REQ +#define MUST_BE2(NAME, DESC, REQ) #NAME DESC ", it must be " REQ +#define CANNOT_BE(NAME, REQ) #NAME " cannot be " REQ diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 7254d45cf7..77b5a85b51 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace golos { namespace protocol { @@ -208,12 +209,33 @@ namespace golos { namespace protocol { STEEMIT_100_PERCENT, "Percent must be valid golos percent"); } + + void chain_properties_17::validate() const { + GOLOS_CHECK_ASSET_GE(account_creation_fee, GOLOS, STEEMIT_MIN_ACCOUNT_CREATION_FEE); + GOLOS_CHECK_FIELD_GE(maximum_block_size, STEEMIT_MIN_BLOCK_SIZE_LIMIT); + GOLOS_CHECK_FIELD_LEGE(sbd_interest_rate, 0, STEEMIT_100_PERCENT); + } + + void chain_properties_18::validate() const { + chain_properties_17::validate(); + GOLOS_CHECK_ASSET_GT0(create_account_min_golos_fee, GOLOS); + GOLOS_CHECK_ASSET_GT0(create_account_min_delegation, GOLOS); + GOLOS_CHECK_ASSET_GT0(min_delegation, GOLOS); + GOLOS_CHECK_FIELD_GT(create_account_delegation_time, + (GOLOS_CREATE_ACCOUNT_DELEGATION_TIME).to_seconds() / 2); + } + void witness_update_operation::validate() const { - validate_account_name(owner); - FC_ASSERT(url.size() > 0, "URL size must be greater than 0"); - FC_ASSERT(fc::is_utf8(url), "URL is not valid UTF8"); - FC_ASSERT(fee >= asset(0, STEEM_SYMBOL), "Fee cannot be negative"); - props.validate(); + GOLOS_CHECK_PARAM_ACCOUNT(owner); + GOLOS_CHECK_PARAM(url, { + GOLOS_CHECK_VALUE_NOT_EMPTY(url); + // GOLOS_CHECK_VALUE_MAX_SIZE(url, STEEMIT_MAX_WITNESS_URL_LENGTH); // can't add without HF + GOLOS_CHECK_VALUE_UTF8(url); + }); + GOLOS_CHECK_PARAM(fee, { + GOLOS_CHECK_ASSET_GE0(fee, GOLOS); //"cannot be negative" + }); + GOLOS_CHECK_PARAM_VALIDATE(props); } struct chain_properties_validator { @@ -226,8 +248,8 @@ namespace golos { namespace protocol { }; void chain_properties_update_operation::validate() const { - validate_account_name(owner); - props.visit(chain_properties_validator()); + GOLOS_CHECK_PARAM_ACCOUNT(owner); + GOLOS_CHECK_PARAM(props, props.visit(chain_properties_validator())); } void account_witness_vote_operation::validate() const { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 9980dfb88b..3e4d78572d 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -483,6 +483,12 @@ namespace golos { namespace chain { template void push_tx_with_ops(signed_transaction& tx, const fc::ecc::private_key& k, Ops... ops) { + sign_tx_with_ops(tx, k, ops...); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + } + + template + void push_tx_with_ops_throw(signed_transaction& tx, const fc::ecc::private_key& k, Ops... ops) { sign_tx_with_ops(tx, k, ops...); db->push_transaction(tx, 0); } diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp new file mode 100644 index 0000000000..e85ec48e9c --- /dev/null +++ b/tests/common/helpers.hpp @@ -0,0 +1,90 @@ +#pragma once + +// Common code sequences for testing and boost container extensions + + +// Validate +//------------------------------------------------------------- + +/// validate operation +#define CHECK_OP_VALID(OP) BOOST_CHECK_NO_THROW(OP.validate()) + +/// change operation parameter value and check it's still valid +#define CHECK_PARAM_VALID(OP, NAME, VAL) \ + CHECK_PARAM_VALID_I(OP, NAME, VAL, CHECK_OP_VALID(OP)) + +/// change operation parameter value and check it's invalid (+restore param) +#define CHECK_PARAM_INVALID(OP, N, V) \ + CHECK_PARAM_VALIDATION_FAIL(OP, N, V, invalid_parameter, #N) + +/// change operation parameter value and check it fails with logic_exceprion (+restore param) +#define CHECK_PARAM_INVALID_LOGIC(OP, N, V, EX) \ + CHECK_PARAM_VALIDATION_FAIL(OP, N, V, logic_exception, logic_exception:: EX) + +/// same as previous but with configurable CHECK_ERROR parameters +#define CHECK_PARAM_VALIDATION_FAIL(OP, N, V, EX, EV) \ + CHECK_PARAM_VALID_I(OP, N, V, \ + GOLOS_CHECK_ERROR_PROPS(OP.validate(), CHECK_ERROR(EX, EV))) + + +// Push tx +#define GOLOS_TEST_TX_THROW(E, KEY, SETUP) GOLOS_TEST_TX_I(SETUP, KEY, GOLOS_CHECK_PUSH_TX_THROW(E)) +#define GOLOS_TEST_TX_NO_THROW(KEY, SETUP) GOLOS_TEST_TX_I(SETUP, KEY, GOLOS_CHECK_PUSH_TX_NO_THROW) +#define GOLOS_TEST_TX_I(SETUP, KEY, PUSH) \ + tx.clear(); \ + SETUP; \ + tx.sign(KEY, db->get_chain_id()); \ + PUSH; + + +// Check operation authorities +#define CHECK_OP_AUTHS(OP, OWNER, ACTIVE, POSTING) {\ + account_name_set auths; \ + OP.get_required_owner_authorities(auths); \ + BOOST_CHECK_EQUAL(auths, OWNER); \ + auths.clear(); \ + OP.get_required_active_authorities(auths); \ + BOOST_CHECK_EQUAL(auths, ACTIVE); \ + auths.clear(); \ + OP.get_required_posting_authorities(auths); \ + BOOST_CHECK_EQUAL(auths, POSTING); \ + auths.clear(); \ +} + + +// internals +//------------------------------------------------------------- + +// validate +#define CHECK_PARAM_VALID_I(OP, NAME, VAL, CHECK) { \ + auto t = OP.NAME; \ + OP.NAME = VAL; \ + CHECK; \ + OP.NAME = t; \ +} + + +// push tx +#define GOLOS_CHECK_PUSH_TX_NO_THROW GOLOS_CHECK_PUSH_TX_NO_THROW_F(0) +#define GOLOS_CHECK_PUSH_TX_NO_THROW_F(F) BOOST_CHECK_NO_THROW(db->push_transaction(tx, F)) +#define GOLOS_CHECK_PUSH_TX_THROW(E) GOLOS_CHECK_PUSH_TX_THROW_F(0, E) +#define GOLOS_CHECK_PUSH_TX_THROW_F(F, E) \ + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, F), CHECK_ERROR(E, 0)) + + +// boost::container << +//------------------------------------------------------------- +namespace boost { namespace container { + +template +std::ostream &operator<<(std::ostream &out, const flat_set &t) { + out << "("; + if (!t.empty()) { + std::for_each(t.begin(), t.end()-1, [&](const T& v) {out << v << ",";}); + out << *t.rbegin(); + } + out << ")"; + return out; +} + +} } // namespace boost::container diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 448b0ccf9b..032e65ddd9 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -15,6 +15,7 @@ #include #include "database_fixture.hpp" +#include "helpers.hpp" #include #include @@ -27,21 +28,7 @@ using namespace golos::chain; using namespace golos::protocol; using std::string; - -namespace boost { namespace container { - -template -std::ostream &operator<<(std::ostream &out, const flat_set &t) { - out << "("; - if (!t.empty()) { - std::for_each(t.begin(), t.end()-1, [&](const T& v) {out << v << ",";}); - out << *t.rbegin(); - } - out << ")"; - return out; -} - -} } // namespace boost::container +using account_name_set = flat_set; fc::variant_object make_comment_id(const std::string& author, const std::string& permlink) { @@ -456,13 +443,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_posting_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.sign(alice_post_key, db->get_chain_id()); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with post signature"); @@ -472,13 +459,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the creator's authority"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_posting_auth, 0)); validate_database(); @@ -545,7 +532,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "comment", make_comment_id("alice", "foobar")))); @@ -1776,65 +1763,52 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(witness_update_validate) { try { BOOST_TEST_MESSAGE("Testing: withness_update_validate"); + BOOST_TEST_MESSAGE("--- success on valid parameters"); + witness_update_operation op; + op.owner = "bob"; + op.url = "http://localhost"; + op.fee = ASSET_GOLOS(100); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, url, "-"); + CHECK_PARAM_VALID(op, url, string(STEEMIT_MAX_WITNESS_URL_LENGTH, ' ')); + CHECK_PARAM_VALID(op, url, u8"тест"); + CHECK_PARAM_VALID(op, fee, ASSET_GOLOS(0)); + + BOOST_TEST_MESSAGE("--- failure when owner is empty"); + CHECK_PARAM_INVALID(op, owner, ""); + + BOOST_TEST_MESSAGE("--- failure when url is empty or too long or have invalid utf8"); + CHECK_PARAM_INVALID(op, url, ""); + // CHECK_PARAM_INVALID(op, url, string(1+STEEMIT_MAX_WITNESS_URL_LENGTH, ' ')); // needs HF + CHECK_PARAM_INVALID(op, url, "\xc3\x28"); + + BOOST_TEST_MESSAGE("--- failure when fee in not GOLOS or negative"); + CHECK_PARAM_INVALID(op, fee, ASSET_GBG(1)); + CHECK_PARAM_INVALID(op, fee, ASSET_GESTS(1)); + CHECK_PARAM_INVALID(op, fee, ASSET_GOLOS(-1)); + + // TODO: chain_properties_17 validate_database(); } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE(witness_update_authorities) { - try { - BOOST_TEST_MESSAGE("Testing: witness_update_authorities"); - - ACTORS((alice)(bob)); - fund("alice", 10000); - - private_key_type signing_key = generate_private_key("new_key"); - - witness_update_operation op; - op.owner = "alice"; - op.url = "foo.bar"; - op.fee = ASSET("1.000 GOLOS"); - op.block_signing_key = signing_key.get_public_key(); - - signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(op); - - BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); - - BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); - tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + BOOST_AUTO_TEST_CASE(witness_update_authorities) { try { + BOOST_TEST_MESSAGE("Testing: witness_update_authorities"); + witness_update_operation op; + op.owner = "bob"; + op.url = "http://localhost"; + // op.fee = ASSET_GOLOS(1); + // op.block_signing_key = signing_key.get_public_key(); - BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); - tx.signatures.clear(); - tx.sign(alice_private_key, db->get_chain_id()); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); - BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); - tx.signatures.clear(); - tx.sign(alice_private_key, db->get_chain_id()); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); - - BOOST_TEST_MESSAGE("--- Test success with witness signature"); - tx.signatures.clear(); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - tx.signatures.clear(); - tx.sign(signing_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); - validate_database(); - } - FC_LOG_AND_RETHROW() - } + } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(witness_update_apply) { try { @@ -1842,11 +1816,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ACTORS((alice)) fund("alice", 10000); - private_key_type signing_key = generate_private_key("new_key"); BOOST_TEST_MESSAGE("--- Test upgrading an account to a witness"); - signed_transaction tx; tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); @@ -1863,69 +1835,70 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op1.owner = op.owner; op1.props = op.props; tx.operations.push_back(op1); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - const witness_object &alice_witness = db->get_witness("alice"); - - BOOST_REQUIRE(alice_witness.owner == "alice"); - BOOST_REQUIRE(alice_witness.created == db->head_block_time()); - BOOST_REQUIRE(to_string(alice_witness.url) == op.url); - BOOST_REQUIRE(alice_witness.signing_key == op.block_signing_key); - BOOST_REQUIRE(alice_witness.props.account_creation_fee == op.props.account_creation_fee); - BOOST_REQUIRE(alice_witness.props.maximum_block_size == op.props.maximum_block_size); - BOOST_REQUIRE(alice_witness.total_missed == 0); - BOOST_REQUIRE(alice_witness.last_aslot == 0); - BOOST_REQUIRE(alice_witness.last_confirmed_block_num == 0); - BOOST_REQUIRE(alice_witness.pow_worker == 0); - BOOST_REQUIRE(alice_witness.votes.value == 0); - BOOST_REQUIRE(alice_witness.virtual_last_update == 0); - BOOST_REQUIRE(alice_witness.virtual_position == 0); - BOOST_REQUIRE(alice_witness.virtual_scheduled_time == fc::uint128_t::max_value()); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); // No fee + const witness_object& w = db->get_witness("alice"); + BOOST_CHECK(w.owner == "alice"); + BOOST_CHECK(w.created == db->head_block_time()); + BOOST_CHECK(to_string(w.url) == op.url); + BOOST_CHECK(w.signing_key == op.block_signing_key); + BOOST_CHECK(w.props.account_creation_fee == op.props.account_creation_fee); + BOOST_CHECK(w.props.maximum_block_size == op.props.maximum_block_size); + BOOST_CHECK(w.total_missed == 0); + BOOST_CHECK(w.last_aslot == 0); + BOOST_CHECK(w.last_confirmed_block_num == 0); + BOOST_CHECK(w.pow_worker == 0); + BOOST_CHECK(w.votes.value == 0); + BOOST_CHECK(w.virtual_last_update == 0); + BOOST_CHECK(w.virtual_position == 0); + BOOST_CHECK(w.virtual_scheduled_time == fc::uint128_t::max_value()); + BOOST_CHECK(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); // No fee validate_database(); BOOST_TEST_MESSAGE("--- Test updating a witness"); - - tx.signatures.clear(); - tx.operations.clear(); + tx.clear(); op.url = "bar.foo"; tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(alice_witness.owner == "alice"); - BOOST_REQUIRE(alice_witness.created == db->head_block_time()); - BOOST_REQUIRE(to_string(alice_witness.url) == "bar.foo"); - BOOST_REQUIRE(alice_witness.signing_key == op.block_signing_key); - BOOST_REQUIRE(alice_witness.props.account_creation_fee == op.props.account_creation_fee); - BOOST_REQUIRE(alice_witness.props.maximum_block_size == op.props.maximum_block_size); - BOOST_REQUIRE(alice_witness.total_missed == 0); - BOOST_REQUIRE(alice_witness.last_aslot == 0); - BOOST_REQUIRE(alice_witness.last_confirmed_block_num == 0); - BOOST_REQUIRE(alice_witness.pow_worker == 0); - BOOST_REQUIRE(alice_witness.votes.value == 0); - BOOST_REQUIRE(alice_witness.virtual_last_update == 0); - BOOST_REQUIRE(alice_witness.virtual_position == 0); - BOOST_REQUIRE(alice_witness.virtual_scheduled_time == fc::uint128_t::max_value()); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); - validate_database(); - - BOOST_TEST_MESSAGE("--- Test failure when upgrading a non-existent account"); - - tx.signatures.clear(); - tx.operations.clear(); - op.owner = "bob"; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + BOOST_CHECK(w.owner == "alice"); + BOOST_CHECK(w.created == db->head_block_time()); + BOOST_CHECK(to_string(w.url) == "bar.foo"); + BOOST_CHECK(w.signing_key == op.block_signing_key); + BOOST_CHECK(w.props.account_creation_fee == op.props.account_creation_fee); + BOOST_CHECK(w.props.maximum_block_size == op.props.maximum_block_size); + BOOST_CHECK(w.total_missed == 0); + BOOST_CHECK(w.last_aslot == 0); + BOOST_CHECK(w.last_confirmed_block_num == 0); + BOOST_CHECK(w.pow_worker == 0); + BOOST_CHECK(w.votes.value == 0); + BOOST_CHECK(w.virtual_last_update == 0); + BOOST_CHECK(w.virtual_position == 0); + BOOST_CHECK(w.virtual_scheduled_time == fc::uint128_t::max_value()); + BOOST_CHECK(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); validate_database(); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(chain_properties_update_validate) { try { + BOOST_TEST_MESSAGE("!NOT READY! Testing: chain_properties_update_validate"); + // TODO + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(chain_properties_update_authorities) { try { + BOOST_TEST_MESSAGE("!NOT READY! Testing: chain_properties_update_authorities"); + // TODO + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(chain_properties_update_apply) { try { + BOOST_TEST_MESSAGE("!NOT READY! Testing: chain_properties_update_apply"); + // TODO + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(account_witness_vote_validate) { try { BOOST_TEST_MESSAGE("Testing: account_witness_vote_validate"); @@ -5572,14 +5545,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("failure when 'from' is empty"); op.from = ""; - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "from")); BOOST_TEST_MESSAGE("failure when 'to' is empty"); op.from = "alice"; op.to = ""; - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "to")); @@ -5591,7 +5564,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("failure when amount is VESTS"); op.to = "alice"; op.amount = ASSET("1.000 VESTS"); - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "amount")); @@ -5608,14 +5581,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("failure when amount is negative"); op.memo = std::string(); op.amount = ASSET("-1.000 GOLOS"); - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "amount")); BOOST_TEST_MESSAGE("failure when memo too large"); op.amount = ASSET("1.000 GOLOS"); op.memo = string(STEEMIT_MAX_MEMO_SIZE, ' '); - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(golos::invalid_parameter, "memo")); } FC_LOG_AND_RETHROW() @@ -5891,7 +5864,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "sam"))); From c602aee1de77dbd31b66664bd9d2393c7a0d0f9d Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 03:08:30 +0300 Subject: [PATCH 093/250] Refactor errors: proposal_delete & proposal_update ops #790 --- libraries/chain/proposal_evaluator.cpp | 28 ++-- .../include/golos/protocol/exceptions.hpp | 27 ++++ libraries/protocol/proposal_operations.cpp | 55 ++++--- tests/common/database_fixture.hpp | 1 + tests/tests/proposal_tests.cpp | 150 +++++++++++++++++- 5 files changed, 222 insertions(+), 39 deletions(-) diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 8486462e18..efd1d57e6b 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -204,13 +205,12 @@ namespace golos { namespace chain { } void proposal_update_evaluator::do_apply(const proposal_update_operation& o) { try { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__542, "Proposal transaction updating"); // remove after hf - safe_int_increment depth_increment(depth_); if (_db.is_producing()) { - FC_ASSERT( + GOLOS_CHECK_LOGIC( depth_ <= STEEMIT_MAX_PROPOSAL_DEPTH, + logic_exception::proposal_depth_too_high, "You can't create more than ${depth} nested proposals", ("depth", STEEMIT_MAX_PROPOSAL_DEPTH)); } @@ -219,17 +219,20 @@ namespace golos { namespace chain { const auto now = _db.head_block_time(); if (proposal.review_period_time && now >= *proposal.review_period_time) { - FC_ASSERT( - o.active_approvals_to_add.empty() && + GOLOS_CHECK_LOGIC( o.owner_approvals_to_add.empty() && + o.active_approvals_to_add.empty() && o.posting_approvals_to_add.empty() && o.key_approvals_to_add.empty(), - "This proposal is in its review period. No new approvals may be added."); + logic_exception::cannot_add_approval_in_review_period, + "This proposal is in it's review period. No new approvals may be added."); } auto check_existing = [&](const auto& to_remove, const auto& dst) { for (const auto& a: to_remove) { - FC_ASSERT(dst.find(a) != dst.end(), "Can't remove the non existing approval '${id}'", ("id", a)); + GOLOS_CHECK_LOGIC(dst.find(a) != dst.end(), + logic_exception::non_existing_approval, + "Can't remove the non existing approval '${id}'", ("id", a)); } }; @@ -240,7 +243,9 @@ namespace golos { namespace chain { auto check_duplicate = [&](const auto& to_add, const auto& dst) { for (const auto& a: to_add) { - FC_ASSERT(dst.find(a) == dst.end(), "Can't add already exist approval '${id}'", ("id", a)); + GOLOS_CHECK_LOGIC(dst.find(a) == dst.end(), + logic_exception::already_existing_approval, + "Can't add already exist approval '${id}'", ("id", a)); } }; @@ -291,14 +296,13 @@ namespace golos { namespace chain { } FC_CAPTURE_AND_RETHROW((o)) } void proposal_delete_evaluator::do_apply(const proposal_delete_operation& o) { try { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__542, "Proposal transaction deleting"); // remove after hf const auto& proposal = _db.get_proposal(o.author, o.title); - - FC_ASSERT( + GOLOS_CHECK_LOGIC( proposal.author == o.requester || proposal.required_active_approvals.count(o.requester) || proposal.required_owner_approvals.count(o.requester) || proposal.required_posting_approvals.count(o.requester), + logic_exception::proposal_delete_not_allowed, // or should it be auth-related? "Provided authority is not authoritative for this proposal.", ("author", o.author)("title", o.title)("requester", o.requester)); @@ -306,4 +310,4 @@ namespace golos { namespace chain { } FC_CAPTURE_AND_RETHROW((o)) } -} } // golos::chain \ No newline at end of file +} } // golos::chain diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index d74d12d2cb..090b518bfe 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -105,6 +105,11 @@ FC_THROW_EXCEPTION(golos::missing_object, "Missing ${type} with id \"${id}\"", \ ("type",type)("id",id) __VA_ARGS__) +#define GOLOS_THROW_OBJECT_ALREADY_EXIST(type, id, ...) \ + FC_THROW_EXCEPTION(golos::object_already_exist, "Object ${type} with id \"${id}\" already exists", \ + ("type",type)("id",id) __VA_ARGS__) + + #define GOLOS_THROW_INTERNAL_ERROR(MSG, ...) \ FC_THROW_EXCEPTION(golos::internal_error, MSG, __VA_ARGS__) @@ -194,6 +199,17 @@ namespace golos { // withdraw_vesting insufficient_fee_for_powerdown_registered_account, operation_would_not_change_vesting_withdraw_rate, + + + + //proposals + empty_approvals, + add_and_remove_same_approval, + cannot_add_approval_in_review_period, + non_existing_approval, + already_existing_approval, + + proposal_delete_not_allowed }; }; @@ -321,6 +337,17 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // withdraw_vesting (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) + + + + //proposals + (empty_approvals) + (add_and_remove_same_approval) + (cannot_add_approval_in_review_period) + (non_existing_approval) + (already_existing_approval) + + (proposal_delete_not_allowed) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/proposal_operations.cpp b/libraries/protocol/proposal_operations.cpp index 3dccb4d0de..0e3c4099e8 100644 --- a/libraries/protocol/proposal_operations.cpp +++ b/libraries/protocol/proposal_operations.cpp @@ -1,15 +1,22 @@ #include #include #include +#include +#include #include -#include #include +// TODO: move somewhere globally accessible +#define GOLOS_PROPOSAL_MAX_TITLE_SIZE 256 +#define GOLOS_PROPOSAL_MAX_MEMO_SIZE 4096 + + namespace golos { namespace protocol { - static inline void validate_account_name(const string& name) { - FC_ASSERT(is_valid_account_name(name), "Account name ${n} is invalid", ("n", name)); + // TODO: reuse code from steem_operations.cpp + static inline void validate_account_name(const string &name) { + GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } void proposal_create_operation::validate() const { @@ -31,27 +38,31 @@ namespace golos { namespace protocol { } void proposal_update_operation::validate() const { - validate_account_name(author); - - FC_ASSERT(!title.empty(), "Title is empty"); - FC_ASSERT(fc::is_utf8(title), "Title not formatted in UTF8"); - - FC_ASSERT( - !(active_approvals_to_add.empty() && active_approvals_to_remove.empty() && - owner_approvals_to_add.empty() && owner_approvals_to_remove.empty() && - posting_approvals_to_add.empty() && posting_approvals_to_remove.empty() && - key_approvals_to_add.empty() && key_approvals_to_remove.empty())); + GOLOS_CHECK_PARAM_ACCOUNT(author); + GOLOS_CHECK_PARAM(title, { + GOLOS_CHECK_VALUE_NOT_EMPTY(title); + GOLOS_CHECK_VALUE_MAX_SIZE(title, GOLOS_PROPOSAL_MAX_TITLE_SIZE); + GOLOS_CHECK_VALUE_UTF8(title); + }); + + GOLOS_CHECK_LOGIC(0 < ( + owner_approvals_to_add.size() + owner_approvals_to_remove.size() + + active_approvals_to_add.size() + active_approvals_to_remove.size() + + posting_approvals_to_add.size() + posting_approvals_to_remove.size() + + key_approvals_to_add.size() + key_approvals_to_remove.size()), + logic_exception::empty_approvals, + "At least one approval add or approval remove must exist"); auto validate = [&](const auto& to_add, const auto& to_remove) { for (const auto& a: to_add) { - FC_ASSERT( - to_remove.find(a) == to_remove.end(), - "Cannot add and remove approval at the same time."); + GOLOS_CHECK_LOGIC(to_remove.find(a) == to_remove.end(), + logic_exception::add_and_remove_same_approval, + "Cannot add and remove approval at the same time"); } }; - validate(active_approvals_to_add, active_approvals_to_remove); validate(owner_approvals_to_add, owner_approvals_to_remove); + validate(active_approvals_to_add, active_approvals_to_remove); validate(posting_approvals_to_add, posting_approvals_to_remove); validate(key_approvals_to_add, key_approvals_to_remove); } @@ -87,9 +98,13 @@ namespace golos { namespace protocol { } void proposal_delete_operation::validate() const { - validate_account_name(author); - FC_ASSERT(!title.empty(), "Title is empty"); - FC_ASSERT(fc::is_utf8(title), "Title not formatted in UTF8"); + GOLOS_CHECK_PARAM_ACCOUNT(requester); + GOLOS_CHECK_PARAM_ACCOUNT(author); + GOLOS_CHECK_PARAM(title, { + GOLOS_CHECK_VALUE_NOT_EMPTY(title); + GOLOS_CHECK_VALUE_MAX_SIZE(title, GOLOS_PROPOSAL_MAX_TITLE_SIZE); + GOLOS_CHECK_VALUE_UTF8(title); + }); } } } // golos::chain diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 3e4d78572d..34ef0d648c 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -85,6 +85,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected, but no exception thrown" ); } \ catch( E const& ex ) { \ const fc::variant_object &props = ex.get_log().at(0).get_data(); \ + (void)props; /*avoid "unused var" spam. TODO: @smedvedev, make it used?*/ \ try { \ C; \ } catch (const fc::exception& err) { \ diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index 126ed65943..ede8bb6912 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -13,11 +13,18 @@ #include #include "database_fixture.hpp" +#include "helpers.hpp" #include #include #include + +// TODO: move somewhere globally accessible +#define GOLOS_PROPOSAL_MAX_TITLE_SIZE 256 +#define GOLOS_PROPOSAL_MAX_MEMO_SIZE 4096 + + using namespace golos; using namespace golos::chain; using namespace golos::protocol; @@ -25,6 +32,135 @@ using std::string; BOOST_FIXTURE_TEST_SUITE(proposal_tests, clean_database_fixture) + +BOOST_AUTO_TEST_CASE(proposal_create_validate) { try { + BOOST_TEST_MESSAGE("Testing: proposal_create_validate"); + + +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(proposal_create_authorities) { try { + BOOST_TEST_MESSAGE("Testing: proposal_create_authorities"); + +} FC_LOG_AND_RETHROW() } + + +BOOST_AUTO_TEST_CASE(proposal_update_validate) { try { + BOOST_TEST_MESSAGE("Testing: proposal_update_validate"); + + using approvals = flat_set; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + proposal_update_operation op; + op.author = "alice"; + op.title = "test"; + op.owner_approvals_to_add = approvals({"bob"}); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, title, "-"); + CHECK_PARAM_VALID(op, title, string(GOLOS_PROPOSAL_MAX_TITLE_SIZE, ' ')); + CHECK_PARAM_VALID(op, title, u8"тест"); + CHECK_PARAM_VALID(op, active_approvals_to_add, approvals({"cid", "dave"})); + + BOOST_TEST_MESSAGE("--- failure when author is empty"); + CHECK_PARAM_INVALID(op, author, ""); + + BOOST_TEST_MESSAGE("--- failure when title is not valid"); + CHECK_PARAM_INVALID(op, title, ""); + CHECK_PARAM_INVALID(op, title, string(1+GOLOS_PROPOSAL_MAX_TITLE_SIZE, ' ')); + CHECK_PARAM_INVALID(op, title, "\xc3\x28"); + + BOOST_TEST_MESSAGE("--- failure when no approvals"); + CHECK_PARAM_INVALID_LOGIC(op, owner_approvals_to_add, approvals(), empty_approvals); + + BOOST_TEST_MESSAGE("--- failure when adding and deleting same approval"); + CHECK_PARAM_INVALID_LOGIC(op, owner_approvals_to_remove, approvals({"bob"}), add_and_remove_same_approval); + +} FC_LOG_AND_RETHROW() } + + +BOOST_AUTO_TEST_CASE(proposal_update_authorities) { try { + BOOST_TEST_MESSAGE("Testing: proposal_update_authorities"); + using account_name_set = flat_set; + account_name_set nobody; + account_name_set bob_acc = account_name_set({"bob"}); + account_name_set cid_acc = account_name_set({"cid"}); + account_name_set bob_and_cid = account_name_set({"bob", "cid"}); + + proposal_update_operation op; + op.author = "alice"; + op.title = "test"; + + BOOST_TEST_MESSAGE("--- owner_approvals_to_add and owner_approvals_to_remove"); + op.owner_approvals_to_add = bob_acc; + CHECK_OP_AUTHS(op, bob_acc, nobody, nobody); + op.owner_approvals_to_remove = cid_acc; + CHECK_OP_AUTHS(op, bob_and_cid, nobody, nobody); + op.owner_approvals_to_add = nobody; + CHECK_OP_AUTHS(op, cid_acc, nobody, nobody); + op.owner_approvals_to_remove = nobody; + + BOOST_TEST_MESSAGE("--- active_approvals_to_add and active_approvals_to_remove"); + op.active_approvals_to_add = bob_acc; + CHECK_OP_AUTHS(op, nobody, bob_acc, nobody); + op.active_approvals_to_remove = cid_acc; + CHECK_OP_AUTHS(op, nobody, bob_and_cid, nobody); + op.active_approvals_to_add = nobody; + CHECK_OP_AUTHS(op, nobody, cid_acc, nobody); + op.active_approvals_to_remove = nobody; + + BOOST_TEST_MESSAGE("--- poting_approvals_to_add and poting_approvals_to_remove"); + op.posting_approvals_to_add = bob_acc; + CHECK_OP_AUTHS(op, nobody, nobody, bob_acc); + op.posting_approvals_to_remove = cid_acc; + CHECK_OP_AUTHS(op, nobody, nobody, bob_and_cid); + op.posting_approvals_to_add = nobody; + CHECK_OP_AUTHS(op, nobody, nobody, cid_acc); + op.posting_approvals_to_remove = nobody; + + // TODO: keys? + +} FC_LOG_AND_RETHROW() } + + +BOOST_AUTO_TEST_CASE(proposal_delete_validate) { try { + BOOST_TEST_MESSAGE("Testing: proposal_delete_validate"); + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + proposal_delete_operation op; + op.requester = "bob"; + op.author = "alice"; + op.title = "test"; + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, title, "-"); + CHECK_PARAM_VALID(op, title, string(GOLOS_PROPOSAL_MAX_TITLE_SIZE, ' ')); + CHECK_PARAM_VALID(op, title, u8"тест"); + + BOOST_TEST_MESSAGE("--- failure when requester or author is empty"); + CHECK_PARAM_INVALID(op, requester, ""); + CHECK_PARAM_INVALID(op, author, ""); + + BOOST_TEST_MESSAGE("--- failure when title is not valid"); + CHECK_PARAM_INVALID(op, title, ""); + CHECK_PARAM_INVALID(op, title, string(GOLOS_PROPOSAL_MAX_TITLE_SIZE+1, ' ')); + CHECK_PARAM_INVALID(op, title, "\xc3\x28"); + +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(proposal_delete_authorities) { try { + BOOST_TEST_MESSAGE("Testing: proposal_delete_authorities"); + proposal_delete_operation op; + op.requester = "bob"; + op.author = "alice"; + op.title = "test"; + + using account_name_set = flat_set; + account_name_set auths; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); + +} FC_LOG_AND_RETHROW() } + + + BOOST_AUTO_TEST_CASE(create_proposal) { try { BOOST_TEST_MESSAGE("Testing: proposal_create_operation"); @@ -56,7 +192,7 @@ BOOST_AUTO_TEST_CASE(create_proposal) { try { cop.proposed_operations.push_back(operation_wrapper(top)); cop.proposed_operations.push_back(operation_wrapper(vop)); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, bob_private_key, cop), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, cop), fc::exception); BOOST_TEST_MESSAGE("--- Simple proposal with a transfer operation"); @@ -122,7 +258,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop.title = cop.title; uop.active_approvals_to_add.insert("alice"); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, bob_private_key, uop), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, uop), fc::exception); proposal_update_operation uop1; uop1.author = cop.author; @@ -130,14 +266,14 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop1.active_approvals_to_add.insert("alice"); uop1.active_approvals_to_remove.insert("alice"); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, alice_private_key, uop1), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, alice_private_key, uop1), fc::exception); proposal_update_operation uop2; uop2.author = cop.author; uop2.title = cop.title; uop2.key_approvals_to_add.insert(bob_public_key); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, alice_private_key, uop2), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, alice_private_key, uop2), fc::exception); BOOST_TEST_MESSAGE("--- Add an approval to a proposal"); @@ -245,7 +381,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop10.author = cop.author; uop10.title = cop.title; uop10.active_approvals_to_add.insert("bob"); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, bob_private_key, uop10), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, uop10), fc::exception); BOOST_TEST_MESSAGE("--- Auto removing of a proposal if no approvals in a review period"); proposal_update_operation uop11; @@ -532,7 +668,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop3.author = cop.author; uop3.title = cop.title; uop3.key_approvals_to_add.insert(dave_public_key); - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, dave_private_key, uop3), tx_invalid_operation); // TODO tx_invalid_operation -> tx_irrelevant_sig + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, dave_private_key, uop3), tx_invalid_operation); // TODO tx_invalid_operation -> tx_irrelevant_sig proposal_update_operation uop4; uop4.author = cop.author; @@ -578,7 +714,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { dop.author = cop.author; dop.title = cop.title; dop.requester = "dave"; - BOOST_REQUIRE_THROW(push_tx_with_ops(tx, dave_private_key, dop), fc::exception); + BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, dave_private_key, dop), fc::exception); BOOST_TEST_MESSAGE("--- Authorized delete of proposal"); From 1bc700b1fceb975e516dcadccf6a5b1525769971 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 03:13:46 +0300 Subject: [PATCH 094/250] Refactor errors: proposal_create #790 --- libraries/chain/proposal_evaluator.cpp | 53 +++++++++++-------- .../include/golos/protocol/exceptions.hpp | 6 +++ libraries/protocol/proposal_operations.cpp | 33 +++++++----- tests/tests/proposal_tests.cpp | 50 +++++++++++++++++ 4 files changed, 108 insertions(+), 34 deletions(-) diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index efd1d57e6b..d1777817d4 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -97,33 +97,41 @@ namespace golos { namespace chain { : evaluator_impl(db) { } - void proposal_create_evaluator::do_apply(const proposal_create_operation& o) { try { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__542, "Proposal transaction creating"); // remove after hf +#define CHECK_ALREADY_EXIST(OP, N, X, Y) \ + if (_db.find_##N(o.X, o.Y)) { \ + GOLOS_THROW_OBJECT_ALREADY_EXIST(#N, fc::mutable_variant_object()(#X,o.X)(#Y,o.Y)); \ + } + void proposal_create_evaluator::do_apply(const proposal_create_operation& o) { try { safe_int_increment depth_increment(depth_); if (_db.is_producing()) { - FC_ASSERT( + GOLOS_CHECK_LOGIC( depth_ <= STEEMIT_MAX_PROPOSAL_DEPTH, + logic_exception::proposal_depth_too_high, "You can't create more than ${depth} nested proposals", ("depth", STEEMIT_MAX_PROPOSAL_DEPTH)); } - FC_ASSERT(nullptr == _db.find_proposal(o.author, o.title), "Proposal already exists."); + CHECK_ALREADY_EXIST(o, proposal, author, title); + // if (nullptr == _db.find_proposal(o.author, o.title)) { + // GOLOS_THROW_OBJECT_ALREADY_EXIST("Proposal", fc::mutable_variant_object()("author",o.author)("title",o.title)); + // } const auto now = _db.head_block_time(); - FC_ASSERT( - o.expiration_time > now, - "Proposal has already expired on creation."); - FC_ASSERT( - o.expiration_time <= now + STEEMIT_MAX_PROPOSAL_LIFETIME_SEC, - "Proposal expiration time is too far in the future."); - FC_ASSERT( - !o.review_period_time || *o.review_period_time > now, - "Proposal review period has expired on creation."); - FC_ASSERT( - !o.review_period_time || *o.review_period_time < o.expiration_time, - "Proposal review period must be less than its overall lifetime."); + GOLOS_CHECK_OP_PARAM(o, expiration_time, { + GOLOS_CHECK_VALUE(o.expiration_time > now, "Proposal has already expired on creation."); + GOLOS_CHECK_VALUE(o.expiration_time <= now + STEEMIT_MAX_PROPOSAL_LIFETIME_SEC, + "Proposal expiration time is too far i n the future."); + }); + if (o.review_period_time) { + GOLOS_CHECK_OP_PARAM(o, review_period_time, { + GOLOS_CHECK_VALUE(*o.review_period_time > now, + "Proposal review period has expired on creation."); + GOLOS_CHECK_VALUE(*o.review_period_time < o.expiration_time, + "Proposal review period must be less than its overall lifetime."); + }); + } //Populate the required approval sets flat_set required_owner; @@ -135,7 +143,7 @@ namespace golos { namespace chain { for (const auto& op : o.proposed_operations) { operation_get_required_authorities(op.op, required_active, required_owner, required_posting, other); } - FC_ASSERT(other.size() == 0); // TODO: what about other??? + GOLOS_ASSERT(other.size() == 0, golos::internal_error, "other size > 0"); // TODO: what about other??? // All accounts which must provide both owner and active authority should be omitted from // the active authority set. Owner authority approval implies active authority approval. @@ -144,20 +152,21 @@ namespace golos { namespace chain { required_total.insert(required_active.begin(), required_active.end()); // For more information, see transaction.cpp - FC_ASSERT( + GOLOS_CHECK_LOGIC( required_posting.empty() != required_total.empty(), + logic_exception::tx_with_both_posting_active_ops, "Can't combine operations required posting authority and active or owner authority"); required_total.insert(required_posting.begin(), required_posting.end()); // Doesn't allow proposal with combination of create_account() + some_operation() // because it will be never approved. for (const auto& account: required_total) { - FC_ASSERT( - nullptr != _db.find_account(account), - "Account '${account}' for proposed operation doesn't exist", ("account", account)); + _db.get_account(account); // will throw if no account + // "Account '${account}' for proposed operation doesn't exist", ("account", account)); } - FC_ASSERT(required_total.size(), "No operations require approvals"); + // Looks like it's impossible to fail because other = 0 and proposed_ops.size > 0 + GOLOS_ASSERT(required_total.size(), golos::internal_error, "No operations require approvals"); transaction trx; for (const auto& op : o.proposed_operations) { diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 090b518bfe..3136097033 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -203,6 +203,9 @@ namespace golos { //proposals + proposal_depth_too_high, + tx_with_both_posting_active_ops, + empty_approvals, add_and_remove_same_approval, cannot_add_approval_in_review_period, @@ -341,6 +344,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, //proposals + (proposal_depth_too_high) + (tx_with_both_posting_active_ops) + (empty_approvals) (add_and_remove_same_approval) (cannot_add_approval_in_review_period) diff --git a/libraries/protocol/proposal_operations.cpp b/libraries/protocol/proposal_operations.cpp index 0e3c4099e8..0dcd1ec79b 100644 --- a/libraries/protocol/proposal_operations.cpp +++ b/libraries/protocol/proposal_operations.cpp @@ -19,22 +19,31 @@ namespace golos { namespace protocol { GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } + void proposal_create_operation::validate() const { - validate_account_name(author); + GOLOS_CHECK_PARAM_ACCOUNT(author); + GOLOS_CHECK_PARAM(title, { + GOLOS_CHECK_VALUE_NOT_EMPTY(title); + GOLOS_CHECK_VALUE_MAX_SIZE(title, GOLOS_PROPOSAL_MAX_TITLE_SIZE); + GOLOS_CHECK_VALUE_UTF8(title); + }); - FC_ASSERT(!title.empty(), "Title is empty"); - FC_ASSERT(title.size() < 256, "Title larger than size limit"); - FC_ASSERT(fc::is_utf8(title), "Title not formatted in UTF8"); + GOLOS_CHECK_PARAM(proposed_operations, { + GOLOS_CHECK_VALUE(!proposed_operations.empty(), "proposed_operations can't be empty"); + for (const auto& op : proposed_operations) { + operation_validate(op.op); + } + }); - FC_ASSERT(!proposed_operations.empty()); - for (const auto& op : proposed_operations) { - operation_validate(op.op); - } + GOLOS_CHECK_PARAM(memo, { + if (memo.size() > 0) { + GOLOS_CHECK_VALUE_MAX_SIZE(memo, GOLOS_PROPOSAL_MAX_MEMO_SIZE); // "Memo larger than size limit" + GOLOS_CHECK_VALUE_UTF8(memo); + } + }); - if (memo.size() > 0) { - FC_ASSERT(memo.size() < 4096, "Memo larger than size limit"); - FC_ASSERT(fc::is_utf8(memo), "Memo not formatted in UTF8"); - } + // TODO: time in past can be validated (expiration_time and review_period_time) + // TODO: combination of posting+active ops van be validated } void proposal_update_operation::validate() const { diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index ede8bb6912..5538d35127 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -36,11 +36,61 @@ BOOST_FIXTURE_TEST_SUITE(proposal_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(proposal_create_validate) { try { BOOST_TEST_MESSAGE("Testing: proposal_create_validate"); + BOOST_TEST_MESSAGE("--- success on valid parameters"); + transfer_operation top; + top.from = "alice"; + top.to = "bob"; + top.amount = ASSET_GBG(1.0); + + proposal_create_operation op; + op.author = "alice"; + op.title = "test"; + op.expiration_time = db->head_block_time() + fc::hours(6); + op.review_period_time = db->head_block_time() + fc::hours(3); + op.proposed_operations.push_back(operation_wrapper(top)); + + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, title, "-"); + CHECK_PARAM_VALID(op, title, string(GOLOS_PROPOSAL_MAX_TITLE_SIZE, ' ')); + CHECK_PARAM_VALID(op, title, u8"тест"); + CHECK_PARAM_VALID(op, memo, string(GOLOS_PROPOSAL_MAX_MEMO_SIZE, ' ')); + CHECK_PARAM_VALID(op, memo, u8"тест"); + + BOOST_TEST_MESSAGE("--- failure when author is empty"); + CHECK_PARAM_INVALID(op, author, ""); + + BOOST_TEST_MESSAGE("--- failure when title is not valid"); + CHECK_PARAM_INVALID(op, title, ""); + CHECK_PARAM_INVALID(op, title, string(1+GOLOS_PROPOSAL_MAX_TITLE_SIZE, ' ')); + CHECK_PARAM_INVALID(op, title, "\xc3\x28"); + + BOOST_TEST_MESSAGE("--- failure when memo is not valid"); + CHECK_PARAM_INVALID(op, memo, string(1+GOLOS_PROPOSAL_MAX_MEMO_SIZE, ' ')); + CHECK_PARAM_INVALID(op, memo, "\xc3\x28"); + + BOOST_TEST_MESSAGE("--- failure when proposed_operations is empty"); + proposal_create_operation e; + CHECK_PARAM_INVALID(op, proposed_operations, e.proposed_operations); + + BOOST_TEST_MESSAGE("--- failure when proposed_operations contains invalid op"); + auto ops = op.proposed_operations; + transfer_operation t2; + t2.from = "alice"; + t2.to = "bob"; + t2.amount = ASSET_GESTS(1.0); + ops.push_back(operation_wrapper(t2)); + // validation fails inside internal transaction, so error contains "amount" field + CHECK_PARAM_VALIDATION_FAIL(op, proposed_operations, ops, invalid_parameter, "amount"); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(proposal_create_authorities) { try { BOOST_TEST_MESSAGE("Testing: proposal_create_authorities"); + proposal_create_operation op; + op.author = "bob"; + op.title = "test"; + using account_name_set = flat_set; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); } FC_LOG_AND_RETHROW() } From b658af81be54d5fb049f2b882d8c1ffd4c4e8e91 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 03:19:32 +0300 Subject: [PATCH 095/250] Refactor errors: account_metadata #790 --- libraries/chain/steem_evaluator.cpp | 1 - libraries/protocol/steem_operations.cpp | 12 +++-- tests/tests/operation_tests.cpp | 69 ++++++++++--------------- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 6e7f0f3d2f..3bf913d693 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -398,7 +398,6 @@ namespace golos { namespace chain { } void account_metadata_evaluator::do_apply(const account_metadata_operation& o) { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__196, "account_metadata_operation"); //TODO: Delete after hardfork const auto& account = _db.get_account(o.account); _db.modify(account, [&](account_object& a) { a.last_account_update = _db.head_block_time(); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 77b5a85b51..bd575e18e8 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -19,8 +19,8 @@ namespace golos { namespace protocol { inline void validate_account_json_metadata(const string& json_metadata) { if (json_metadata.size() > 0) { - FC_ASSERT(fc::is_utf8(json_metadata), "JSON Metadata not formatted in UTF8"); - FC_ASSERT(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); + GOLOS_CHECK_VALUE_UTF8(json_metadata); + GOLOS_CHECK_VALUE(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); } } @@ -62,9 +62,11 @@ namespace golos { namespace protocol { } void account_metadata_operation::validate() const { - validate_account_name(account); - FC_ASSERT(json_metadata.size() > 0, "json_metadata can't be empty"); - validate_account_json_metadata(json_metadata); + GOLOS_CHECK_PARAM_ACCOUNT(account); + GOLOS_CHECK_PARAM(json_metadata, { + GOLOS_CHECK_VALUE_NOT_EMPTY(json_metadata); + validate_account_json_metadata(json_metadata); + }); } void comment_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 032e65ddd9..2c52943f0a 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6991,24 +6991,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_metadata_validate) { try { BOOST_TEST_MESSAGE("Testing: account_metadata_validate"); + + BOOST_TEST_MESSAGE("--- Test success under normal conditions"); account_metadata_operation op; - BOOST_TEST_MESSAGE("--- Test failure when bad account name passed"); - op.account = "-bad-"; + op.account = "bob"; op.json_metadata = "{}"; - STEEMIT_REQUIRE_THROW(op.validate(), invalid_value); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, json_metadata, "{\"a\":\"тест\"}") + + BOOST_TEST_MESSAGE("--- Test failure when bad account name passed"); + CHECK_PARAM_INVALID(op, account, "-bad-"); BOOST_TEST_MESSAGE("--- Test failure when json_metadata is empty"); - op.account = "alice"; - op.json_metadata = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID(op, json_metadata, ""); BOOST_TEST_MESSAGE("--- Test failure when json_metadata is invalid JSON"); - op.json_metadata = "{test:fail}"; - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); - - BOOST_TEST_MESSAGE("--- Test success under normal conditions"); - op.json_metadata = "{}"; - op.validate(); + CHECK_PARAM_INVALID(op, json_metadata, "{test:fail}"); } FC_LOG_AND_RETHROW() } @@ -7017,20 +7015,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: account_metadata_authorities"); account_metadata_operation op; - op.account = "alice"; + op.account = "bob"; op.json_metadata = "{}"; - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set({"bob"})); } FC_LOG_AND_RETHROW() } @@ -7058,21 +7045,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->get("alice"); - BOOST_REQUIRE(meta.account == "alice"); - BOOST_REQUIRE(meta.json_metadata == json); - BOOST_REQUIRE(alice_acc.last_account_update == now); + BOOST_CHECK(meta.account == "alice"); + BOOST_CHECK(meta.json_metadata == json); + BOOST_CHECK(alice_acc.last_account_update == now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_REQUIRE(alice_api.json_metadata == json); + BOOST_CHECK(alice_api.json_metadata == json); BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create"); // bob is created before all metadata storing settings // therefore it should have account_metadata_object ACTOR(bob); // create_account with json_metadata = "" meta = db->get("bob"); // just checks presence, throws on fail - BOOST_REQUIRE(meta.account == "bob"); - BOOST_REQUIRE(meta.json_metadata == ""); + BOOST_CHECK(meta.account == "bob"); + BOOST_CHECK(meta.json_metadata == ""); BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create_with_delegation"); generate_blocks(1); @@ -7089,8 +7076,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) push_tx_with_ops(tx, bob_private_key, cr); meta = db->get("sam"); - BOOST_REQUIRE(meta.account == "sam"); - BOOST_REQUIRE(meta.json_metadata == ""); + BOOST_CHECK(meta.account == "sam"); + BOOST_CHECK(meta.json_metadata == ""); validate_database(); } FC_LOG_AND_RETHROW() @@ -7122,12 +7109,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->find("alice"); - BOOST_REQUIRE(meta == nullptr); - BOOST_REQUIRE(alice_acc.last_account_update == now); + BOOST_CHECK(meta == nullptr); + BOOST_CHECK(alice_acc.last_account_update == now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_REQUIRE(alice_api.json_metadata == ""); + BOOST_CHECK(alice_api.json_metadata == ""); ACTOR(bob); // create_account with json_metadata = "" @@ -7146,7 +7133,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) push_tx_with_ops(tx, bob_private_key, cr); meta = db->find("sam"); - BOOST_REQUIRE(meta == nullptr); + BOOST_CHECK(meta == nullptr); validate_database(); } FC_LOG_AND_RETHROW() @@ -7177,12 +7164,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->find("alice"); - BOOST_REQUIRE(meta == nullptr); - BOOST_REQUIRE(alice_acc.last_account_update == now); + BOOST_CHECK(meta == nullptr); + BOOST_CHECK(alice_acc.last_account_update == now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_REQUIRE(alice_api.json_metadata == ""); + BOOST_CHECK(alice_api.json_metadata == ""); ACTOR(bob); // create_account with json_metadata = "" @@ -7201,7 +7188,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) push_tx_with_ops(tx, bob_private_key, cr); meta = db->find("sam"); - BOOST_REQUIRE(meta != nullptr); + BOOST_CHECK(meta != nullptr); validate_database(); } FC_LOG_AND_RETHROW() From fb8444fb71995b1bdc99612351026fb13e5af369 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 03:22:05 +0300 Subject: [PATCH 096/250] Refactor errors: account_create_with_delegation #790 --- libraries/chain/steem_evaluator.cpp | 25 +++--- .../include/golos/protocol/exceptions.hpp | 6 ++ libraries/protocol/steem_operations.cpp | 18 ++--- tests/tests/operation_tests.cpp | 79 +++++++++---------- 4 files changed, 61 insertions(+), 67 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 3bf913d693..8fe7baebb0 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -247,16 +247,9 @@ namespace golos { namespace chain { } void account_create_with_delegation_evaluator::do_apply(const account_create_with_delegation_operation& o) { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__535, "Account creation with delegation"); - const auto& creator = _db.get_account(o.creator); - FC_ASSERT(creator.balance >= o.fee, "Insufficient balance to create account.", - ("creator.balance", creator.balance)("required", o.fee)); - FC_ASSERT(creator.available_vesting_shares(true) >= o.delegation, - "Insufficient vesting shares to delegate to new account.", - ("creator.vesting_shares", creator.vesting_shares) - ("creator.delegated_vesting_shares", creator.delegated_vesting_shares) - ("required", o.delegation)); + GOLOS_CHECK_BALANCE(creator, MAIN_BALANCE, o.fee); + GOLOS_CHECK_BALANCE(creator, AVAILABLE_VESTING, o.delegation); const auto& v_share_price = _db.get_dynamic_global_properties().get_vesting_share_price(); const auto& median_props = _db.get_witness_schedule_object().median_props; @@ -269,11 +262,15 @@ namespace golos { namespace chain { #endif auto current_delegation = o.fee * target.amount.value / min_fee * v_share_price + o.delegation; - FC_ASSERT(current_delegation >= target_delegation, - "Inssufficient Delegation ${f} required, ${p} provided.", + GOLOS_CHECK_LOGIC(current_delegation >= target_delegation, + logic_exception::not_enough_delegation, + "Insufficient Delegation ${f} required, ${p} provided.", ("f", target_delegation)("p", current_delegation)("o.fee", o.fee) ("o.delegation", o.delegation)); - FC_ASSERT(o.fee >= median_props.create_account_min_golos_fee, - "Insufficient Fee: ${f} required, ${p} provided.", ("f", median_props.create_account_min_golos_fee)("p", o.fee)); + auto min_golos = median_props.create_account_min_golos_fee; + GOLOS_CHECK_OP_PARAM(o, fee, { + GOLOS_CHECK_VALUE(o.fee >= min_golos, + "Insufficient Fee: ${f} required, ${p} provided.", ("f", min_golos)("p", o.fee)); + }); for (auto& a : o.owner.account_auths) { _db.get_account(a.first); @@ -309,7 +306,7 @@ namespace golos { namespace chain { auth.posting = o.posting; auth.last_owner_update = fc::time_point_sec::min(); }); - if (o.delegation.amount > 0) { // Is it needed to allow zero delegation in this method ? + if (o.delegation.amount > 0) { _db.create([&](vesting_delegation_object& d) { d.delegator = o.creator; d.delegatee = o.new_account_name; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 3136097033..fe7cbb7acc 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -202,6 +202,9 @@ namespace golos { + //account_create_with_delegation + not_enough_delegation, + //proposals proposal_depth_too_high, tx_with_both_posting_active_ops, @@ -343,6 +346,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, + //account_create_with_delegation + (not_enough_delegation) + //proposals (proposal_depth_too_high) (tx_with_both_posting_active_ops) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index bd575e18e8..06b41b5718 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -38,16 +38,14 @@ namespace golos { namespace protocol { } void account_create_with_delegation_operation::validate() const { - validate_account_name(new_account_name); - validate_account_name(creator); - FC_ASSERT(is_asset_type(fee, STEEM_SYMBOL), "Account creation fee must be GOLOS"); - FC_ASSERT(is_asset_type(delegation, VESTS_SYMBOL), "Delegation must be GESTS"); - FC_ASSERT(fee.amount >= 0, "Account creation fee cannot be negative"); - FC_ASSERT(delegation.amount >= 0, "Delegation cannot be negative"); - owner.validate(); - active.validate(); - posting.validate(); - validate_account_json_metadata(json_metadata); + GOLOS_CHECK_PARAM_ACCOUNT(new_account_name); + GOLOS_CHECK_PARAM_ACCOUNT(creator); + GOLOS_CHECK_PARAM(fee, {GOLOS_CHECK_ASSET_GE0(fee, GOLOS)}); + GOLOS_CHECK_PARAM(delegation, {GOLOS_CHECK_ASSET_GE0(delegation, GESTS)}); + GOLOS_CHECK_PARAM_VALIDATE(owner); + GOLOS_CHECK_PARAM_VALIDATE(active); + GOLOS_CHECK_PARAM_VALIDATE(posting); + GOLOS_CHECK_PARAM(json_metadata, validate_account_json_metadata(json_metadata)); } void account_update_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 2c52943f0a..66ffaaaee4 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6589,8 +6589,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_with_delegation_validate) { try { + BOOST_TEST_MESSAGE("Testing: account_create_with_delegation_validate"); + + BOOST_TEST_MESSAGE("--- Test valid operation"); account_create_with_delegation_operation op; private_key_type priv_key = generate_private_key("temp_key"); + op.fee = ASSET_GOLOS(10); op.delegation = ASSET_GESTS(100); op.creator = "alice"; op.new_account_name = "bob"; @@ -6598,28 +6602,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.active = authority(1, priv_key.get_public_key(), 1); op.memo_key = priv_key.get_public_key(); op.json_metadata = "{\"foo\":\"bar\"}"; + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, json_metadata, ""); + CHECK_PARAM_VALID(op, json_metadata, "{\"a\":\"тест\"}"); BOOST_TEST_MESSAGE("--- Test failing on negative fee"); - op.fee = ASSET_GOLOS(-1); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID(op, fee, ASSET_GOLOS(-1)); + + BOOST_TEST_MESSAGE("--- Test failing when fee is not GOLOS"); + CHECK_PARAM_INVALID(op, fee, ASSET_GBG(10)); BOOST_TEST_MESSAGE("--- Test failing on negative delegation"); - op.fee = ASSET_GOLOS(10); - op.delegation = ASSET_GESTS(-1); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID(op, delegation, ASSET_GESTS(-1)); BOOST_TEST_MESSAGE("--- Test failing when delegation is not VESTS"); - op.delegation = ASSET_GOLOS(100); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID(op, delegation, ASSET_GOLOS(100)); - BOOST_TEST_MESSAGE("--- Test failing when fee is not GOLOS"); - op.fee = ASSET_GBG(10); - op.delegation = ASSET_GESTS(100); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + BOOST_TEST_MESSAGE("--- Test failing when account empty"); + CHECK_PARAM_INVALID(op, creator, ""); + CHECK_PARAM_INVALID(op, new_account_name, ""); - BOOST_TEST_MESSAGE("--- Test valid operation"); - op.fee = ASSET_GOLOS(10); - op.validate(); + BOOST_TEST_MESSAGE("--- Test failing when json_metadata invalid"); + CHECK_PARAM_INVALID(op, json_metadata, "{a:b}"); + + // TODO: owner/active/posting } FC_LOG_AND_RETHROW() } @@ -6628,21 +6634,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) try { BOOST_TEST_MESSAGE("Testing: account_create_with_delegation_authorities"); account_create_with_delegation_operation op; - op.creator = "alice"; - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - expected.insert("alice"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); - - expected.clear(); - auths.clear(); - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); + op.creator = "bob"; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -6688,22 +6681,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) const account_object& bob_acc = db->get_account("bob"); const account_object& alice_acc = db->get_account("alice"); - BOOST_REQUIRE(alice_acc.delegated_vesting_shares == ASSET_GESTS(1e7)); - BOOST_REQUIRE(bob_acc.received_vesting_shares == ASSET_GESTS(1e7)); - BOOST_REQUIRE(bob_acc.available_vesting_shares(true) == + BOOST_CHECK(alice_acc.delegated_vesting_shares == ASSET_GESTS(1e7)); + BOOST_CHECK(bob_acc.received_vesting_shares == ASSET_GESTS(1e7)); + BOOST_CHECK(bob_acc.available_vesting_shares(true) == bob_acc.vesting_shares - bob_acc.delegated_vesting_shares); - BOOST_REQUIRE(bob_acc.available_vesting_shares() == + BOOST_CHECK(bob_acc.available_vesting_shares() == bob_acc.vesting_shares - bob_acc.delegated_vesting_shares); - BOOST_REQUIRE(bob_acc.effective_vesting_shares() == + BOOST_CHECK(bob_acc.effective_vesting_shares() == bob_acc.vesting_shares - bob_acc.delegated_vesting_shares + bob_acc.received_vesting_shares); BOOST_TEST_MESSAGE("--- Test delegation object integrity"); auto delegation = db->find(std::make_tuple(op.creator, op.new_account_name)); - BOOST_REQUIRE(delegation != nullptr); - BOOST_REQUIRE(delegation->delegator == op.creator); - BOOST_REQUIRE(delegation->delegatee == op.new_account_name); - BOOST_REQUIRE(delegation->vesting_shares == ASSET_GESTS(1e7)); - BOOST_REQUIRE(delegation->min_delegation_time == db->head_block_time() + GOLOS_CREATE_ACCOUNT_DELEGATION_TIME); + BOOST_CHECK(delegation != nullptr); + BOOST_CHECK(delegation->delegator == op.creator); + BOOST_CHECK(delegation->delegatee == op.new_account_name); + BOOST_CHECK(delegation->vesting_shares == ASSET_GESTS(1e7)); + BOOST_CHECK(delegation->min_delegation_time == db->head_block_time() + GOLOS_CREATE_ACCOUNT_DELEGATION_TIME); auto delegated = delegation->vesting_shares; auto exp_time = delegation->min_delegation_time; @@ -6759,10 +6752,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto itr = db->get_index().begin(); auto end = db->get_index().end(); - BOOST_REQUIRE(itr != end); - BOOST_REQUIRE(itr->delegator == "alice"); - BOOST_REQUIRE(itr->vesting_shares == delegated); - BOOST_REQUIRE(itr->expiration == exp_time); + BOOST_CHECK(itr != end); + BOOST_CHECK(itr->delegator == "alice"); + BOOST_CHECK(itr->vesting_shares == delegated); + BOOST_CHECK(itr->expiration == exp_time); validate_database(); } FC_LOG_AND_RETHROW() From 44e9e8881841ae153a4b74c1d7d57165591ae65f Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:48:07 +0700 Subject: [PATCH 097/250] Code style. #805 --- .../private_message_evaluators.hpp | 31 +- .../private_message_objects.hpp | 271 ++++++++-------- .../private_message_plugin.hpp | 96 +++--- .../private_message_objects.cpp | 12 +- .../private_message_plugin.cpp | 298 +++++++++--------- 5 files changed, 344 insertions(+), 364 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index c3aa1e4962..51608f13ff 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -5,25 +5,22 @@ #include #include -namespace golos { - namespace plugins { - namespace private_message { +namespace golos { namespace plugins { namespace private_message { - class private_message_evaluator : public golos::chain::evaluator_impl - { - public: - typedef private_message_operation operation_type; + class private_message_evaluator: + public golos::chain::evaluator_impl + { + public: + using operation_type = private_message_operation; - private_message_evaluator(database& db, private_message_plugin* plugin) - : golos::chain::evaluator_impl( db ) - , _plugin( plugin ) - {} + private_message_evaluator(database& db, private_message_plugin* plugin) + : golos::chain::evaluator_impl(db), + plugin_(plugin) + {} - void do_apply( const private_message_operation& o ); + void do_apply(const private_message_operation& o); - private_message_plugin* _plugin; - }; + private_message_plugin* plugin_; + }; - } - } -} +} } } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 119976e56b..ed90bef7b6 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -10,154 +10,145 @@ #include #include -namespace golos { - namespace plugins { - namespace private_message { +namespace golos { namespace plugins { namespace private_message { - using namespace golos::protocol; - using namespace chainbase; - using namespace golos::chain; + using namespace golos::protocol; + using namespace chainbase; + using namespace golos::chain; #ifndef PRIVATE_MESSAGE_SPACE_ID #define PRIVATE_MESSAGE_SPACE_ID 6 #endif -#define STEEMIT_PRIVATE_MESSAGE_COP_ID 777 - - enum private_message_object_type { - message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) - }; - - - struct message_body { - fc::time_point thread_start; /// the sent_time of the original message, if any - std::string subject; - std::string body; - std::string json_meta; - flat_set cc; - }; - - - class message_object - : public object { - public: - template - message_object(Constructor &&c, allocator a) : - encrypted_message(a) { - c(*this); - } - - id_type id; - - account_name_type from; - account_name_type to; - public_key_type from_memo_key; - public_key_type to_memo_key; - uint64_t sent_time = 0; /// used as seed to secret generation - time_point_sec receive_time; /// time received by blockchain - uint32_t checksum = 0; - buffer_type encrypted_message; - }; - - typedef message_object::id_type message_id_type; - - struct message_api_obj { - message_api_obj(const message_object &o) : - id(o.id), - from(o.from), - to(o.to), - from_memo_key(o.from_memo_key), - to_memo_key(o.to_memo_key), - sent_time(o.sent_time), - receive_time(o.receive_time), - checksum(o.checksum), - encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { - } - - message_api_obj() { - } - - message_id_type id; - account_name_type from; - account_name_type to; - public_key_type from_memo_key; - public_key_type to_memo_key; - uint64_t sent_time; - time_point_sec receive_time; - uint32_t checksum; - vector encrypted_message; - }; - - struct extended_message_object : public message_api_obj { - extended_message_object() { - } - - extended_message_object(const message_api_obj &o) - : message_api_obj(o) { - } - - message_body message; - }; - - struct by_to_date; - struct by_from_date; - - using namespace boost::multi_index; - - using message_index = multi_index_container< - message_object, - indexed_by< - ordered_unique< - tag, - member - >, - ordered_unique< - tag, - composite_key< - message_object, - member, - member, - member - >, - composite_key_compare, std::greater, std::less> - >, - ordered_unique< - tag, - composite_key< - message_object, - member, - member, - member - >, - composite_key_compare, std::greater, std::less> - > - >, - allocator - >; - - struct private_message_operation: public base_operation { - account_name_type from; - account_name_type to; - public_key_type from_memo_key; - public_key_type to_memo_key; - uint64_t sent_time = 0; /// used as seed to secret generation - uint32_t checksum = 0; - std::vector encrypted_message; - - void validate() const; - void get_required_posting_authorities(flat_set& a) const { - a.insert(from); - } - }; - - using private_message_plugin_operation = fc::static_variant; + enum private_message_object_type { + message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + }; + + struct message_body { + fc::time_point thread_start; /// the sent_time of the original message, if any + std::string subject; + std::string body; + std::string json_meta; + flat_set cc; + }; + + class message_object: + public object { + public: + template + message_object(Constructor&& c, allocator a) + : encrypted_message(a) { + c(*this); + } + + id_type id; + + account_name_type from; + account_name_type to; + public_key_type from_memo_key; + public_key_type to_memo_key; + uint64_t sent_time = 0; /// used as seed to secret generation + time_point_sec receive_time; /// time received by blockchain + uint32_t checksum = 0; + buffer_type encrypted_message; + }; + + using message_id_type = message_object::id_type; + + struct message_api_obj { + message_api_obj(const message_object& o) + : id(o.id), + from(o.from), + to(o.to), + from_memo_key(o.from_memo_key), + to_memo_key(o.to_memo_key), + sent_time(o.sent_time), + receive_time(o.receive_time), + checksum(o.checksum), + encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { + } + + message_api_obj() = default; + + message_id_type id; + account_name_type from; + account_name_type to; + public_key_type from_memo_key; + public_key_type to_memo_key; + uint64_t sent_time; + time_point_sec receive_time; + uint32_t checksum; + std::vector encrypted_message; + }; + struct extended_message_object: public message_api_obj { + extended_message_object() = default; + + extended_message_object(const message_api_obj& o) + : message_api_obj(o) { + } + + message_body message; + }; + + struct by_to_date; + struct by_from_date; + + using namespace boost::multi_index; + + using message_index = multi_index_container< + message_object, + indexed_by< + ordered_unique< + tag, + member>, + ordered_unique< + tag, + composite_key< + message_object, + member, + member, + member>, + composite_key_compare< + std::less, + std::greater, + std::less>>, + ordered_unique< + tag, + composite_key< + message_object, + member, + member, + member>, + composite_key_compare< + std::less, + std::greater, + std::less>>>, + allocator>; + + struct private_message_operation: public base_operation { + account_name_type from; + account_name_type to; + public_key_type from_memo_key; + public_key_type to_memo_key; + uint64_t sent_time = 0; /// used as seed to secret generation + uint32_t checksum = 0; + std::vector encrypted_message; + + void validate() const; + + void get_required_posting_authorities(flat_set& a) const { + a.insert(from); } - } -} + }; + + using private_message_plugin_operation = fc::static_variant; + +} } } // golos::plugins::private_message -FC_REFLECT((golos::plugins::private_message::private_message_operation), - (from)(to)(from_memo_key)(to_memo_key)(sent_time)(checksum)(encrypted_message)) +FC_REFLECT( + (golos::plugins::private_message::private_message_operation), + (from)(to)(from_memo_key)(to_memo_key)(sent_time)(checksum)(encrypted_message)) FC_REFLECT_TYPENAME((golos::plugins::private_message::private_message_plugin_operation)) -DECLARE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation) +DECLARE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation) \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index f969a59ac4..f8fe151e69 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -13,73 +13,65 @@ #include #include -namespace golos { - namespace plugins { - namespace private_message { - using namespace golos::chain; - // struct inbox_r { - // vector inbox; - // }; +namespace golos { namespace plugins { namespace private_message { + using namespace golos::chain; - // struct outbox_r { - // vector outbox; - // }; + DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) - DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, vector ) - DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, vector ) + /** + * This plugin scans the blockchain for custom operations containing a valid message and authorized + * by the posting key. + * + */ + class private_message_plugin final : public appbase::plugin { + public: + APPBASE_PLUGIN_REQUIRES((json_rpc::plugin)) - /** - * This plugin scans the blockchain for custom operations containing a valid message and authorized - * by the posting key. - * - */ - class private_message_plugin final : public appbase::plugin { - public: + private_message_plugin(); - APPBASE_PLUGIN_REQUIRES((json_rpc::plugin)) + ~private_message_plugin(); - private_message_plugin(); + void set_program_options( + boost::program_options::options_description &cli, + boost::program_options::options_description &cfg) override; - ~private_message_plugin(); + void plugin_initialize(const boost::program_options::variables_map &options) override; - void set_program_options( - boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) override; + void plugin_startup() override; - void plugin_initialize(const boost::program_options::variables_map &options) override; + void plugin_shutdown() override; - void plugin_startup() override; + flat_map tracked_accounts() const; /// map start_range to end_range - void plugin_shutdown() override; + static const std::string &name(); - flat_map tracked_accounts() const; /// map start_range to end_range + DECLARE_API((get_inbox)(get_outbox)) - friend class private_message_plugin_impl; + private: + class private_message_plugin_impl; + friend class private_message_plugin_impl; - constexpr const static char *plugin_name = "private_message"; + std::unique_ptr my; + }; - static const std::string &name() { - static std::string name = plugin_name; - return name; - } +} } } //golos::plugins::private_message - DECLARE_API((get_inbox)(get_outbox)) +FC_REFLECT( + (golos::plugins::private_message::message_body), + (thread_start)(subject)(body)(json_meta)(cc)); +FC_REFLECT( + (golos::plugins::private_message::message_object), + (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::private_message::message_object, golos::plugins::private_message::message_index); - private: - class private_message_plugin_impl; +FC_REFLECT( + (golos::plugins::private_message::message_api_obj), + (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); - std::unique_ptr my; - }; - } - } -} //golos::plugins::private_message - -FC_REFLECT((golos::plugins::private_message::message_body), (thread_start)(subject)(body)(json_meta)(cc)); - -FC_REFLECT((golos::plugins::private_message::message_object), (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); -CHAINBASE_SET_INDEX_TYPE(golos::plugins::private_message::message_object, golos::plugins::private_message::message_index); - -FC_REFLECT((golos::plugins::private_message::message_api_obj), (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); - -FC_REFLECT_DERIVED((golos::plugins::private_message::extended_message_object), ((golos::plugins::private_message::message_api_obj)), (message)); +FC_REFLECT_DERIVED( + (golos::plugins::private_message::extended_message_object), + ((golos::plugins::private_message::message_api_obj)), + (message)); diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_objects.cpp index 95775dab53..5341e04cd0 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_objects.cpp @@ -1,15 +1,11 @@ #include #include -namespace golos { - namespace plugins { - namespace private_message { +namespace golos { namespace plugins { namespace private_message { - void private_message_operation::validate() const { - FC_ASSERT(from != to, "You cannot write to yourself"); - } - } + void private_message_operation::validate() const { + FC_ASSERT(from != to, "You cannot write to yourself"); } -} +} } } // golos::plugins::private_message DEFINE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 3aa2e7ed68..9c9f3cbe67 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -16,7 +16,6 @@ T dejsonify(const std::string &s) { return fc::json::from_string(s).as(); } -#define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value)) #define LOAD_VALUE_SET(options, name, container, type) \ if( options.count(name) ) { \ const std::vector& ops = options[name].as>(); \ @@ -24,181 +23,186 @@ if( options.count(name) ) { \ } // -namespace golos { - namespace plugins { - namespace private_message { +namespace golos { namespace plugins { namespace private_message { - class private_message_plugin::private_message_plugin_impl final { - public: - private_message_plugin_impl(private_message_plugin &_plugin) - : _self(_plugin) , - _db(appbase::app().get_plugin().db()){ - _custom_operation_interpreter = std::make_shared - < generic_custom_operation_interpreter > (_db); + class private_message_plugin::private_message_plugin_impl final { + public: + private_message_plugin_impl(private_message_plugin& plugin) + : db_(appbase::app().get_plugin().db()) { + custom_operation_interpreter_ = std::make_shared + >(db_); - _custom_operation_interpreter->register_evaluator(&_self); + custom_operation_interpreter_->register_evaluator(&plugin); - _db.set_custom_operation_interpreter(_self.name(), _custom_operation_interpreter); - return; - } - - vector get_inbox(const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) const; - - vector get_outbox(const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) const; + db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); + return; + } + std::vector get_inbox( + const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) const; - ~private_message_plugin_impl() {}; + std::vector get_outbox( + const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) const; - private_message_plugin &_self; - std::shared_ptr > _custom_operation_interpreter; - flat_map _tracked_accounts; - golos::chain::database &_db; - }; + ~private_message_plugin_impl() = default; - vector private_message_plugin::private_message_plugin_impl::get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) const { - FC_ASSERT(limit <= 100); + std::shared_ptr> custom_operation_interpreter_; + flat_map tracked_accounts_; - vector result; - const auto &idx = _db.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(to, newest)); + golos::chain::database &db_; + }; - if (idx.size() > offset) { - while (itr != idx.end() && offset && itr->to == to) { - ++itr; - --offset; - } - } + std::vector private_message_plugin::private_message_plugin_impl::get_inbox( + const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset + ) const { + FC_ASSERT(limit <= 100); - while (itr != idx.end() && limit && itr->to == to) { - result.push_back(*itr); - ++itr; - --limit; - } + std::vector result; + const auto &idx = db_.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(to, newest)); - return result; + if (idx.size() > offset) { + while (itr != idx.end() && offset && itr->to == to) { + ++itr; + --offset; } + } - vector private_message_plugin::private_message_plugin_impl::get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) const { - FC_ASSERT(limit <= 100); + while (itr != idx.end() && limit && itr->to == to) { + result.push_back(*itr); + ++itr; + --limit; + } - vector result; - const auto &idx = _db.get_index().indices().get(); + return result; + } - auto itr = idx.lower_bound(std::make_tuple(from, newest)); + std::vector private_message_plugin::private_message_plugin_impl::get_outbox( + const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset + ) const { + FC_ASSERT(limit <= 100); - if (idx.size() > offset) { - while (itr != idx.end() && offset && itr->from == from) { - ++itr; - --offset; - } - } + vector result; + const auto &idx = db_.get_index().indices().get(); - while (itr != idx.end() && limit && itr->from == from) { - result.push_back(*itr); - ++itr; - --limit; - } - return result; - } + auto itr = idx.lower_bound(std::make_tuple(from, newest)); - void private_message_evaluator::do_apply(const private_message_operation &pm) { - database &d = db(); - - const flat_map &tracked_accounts = _plugin->tracked_accounts(); - - auto to_itr = tracked_accounts.lower_bound(pm.to); - auto from_itr = tracked_accounts.lower_bound(pm.from); - - FC_ASSERT(pm.from != pm.to); - FC_ASSERT(pm.from_memo_key != pm.to_memo_key); - FC_ASSERT(pm.sent_time != 0); - FC_ASSERT(pm.encrypted_message.size() >= 32); - - if (!tracked_accounts.size() || - (to_itr != tracked_accounts.end() && pm.to >= to_itr->first && - pm.to <= to_itr->second) || - (from_itr != tracked_accounts.end() && - pm.from >= from_itr->first && pm.from <= from_itr->second)) { - d.create([&](message_object &pmo) { - pmo.from = pm.from; - pmo.to = pm.to; - pmo.from_memo_key = pm.from_memo_key; - pmo.to_memo_key = pm.to_memo_key; - pmo.checksum = pm.checksum; - pmo.sent_time = pm.sent_time; - pmo.receive_time = d.head_block_time(); - pmo.encrypted_message.resize(pm.encrypted_message.size()); - std::copy(pm.encrypted_message.begin(), pm.encrypted_message.end(), - pmo.encrypted_message.begin()); - }); - } + if (idx.size() > offset) { + while (itr != idx.end() && offset && itr->from == from) { + ++itr; + --offset; } + } - private_message_plugin::private_message_plugin(){ - } + while (itr != idx.end() && limit && itr->from == from) { + result.push_back(*itr); + ++itr; + --limit; + } + return result; + } - private_message_plugin::~private_message_plugin() { - } + void private_message_evaluator::do_apply(const private_message_operation &pm) { + database &d = db(); + + const flat_map &tracked_accounts = plugin_->tracked_accounts(); + + auto to_itr = tracked_accounts.lower_bound(pm.to); + auto from_itr = tracked_accounts.lower_bound(pm.from); + + FC_ASSERT(pm.from != pm.to); + FC_ASSERT(pm.from_memo_key != pm.to_memo_key); + FC_ASSERT(pm.sent_time != 0); + FC_ASSERT(pm.encrypted_message.size() >= 32); + + if (!tracked_accounts.size() || + (to_itr != tracked_accounts.end() && pm.to >= to_itr->first && + pm.to <= to_itr->second) || + (from_itr != tracked_accounts.end() && + pm.from >= from_itr->first && pm.from <= from_itr->second) + ) { + d.create([&](message_object &pmo) { + pmo.from = pm.from; + pmo.to = pm.to; + pmo.from_memo_key = pm.from_memo_key; + pmo.to_memo_key = pm.to_memo_key; + pmo.checksum = pm.checksum; + pmo.sent_time = pm.sent_time; + pmo.receive_time = d.head_block_time(); + pmo.encrypted_message.resize(pm.encrypted_message.size()); + std::copy( + pm.encrypted_message.begin(), pm.encrypted_message.end(), + pmo.encrypted_message.begin()); + }); + } + } - void private_message_plugin::set_program_options( - boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) { - cli.add_options() - ("pm-account-range", - boost::program_options::value < std::vector < std::string >> ()->composing()->multitoken(), - "Defines a range of accounts to private messages to/from as a json pair [\"from\",\"to\"] [from,to)"); - cfg.add(cli); - } + private_message_plugin::private_message_plugin() = default; - void private_message_plugin::plugin_initialize(const boost::program_options::variables_map &options) { - ilog("Intializing private message plugin"); - my.reset(new private_message_plugin::private_message_plugin_impl(*this)); + private_message_plugin::~private_message_plugin() = default; - add_plugin_index(my->_db); + const std::string& private_message_plugin::name() { + static std::string name = "private_message"; + return name; + } - typedef pair pairstring; - LOAD_VALUE_SET(options, "pm-accounts", my->_tracked_accounts, pairstring); - JSON_RPC_REGISTER_API(name()) - } + void private_message_plugin::set_program_options( + boost::program_options::options_description &cli, + boost::program_options::options_description &cfg + ) { + cli.add_options() + ("pm-account-range", + boost::program_options::value < std::vector < std::string >> ()->composing()->multitoken(), + "Defines a range of accounts to private messages to/from as a json pair [\"from\",\"to\"] [from,to)"); + cfg.add(cli); + } - void private_message_plugin::plugin_startup() { - ilog("Starting up private message plugin"); - } + void private_message_plugin::plugin_initialize(const boost::program_options::variables_map &options) { + ilog("Intializing private message plugin"); + my = std::make_unique(*this); - void private_message_plugin::plugin_shutdown() { - ilog("Shuting down private message plugin"); - } + add_plugin_index(my->db_); - flat_map private_message_plugin::tracked_accounts() const { - return my->_tracked_accounts; - } + using pairstring = std::pair; + LOAD_VALUE_SET(options, "pm-accounts", my->tracked_accounts_, pairstring); + JSON_RPC_REGISTER_API(name()) + } - // Api Defines - - DEFINE_API(private_message_plugin, get_inbox) { - auto to = args.args->at(0).as(); - auto newest = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto &db = my->_db; - return db.with_weak_read_lock([&]() { - return my->get_inbox(to, newest, limit, offset); - }); - } + void private_message_plugin::plugin_startup() { + ilog("Starting up private message plugin"); + } - DEFINE_API(private_message_plugin, get_outbox) { - auto from = args.args->at(0).as(); - auto newest = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto &db = my->_db; - return db.with_weak_read_lock([&]() { - return my->get_outbox(from, newest, limit, offset); - }); - } - } + void private_message_plugin::plugin_shutdown() { + ilog("Shuting down private message plugin"); + } + + flat_map private_message_plugin::tracked_accounts() const { + return my->tracked_accounts_; + } + + // Api Defines + + DEFINE_API(private_message_plugin, get_inbox) { + auto to = args.args->at(0).as(); + auto newest = args.args->at(1).as(); + auto limit = args.args->at(2).as(); + auto offset = args.args->at(3).as(); + auto &db = my->db_; + return db.with_weak_read_lock([&]() { + return my->get_inbox(to, newest, limit, offset); + }); + } + + DEFINE_API(private_message_plugin, get_outbox) { + auto from = args.args->at(0).as(); + auto newest = args.args->at(1).as(); + auto limit = args.args->at(2).as(); + auto offset = args.args->at(3).as(); + auto &db = my->db_; + return db.with_weak_read_lock([&]() { + return my->get_outbox(from, newest, limit, offset); + }); } -} // golos::plugins::private_message + +} } } // golos::plugins::private_message From 28a492df0f4c9fbef6a54c12c3a00874824140db Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:48:19 +0700 Subject: [PATCH 098/250] Fix inbox/outbox. #805 --- .../private_message_plugin.cpp | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 9c9f3cbe67..599725bb65 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -60,46 +60,38 @@ namespace golos { namespace plugins { namespace private_message { std::vector result; const auto &idx = db_.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(to, newest)); + auto etr = idx.upper_bound(std::make_tuple(to, time_point::min())); - if (idx.size() > offset) { - while (itr != idx.end() && offset && itr->to == to) { - ++itr; - --offset; - } - } + for (; itr != etr && offset; ++itr, --offset); - while (itr != idx.end() && limit && itr->to == to) { - result.push_back(*itr); - ++itr; - --limit; + result.reserve(limit); + for (; itr != etr && limit; ++itr, --limit) { + result.emplace_back(*itr); } return result; } - std::vector private_message_plugin::private_message_plugin_impl::get_outbox( + std::vector private_message_plugin::private_message_plugin_impl::get_outbox( const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset ) const { FC_ASSERT(limit <= 100); - vector result; + std::vector result; const auto &idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(from, newest)); + auto etr = idx.upper_bound(std::make_tuple(from, time_point::min())); - if (idx.size() > offset) { - while (itr != idx.end() && offset && itr->from == from) { - ++itr; - --offset; - } - } + for (; itr != etr && offset; ++itr, --offset); - while (itr != idx.end() && limit && itr->from == from) { - result.push_back(*itr); - ++itr; - --limit; + result.reserve(limit); + for (; itr != etr && limit; ++itr, --limit) { + result.emplace_back(*itr); } + return result; } From 65e7fd250f64547ea811e64ca4515d1d02fcaa95 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:48:45 +0700 Subject: [PATCH 099/250] Fix size of encrypted message. #805 --- plugins/private_message/private_message_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 599725bb65..3db455903b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -106,7 +106,7 @@ namespace golos { namespace plugins { namespace private_message { FC_ASSERT(pm.from != pm.to); FC_ASSERT(pm.from_memo_key != pm.to_memo_key); FC_ASSERT(pm.sent_time != 0); - FC_ASSERT(pm.encrypted_message.size() >= 32); + FC_ASSERT(pm.encrypted_message.size() >= 16); if (!tracked_accounts.size() || (to_itr != tracked_accounts.end() && pm.to >= to_itr->first && From 96f2d81491b5f27643dd386fb69e4e8d6944ac03 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:48:52 +0700 Subject: [PATCH 100/250] Extend time_convertor in cli_wallet. #805 --- libraries/wallet/include/golos/wallet/time_converter.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/wallet/include/golos/wallet/time_converter.hpp b/libraries/wallet/include/golos/wallet/time_converter.hpp index 7ff112ced2..655372e0d6 100644 --- a/libraries/wallet/include/golos/wallet/time_converter.hpp +++ b/libraries/wallet/include/golos/wallet/time_converter.hpp @@ -8,7 +8,7 @@ class time_converter { private: time_point_sec tps; public: - time_converter(const std::string &s, const time_point_sec &start_tps, const time_point_sec &default_tps) { + time_converter(const std::string& s, const time_point_sec& start_tps, const time_point_sec& default_tps) { if (s.empty()) { tps = default_tps; return; @@ -18,6 +18,11 @@ class time_converter { tps += std::stoi(s.substr(1)); return; } + if (s.at(0) == '-') { + tps = start_tps; + tps -= std::stoi(s.substr(1)); + return; + } tps = time_point_sec::from_iso_string(s); if (tps.sec_since_epoch() == 0) { tps = default_tps; From b2b6fb2ead594f29f4b37634539366864fbc5903 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:48:59 +0700 Subject: [PATCH 101/250] Minimize field numbers in private message_body. #805 --- .../golos/plugins/private_message/private_message_objects.hpp | 3 --- .../golos/plugins/private_message/private_message_plugin.hpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index ed90bef7b6..8a905a375d 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -25,11 +25,8 @@ namespace golos { namespace plugins { namespace private_message { }; struct message_body { - fc::time_point thread_start; /// the sent_time of the original message, if any std::string subject; std::string body; - std::string json_meta; - flat_set cc; }; class message_object: diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index f8fe151e69..dbe7428952 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -59,7 +59,7 @@ namespace golos { namespace plugins { namespace private_message { FC_REFLECT( (golos::plugins::private_message::message_body), - (thread_start)(subject)(body)(json_meta)(cc)); + (subject)(body)); FC_REFLECT( (golos::plugins::private_message::message_object), From 47bed8185a45c8bd0b97b34c3d208c85632be108 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:49:15 +0700 Subject: [PATCH 102/250] Add send_private_message to cli_wallet. #805 --- .../wallet/include/golos/wallet/wallet.hpp | 17 ++- libraries/wallet/wallet.cpp | 112 +++++++++++++----- 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 6264214880..3c4de7345b 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1109,9 +1109,21 @@ namespace golos { namespace wallet { // Private message vector get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset); + const std::string& to, const std::string& newest, uint16_t limit, std::uint64_t offset); vector get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset); + const std::string& from, const std::string& newest, uint16_t limit, std::uint64_t offset); + + /** + * Send an encrypted private message from one account to other + * + * @param from account from which you send message + * @param to account to which you send message + * @param message to send + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction send_private_message( + const std::string& from, const std::string& to, const message_body& message, bool broadcast); message_body try_decrypt_message( const message_api_obj& mo ); }; @@ -1231,6 +1243,7 @@ FC_API( golos::wallet::wallet_api, (get_transaction) (get_inbox) (get_outbox) + (send_private_message) ) FC_REFLECT((golos::wallet::memo_data), (from)(to)(nonce)(check)(encrypted)) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 4bb00c3476..cf743a4d06 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2516,68 +2516,118 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->_remote_operation_history->get_transaction( id ); } - vector wallet_api::get_inbox(const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) { - FC_ASSERT( !is_locked() ); - vector result; + vector wallet_api::get_inbox( + const std::string& to, const std::string& newest_str, uint16_t limit, std::uint64_t offset + ) { + FC_ASSERT(!is_locked()); + std::vector result; + auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); auto remote_result = my->_remote_private_message->get_inbox(to, newest, limit, offset); - for( const auto& item : remote_result ) { - result.emplace_back( item ); - message_body tmp = try_decrypt_message( item ); + result.reserve(remote_result.size()); + for (const auto& item : remote_result) { + result.emplace_back(item); + message_body tmp = try_decrypt_message(item); result.back().message = std::move(tmp); } return result; } - vector wallet_api::get_outbox(const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) { - FC_ASSERT( !is_locked() ); - vector result; + vector wallet_api::get_outbox( + const std::string& from, const std::string& newest_str, uint16_t limit, std::uint64_t offset + ) { + FC_ASSERT(!is_locked()); + std::vector result; + auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); auto remote_result = my->_remote_private_message->get_outbox(from, newest, limit, offset); - for( const auto& item : remote_result ) { - result.emplace_back( item ); - message_body tmp = try_decrypt_message( item ); + result.reserve(remote_result.size()); + for (const auto& item : remote_result) { + result.emplace_back(item); + message_body tmp = try_decrypt_message(item); result.back().message = std::move(tmp); } return result; } - message_body wallet_api::try_decrypt_message( const message_api_obj& mo ) { + annotated_signed_transaction wallet_api::send_private_message( + const std::string& from, const std::string& to, const message_body& message, bool broadcast + ) { + auto from_account = get_account(from); + auto to_account = get_account(to); + auto shared_secret = my->get_private_key(from_account.memo_key).get_shared_secret(to_account.memo_key); + auto sent_time = fc::time_point::now().time_since_epoch().count(); + + fc::sha512::encoder enc; + fc::raw::pack(enc, sent_time); + fc::raw::pack(enc, shared_secret); + auto encrypt_key = enc.result(); + + auto msg_json = fc::json::to_string(message); + + private_message_operation op; + + op.from = from; + op.from_memo_key = from_account.memo_key; + op.to = to; + op.to_memo_key = to_account.memo_key; + op.sent_time = sent_time; + op.encrypted_message = fc::aes_encrypt(encrypt_key, std::vector(msg_json.begin(), msg_json.end())); + op.checksum = fc::sha256::hash(encrypt_key)._hash[0]; + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(from); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + + message_body wallet_api::try_decrypt_message(const message_api_obj& mo) { message_body result; fc::sha512 shared_secret; auto it = my->_keys.find(mo.from_memo_key); - if( it == my->_keys.end() ) - { + if (it == my->_keys.end()) { it = my->_keys.find(mo.to_memo_key); - if( it == my->_keys.end() ) - { + if (it == my->_keys.end()) { wlog( "unable to find keys" ); return result; } - auto priv_key = wif_to_key( it->second ); - if( !priv_key ) return result; - shared_secret = priv_key->get_shared_secret( mo.from_memo_key ); + auto priv_key = wif_to_key(it->second); + if (!priv_key) { + return result; + } + shared_secret = priv_key->get_shared_secret(mo.from_memo_key); } else { - auto priv_key = wif_to_key( it->second ); - if( !priv_key ) return result; - shared_secret = priv_key->get_shared_secret( mo.to_memo_key ); + auto priv_key = wif_to_key(it->second); + if (!priv_key) { + return result; + } + shared_secret = priv_key->get_shared_secret(mo.to_memo_key); } - fc::sha512::encoder enc; - fc::raw::pack( enc, mo.sent_time ); - fc::raw::pack( enc, shared_secret ); + fc::raw::pack(enc, mo.sent_time); + fc::raw::pack(enc, shared_secret); auto encrypt_key = enc.result(); - uint32_t check = fc::sha256::hash( encrypt_key )._hash[0]; + uint32_t check = fc::sha256::hash(encrypt_key)._hash[0]; - if( mo.checksum != check ) + if (mo.checksum != check) { return result; + } - auto decrypt_data = fc::aes_decrypt( encrypt_key, mo.encrypted_message ); + auto decrypt_data = fc::aes_decrypt(encrypt_key, mo.encrypted_message); + auto msg_json = std::string(decrypt_data.begin(), decrypt_data.end()); try { - return fc::raw::unpack( decrypt_data ); - } catch ( ... ) { + return fc::json::from_string(msg_json).as(); + } catch (...) { return result; } } From a84b67bda817dc65ad8143b76f80d7a9b3ffd036 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 12:49:35 +0700 Subject: [PATCH 103/250] Move message_body to wallet. #805 --- .../wallet/include/golos/wallet/wallet.hpp | 24 +++++++++++++++++++ libraries/wallet/wallet.cpp | 11 +++++---- .../private_message_objects.hpp | 15 ------------ .../private_message_plugin.hpp | 9 ------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 3c4de7345b..bc2ef4c747 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -44,6 +44,21 @@ namespace golos { namespace wallet { fc::optional min_delegation; }; + struct message_body { + std::string subject; + std::string body; + }; + + struct extended_message_object: public message_api_obj { + extended_message_object() = default; + + extended_message_object(const message_api_obj& o) + : message_api_obj(o) { + } + + message_body message; + }; + struct memo_data { static optional from_string( string str ) { @@ -1258,3 +1273,12 @@ FC_REFLECT((golos::wallet::optional_chain_props), (account_creation_fee)(maximum_block_size)(sbd_interest_rate) (create_account_min_golos_fee)(create_account_min_delegation) (create_account_delegation_time)(min_delegation)) + +FC_REFLECT( + (golos::wallet::message_body), + (subject)(body)); + +FC_REFLECT_DERIVED( + (golos::wallet::extended_message_object), + ((golos::plugins::private_message::message_api_obj)), + (message)); \ No newline at end of file diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index cf743a4d06..fe19ebf0c9 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2562,6 +2562,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st auto encrypt_key = enc.result(); auto msg_json = fc::json::to_string(message); + auto msg_data = std::vector(msg_json.begin(), msg_json.end()); private_message_operation op; @@ -2570,7 +2571,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.to = to; op.to_memo_key = to_account.memo_key; op.sent_time = sent_time; - op.encrypted_message = fc::aes_encrypt(encrypt_key, std::vector(msg_json.begin(), msg_json.end())); + op.encrypted_message = fc::aes_encrypt(encrypt_key, msg_data); op.checksum = fc::sha256::hash(encrypt_key)._hash[0]; private_message_plugin_operation pop = op; @@ -2596,7 +2597,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st if (it == my->_keys.end()) { it = my->_keys.find(mo.to_memo_key); if (it == my->_keys.end()) { - wlog( "unable to find keys" ); + wlog("unable to find keys"); return result; } auto priv_key = wif_to_key(it->second); @@ -2620,16 +2621,18 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st uint32_t check = fc::sha256::hash(encrypt_key)._hash[0]; if (mo.checksum != check) { + wlog("wrong checksum"); return result; } auto decrypt_data = fc::aes_decrypt(encrypt_key, mo.encrypted_message); auto msg_json = std::string(decrypt_data.begin(), decrypt_data.end()); try { - return fc::json::from_string(msg_json).as(); + result = fc::json::from_string(msg_json).as(); } catch (...) { - return result; + result.body = msg_json; } + return result; } annotated_signed_transaction wallet_api::follow( diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 8a905a375d..6ccc4f6091 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -24,11 +24,6 @@ namespace golos { namespace plugins { namespace private_message { message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) }; - struct message_body { - std::string subject; - std::string body; - }; - class message_object: public object { public: @@ -78,16 +73,6 @@ namespace golos { namespace plugins { namespace private_message { std::vector encrypted_message; }; - struct extended_message_object: public message_api_obj { - extended_message_object() = default; - - extended_message_object(const message_api_obj& o) - : message_api_obj(o) { - } - - message_body message; - }; - struct by_to_date; struct by_from_date; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index dbe7428952..3e733c96b6 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -57,10 +57,6 @@ namespace golos { namespace plugins { namespace private_message { } } } //golos::plugins::private_message -FC_REFLECT( - (golos::plugins::private_message::message_body), - (subject)(body)); - FC_REFLECT( (golos::plugins::private_message::message_object), (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); @@ -70,8 +66,3 @@ CHAINBASE_SET_INDEX_TYPE( FC_REFLECT( (golos::plugins::private_message::message_api_obj), (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); - -FC_REFLECT_DERIVED( - (golos::plugins::private_message::extended_message_object), - ((golos::plugins::private_message::message_api_obj)), - (message)); From a60b3cad441c79d123826820da3f65e7628701ab Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 15:19:54 +0700 Subject: [PATCH 104/250] Refactor errors: add macros to check missing object #790 --- libraries/chain/database.cpp | 6 ++++++ .../chain/include/golos/chain/database.hpp | 1 + .../include/golos/protocol/exceptions.hpp | 2 ++ tests/common/database_fixture.hpp | 17 +++++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index e4531b6ff2..8eb8270f61 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -598,6 +598,12 @@ namespace golos { namespace chain { return STEEMIT_CHAIN_ID; } + void database::throw_if_exists_limit_order(const account_name_type& owner, uint32_t id) const { + if (nullptr != find_limit_order(owner, id)) { + GOLOS_THROW_OBJECT_ALREADY_EXIST("limit_order", fc::mutable_variant_object()("account",owner)("order_id",id)); + } + } + const witness_object &database::get_witness(const account_name_type &name) const { try { return get(name); diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index f16d2c500b..d272b6b115 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -151,6 +151,7 @@ namespace golos { namespace chain { chain_id_type get_chain_id() const; + void throw_if_exists_limit_order(const account_name_type &account, uint32_t id) const; const witness_object &get_witness(const account_name_type &name) const; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index fe7cbb7acc..e41a107f0a 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -109,6 +109,8 @@ FC_THROW_EXCEPTION(golos::object_already_exist, "Object ${type} with id \"${id}\" already exists", \ ("type",type)("id",id) __VA_ARGS__) +#define GOLOS_CHECK_OBJECT_MISSING(DB, OBJ, ...) \ + DB.throw_if_exists_##OBJ(__VA_ARGS__) #define GOLOS_THROW_INTERNAL_ERROR(MSG, ...) \ FC_THROW_EXCEPTION(golos::internal_error, MSG, __VA_ARGS__) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 4c849283de..d8fea2db5f 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -184,6 +184,23 @@ struct ErrorValidator { } }; +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, + const std::string& type, const std::string& id) { + BOOST_CHECK_EQUAL(name, "object_already_exist"); + BOOST_CHECK_EQUAL(props["type"].get_string(), type); + BOOST_CHECK_EQUAL(props["id"].get_string(), id); + } + + void validate(const std::string& name, const fc::variant& props, + const std::string& type, const fc::variant_object& id) { + BOOST_CHECK_EQUAL(name, "object_already_exist"); + BOOST_CHECK_EQUAL(props["type"].get_string(), type); + BOOST_CHECK_EQUAL(props["id"].get_object(), id); + } +}; + template<> struct ErrorValidator { void validate(const std::string& name, const fc::variant& props, From 95cd4c6eae844066c1a8873cba9dab6b30a772cf Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 15:29:44 +0700 Subject: [PATCH 105/250] Refactor errors: fix common macros #790 --- .../golos/protocol/validate_helper.hpp | 18 ++++++------- libraries/protocol/steem_operations.cpp | 6 ++--- tests/common/helpers.hpp | 26 +++---------------- tests/tests/proposal_tests.cpp | 3 ++- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/libraries/protocol/include/golos/protocol/validate_helper.hpp b/libraries/protocol/include/golos/protocol/validate_helper.hpp index cd98373ec4..99ee2f36f1 100644 --- a/libraries/protocol/include/golos/protocol/validate_helper.hpp +++ b/libraries/protocol/include/golos/protocol/validate_helper.hpp @@ -30,12 +30,12 @@ // compare field with value -#define GOLOS_CHECK_FIELD_EQ(F, X) GOLOS_CHECK_FIELD_I(F, ==, X) -#define GOLOS_CHECK_FIELD_GT(F, X) GOLOS_CHECK_FIELD_I(F, > , X) -#define GOLOS_CHECK_FIELD_LT(F, X) GOLOS_CHECK_FIELD_I(F, < , X) -#define GOLOS_CHECK_FIELD_GE(F, X) GOLOS_CHECK_FIELD_I(F, >=, X) -#define GOLOS_CHECK_FIELD_LE(F, X) GOLOS_CHECK_FIELD_I(F, <=, X) -#define GOLOS_CHECK_FIELD_LEGE(F, L, H) \ +#define GOLOS_CHECK_VALUE_EQ(F, X) GOLOS_CHECK_VALUE_I(F, ==, X) +#define GOLOS_CHECK_VALUE_GT(F, X) GOLOS_CHECK_VALUE_I(F, > , X) +#define GOLOS_CHECK_VALUE_LT(F, X) GOLOS_CHECK_VALUE_I(F, < , X) +#define GOLOS_CHECK_VALUE_GE(F, X) GOLOS_CHECK_VALUE_I(F, >=, X) +#define GOLOS_CHECK_VALUE_LE(F, X) GOLOS_CHECK_VALUE_I(F, <=, X) +#define GOLOS_CHECK_VALUE_LEGE(F, L, H) \ GOLOS_CHECK_VALUE(L <= F && F <= H , MUST_BE(F, "between " FC_STRINGIZE(L) " and" FC_STRINGIZE(H))) // check asset type @@ -57,8 +57,8 @@ //------------------------------------------------------------- // fields -#define GOLOS_CHECK_FIELD_I(F, OP, X) GOLOS_CHECK_FIELD_II(F, OP, X, F) -#define GOLOS_CHECK_FIELD_II(F, OP, X, N) GOLOS_CHECK_VALUE(F OP X, MUST_BE(N, "" #OP FC_STRINGIZE(X))) +#define GOLOS_CHECK_VALUE_I(F, OP, X) GOLOS_CHECK_VALUE_II(F, OP, X, F) +#define GOLOS_CHECK_VALUE_II(F, OP, X, N) GOLOS_CHECK_VALUE(F OP X, MUST_BE(N, "" #OP FC_STRINGIZE(X))) // asset type #define GOLOS_CHECK_ASSET_TYPE_I(X, SYMBOL, SNAME) GOLOS_CHECK_VALUE(X.symbol == SYMBOL, MUST_BE(X, SNAME)) @@ -66,7 +66,7 @@ // asset value #define GOLOS_CHECK_ASSET_VAL(X, OP, V, N) { \ GOLOS_CHECK_ASSET_TYPE(X, N); \ - GOLOS_CHECK_FIELD_II(X.amount, OP, V, X); \ + GOLOS_CHECK_VALUE_II(X.amount, OP, V, X); \ } // utils diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 8d7226820e..594f622824 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -212,8 +212,8 @@ namespace golos { namespace protocol { void chain_properties_17::validate() const { GOLOS_CHECK_ASSET_GE(account_creation_fee, GOLOS, STEEMIT_MIN_ACCOUNT_CREATION_FEE); - GOLOS_CHECK_FIELD_GE(maximum_block_size, STEEMIT_MIN_BLOCK_SIZE_LIMIT); - GOLOS_CHECK_FIELD_LEGE(sbd_interest_rate, 0, STEEMIT_100_PERCENT); + GOLOS_CHECK_VALUE_GE(maximum_block_size, STEEMIT_MIN_BLOCK_SIZE_LIMIT); + GOLOS_CHECK_VALUE_LEGE(sbd_interest_rate, 0, STEEMIT_100_PERCENT); } void chain_properties_18::validate() const { @@ -221,7 +221,7 @@ namespace golos { namespace protocol { GOLOS_CHECK_ASSET_GT0(create_account_min_golos_fee, GOLOS); GOLOS_CHECK_ASSET_GT0(create_account_min_delegation, GOLOS); GOLOS_CHECK_ASSET_GT0(min_delegation, GOLOS); - GOLOS_CHECK_FIELD_GT(create_account_delegation_time, + GOLOS_CHECK_VALUE_GT(create_account_delegation_time, (GOLOS_CREATE_ACCOUNT_DELEGATION_TIME).to_seconds() / 2); } diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index e85ec48e9c..198fd7fd58 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -15,26 +15,16 @@ /// change operation parameter value and check it's invalid (+restore param) #define CHECK_PARAM_INVALID(OP, N, V) \ - CHECK_PARAM_VALIDATION_FAIL(OP, N, V, invalid_parameter, #N) + CHECK_PARAM_VALIDATION_FAIL(OP, N, V, CHECK_ERROR(invalid_parameter, #N)) /// change operation parameter value and check it fails with logic_exceprion (+restore param) #define CHECK_PARAM_INVALID_LOGIC(OP, N, V, EX) \ - CHECK_PARAM_VALIDATION_FAIL(OP, N, V, logic_exception, logic_exception:: EX) + CHECK_PARAM_VALIDATION_FAIL(OP, N, V, CHECK_ERROR(logic_exception, logic_exception:: EX)) /// same as previous but with configurable CHECK_ERROR parameters -#define CHECK_PARAM_VALIDATION_FAIL(OP, N, V, EX, EV) \ +#define CHECK_PARAM_VALIDATION_FAIL(OP, N, V, VALIDATOR) \ CHECK_PARAM_VALID_I(OP, N, V, \ - GOLOS_CHECK_ERROR_PROPS(OP.validate(), CHECK_ERROR(EX, EV))) - - -// Push tx -#define GOLOS_TEST_TX_THROW(E, KEY, SETUP) GOLOS_TEST_TX_I(SETUP, KEY, GOLOS_CHECK_PUSH_TX_THROW(E)) -#define GOLOS_TEST_TX_NO_THROW(KEY, SETUP) GOLOS_TEST_TX_I(SETUP, KEY, GOLOS_CHECK_PUSH_TX_NO_THROW) -#define GOLOS_TEST_TX_I(SETUP, KEY, PUSH) \ - tx.clear(); \ - SETUP; \ - tx.sign(KEY, db->get_chain_id()); \ - PUSH; + GOLOS_CHECK_ERROR_PROPS(OP.validate(), VALIDATOR)) // Check operation authorities @@ -64,14 +54,6 @@ } -// push tx -#define GOLOS_CHECK_PUSH_TX_NO_THROW GOLOS_CHECK_PUSH_TX_NO_THROW_F(0) -#define GOLOS_CHECK_PUSH_TX_NO_THROW_F(F) BOOST_CHECK_NO_THROW(db->push_transaction(tx, F)) -#define GOLOS_CHECK_PUSH_TX_THROW(E) GOLOS_CHECK_PUSH_TX_THROW_F(0, E) -#define GOLOS_CHECK_PUSH_TX_THROW_F(F, E) \ - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, F), CHECK_ERROR(E, 0)) - - // boost::container << //------------------------------------------------------------- namespace boost { namespace container { diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index 5538d35127..8cffd9877b 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -80,7 +80,8 @@ BOOST_AUTO_TEST_CASE(proposal_create_validate) { try { t2.amount = ASSET_GESTS(1.0); ops.push_back(operation_wrapper(t2)); // validation fails inside internal transaction, so error contains "amount" field - CHECK_PARAM_VALIDATION_FAIL(op, proposed_operations, ops, invalid_parameter, "amount"); + CHECK_PARAM_VALIDATION_FAIL(op, proposed_operations, ops, + CHECK_ERROR(invalid_parameter, "amount")); } FC_LOG_AND_RETHROW() } From 8ed66f532a94829b1fecbafbd73b984c59408d13 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 17:32:13 +0700 Subject: [PATCH 106/250] Refactor errors: limit_order_create_operation #790 --- libraries/chain/steem_evaluator.cpp | 16 +- libraries/protocol/asset.cpp | 7 +- .../include/golos/protocol/exceptions.hpp | 14 +- libraries/protocol/steem_operations.cpp | 9 +- libraries/protocol/transaction.cpp | 13 +- tests/common/database_fixture.cpp | 5 + tests/common/database_fixture.hpp | 13 + tests/tests/operation_tests.cpp | 248 ++++++++++-------- 8 files changed, 204 insertions(+), 121 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 94c7d0b2bd..654ed1dec2 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1876,16 +1876,19 @@ namespace golos { namespace chain { void limit_order_create_evaluator::do_apply(const limit_order_create_operation &o) { database &_db = db(); - FC_ASSERT(o.expiration > - _db.head_block_time(), "Limit order has to expire after head block time."); - const auto &owner = _db.get_account(o.owner); + GOLOS_CHECK_OP_PARAM(o, expiration, { + GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), + "Limit order has to expire after head block time."); + }); - FC_ASSERT(_db.get_balance(owner, o.amount_to_sell.symbol) >= - o.amount_to_sell, "Account does not have sufficient funds for limit order."); + const auto &owner = _db.get_account(o.owner); + GOLOS_CHECK_BALANCE(owner, MAIN_BALANCE, o.amount_to_sell); _db.adjust_balance(owner, -o.amount_to_sell); + GOLOS_CHECK_OBJECT_MISSING(_db, limit_order, o.owner, o.orderid); + const auto &order = _db.create([&](limit_order_object &obj) { obj.created = _db.head_block_time(); obj.seller = o.owner; @@ -1898,7 +1901,8 @@ namespace golos { namespace chain { bool filled = _db.apply_order(order); if (o.fill_or_kill) - FC_ASSERT(filled, "Cancelling order because it was not filled."); + GOLOS_CHECK_LOGIC(filled, logic_exception::cancelling_not_filled_order, + "Cancelling order because it was not filled."); } void limit_order_create2_evaluator::do_apply(const limit_order_create2_operation &o) { diff --git a/libraries/protocol/asset.cpp b/libraries/protocol/asset.cpp index 607c947c96..6dec81a0c8 100644 --- a/libraries/protocol/asset.cpp +++ b/libraries/protocol/asset.cpp @@ -1,4 +1,5 @@ #include +#include /* @@ -194,9 +195,9 @@ namespace golos { void price::validate() const { try { - FC_ASSERT(base.amount > share_type(0)); - FC_ASSERT(quote.amount > share_type(0)); - FC_ASSERT(base.symbol_name() != quote.symbol_name()); + GOLOS_CHECK_VALUE(base.amount > share_type(0), "Amount of base must be positive"); + GOLOS_CHECK_VALUE(quote.amount > share_type(0), "Amount of quote must be positive"); + GOLOS_CHECK_VALUE(base.symbol_name() != quote.symbol_name(), "Symbols of base and quote must be different"); } FC_CAPTURE_AND_RETHROW((base)(quote)) } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index e41a107f0a..d14fb5df24 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -202,8 +202,6 @@ namespace golos { insufficient_fee_for_powerdown_registered_account, operation_would_not_change_vesting_withdraw_rate, - - //account_create_with_delegation not_enough_delegation, @@ -217,7 +215,11 @@ namespace golos { non_existing_approval, already_existing_approval, - proposal_delete_not_allowed + proposal_delete_not_allowed, + + // limit order + limit_order_must_be_for_golos_gbg_market, + cancelling_not_filled_order, }; }; @@ -346,8 +348,6 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) - - //account_create_with_delegation (not_enough_delegation) @@ -362,6 +362,10 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (already_existing_approval) (proposal_delete_not_allowed) + + // limit order + (limit_order_must_be_for_golos_gbg_market) + (cancelling_not_filled_order) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 594f622824..db4d1481d4 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -422,13 +422,16 @@ namespace golos { namespace protocol { } void limit_order_create_operation::validate() const { - validate_account_name(owner); - FC_ASSERT((is_asset_type(amount_to_sell, STEEM_SYMBOL) && + GOLOS_CHECK_PARAM(owner, validate_account_name(owner)); + GOLOS_CHECK_LOGIC((is_asset_type(amount_to_sell, STEEM_SYMBOL) && is_asset_type(min_to_receive, SBD_SYMBOL)) || (is_asset_type(amount_to_sell, SBD_SYMBOL) && is_asset_type(min_to_receive, STEEM_SYMBOL)), + logic_exception::limit_order_must_be_for_golos_gbg_market, "Limit order must be for the GOLOS:GBG market"); - (amount_to_sell / min_to_receive).validate(); + + auto price = (amount_to_sell / min_to_receive); + GOLOS_CHECK_PARAM(price, price.validate()); } void limit_order_create2_operation::validate() const { diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index 5b9a75f1f5..6799e4f107 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -30,8 +30,19 @@ namespace golos { void transaction::validate() const { FC_ASSERT(operations.size() > 0, "A transaction must have at least one operation", ("trx", *this)); + + uint32_t _current_op_in_trx = 0; for (const auto &op : operations) { - operation_validate(op); + try { + operation_validate(op); + ++_current_op_in_trx; + } catch (const fc::exception& e) { + FC_THROW_EXCEPTION(tx_invalid_operation, + "Invalid operation ${index} in transaction: ${errmsg}", + ("index", _current_op_in_trx) + ("errmsg", e.to_string()) + ("error", e)); + } } } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 5839b61c25..2a8d82a3e1 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -86,6 +86,11 @@ std::ostream& operator<<(std::ostream& out, const asset& v) { return out; } +std::ostream& operator<<(std::ostream& out, const price& v) { + out << v.base << '/' << v.quote << '=' << v.to_real(); + return out; +} + } } // namespace golos::protocol diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index d8fea2db5f..44372d5b48 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -341,9 +341,22 @@ std::ostream& operator<<(std::ostream& out, const object_id &v) { } // namespace chainbase + +namespace std { + +template +std::ostream& operator<<(std::ostream& out, const std::pair &v) { + out << "<" << v.first << ":" << v.second << ">"; + return out; +} + +} // namespace std + + namespace golos { namespace protocol { std::ostream& operator<<(std::ostream& out, const asset& v); +std::ostream& operator<<(std::ostream& out, const price& v); } } // namespace golos::protocol diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 2b89e8d059..05d1a06961 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -37,6 +37,11 @@ fc::variant_object make_comment_id(const std::string& author, const std::string& return fc::variant_object(res); } +fc::variant_object make_limit_order_id(const std::string& author, uint32_t orderid) { + auto res = fc::mutable_variant_object()("account",author)("order_id",orderid); + return fc::variant_object(res); +} + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) @@ -2661,6 +2666,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(limit_order_create_validate) { try { BOOST_TEST_MESSAGE("Testing: limit_order_create_validate"); + limit_order_create_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.owner = "alice"; + op.amount_to_sell = ASSET("1.000 GOLOS"); + op.min_to_receive = ASSET("1.000 GBG"); + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'owner' is empty"); + CHECK_PARAM_INVALID(op, owner, ""); + + BOOST_TEST_MESSAGE("--- failed when 'amount_to_sell' is negative"); + CHECK_PARAM_VALIDATION_FAIL(op, amount_to_sell, ASSET_GOLOS(-1), + CHECK_ERROR(invalid_parameter, "price")); + + BOOST_TEST_MESSAGE("--- failed when symbol not GBG or GOLOS"); + CHECK_PARAM_INVALID_LOGIC(op, min_to_receive, ASSET_GESTS(1), + limit_order_must_be_for_golos_gbg_market); + + BOOST_TEST_MESSAGE("--- failed when 'min_to_receive' is negative"); + op.amount_to_sell = ASSET("1.000 GOLOS"); + op.min_to_receive = ASSET("-1.000 GBG"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "price")); } FC_LOG_AND_RETHROW() } @@ -2683,7 +2712,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); tx.sign(alice_private_key, db->get_chain_id()); @@ -2691,18 +2721,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -2734,13 +2767,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "bob", "fund", "10.000 GOLOS"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("bob", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(bob.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == ASSET("100.0000 GBG").amount.value); + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("100.0000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when amount to receive is 0"); @@ -2751,13 +2786,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "price"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("1000.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("1000.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when amount to sell is 0"); @@ -2768,13 +2805,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "price"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("1000.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("1000.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test success creating limit order that will not be filled"); @@ -2785,19 +2824,19 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto limit_order = limit_order_idx.find(std::make_tuple("alice", op.orderid)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == op.owner); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == op.amount_to_sell.amount); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, op.owner); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, op.amount_to_sell.amount); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(op.amount_to_sell / op.min_to_receive)); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure creating limit order with duplicate id"); @@ -2807,18 +2846,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "limit_order", make_limit_order_id("alice", 1)))); limit_order = limit_order_idx.find(std::make_tuple("alice", op.orderid)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == op.owner); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == 10000); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, op.owner); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, 10000); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("10.000 GOLOS"), op.min_to_receive)); - BOOST_REQUIRE(limit_order->get_market() == std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test sucess killing an order that will not be filled"); @@ -2829,13 +2870,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cancelling_not_filled_order))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test having a partial match to limit order"); @@ -2851,38 +2894,38 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto recent_ops = get_last_operations(1); auto fill_order_op = recent_ops[0].get(); limit_order = limit_order_idx.find(std::make_tuple("alice", 1)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "alice"); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == 5000); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, "alice"); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, 5000); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("10.000 GOLOS"), ASSET("15.000 GBG"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("bob", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("7.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("992.500 GBG").amount.value); - BOOST_REQUIRE(fill_order_op.open_owner == "alice"); - BOOST_REQUIRE(fill_order_op.open_orderid == 1); - BOOST_REQUIRE(fill_order_op.open_pays.amount.value == + BOOST_CHECK_EQUAL(fill_order_op.open_owner, "alice"); + BOOST_CHECK_EQUAL(fill_order_op.open_orderid, 1); + BOOST_CHECK_EQUAL(fill_order_op.open_pays.amount.value, ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(fill_order_op.current_owner == "bob"); - BOOST_REQUIRE(fill_order_op.current_orderid == 1); - BOOST_REQUIRE(fill_order_op.current_pays.amount.value == + BOOST_CHECK_EQUAL(fill_order_op.current_owner, "bob"); + BOOST_CHECK_EQUAL(fill_order_op.current_orderid, 1); + BOOST_CHECK_EQUAL(fill_order_op.current_pays.amount.value, ASSET("7.500 GBG").amount.value); validate_database(); @@ -2894,26 +2937,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("bob", 1)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "bob"); - BOOST_REQUIRE(limit_order->orderid == 1); - BOOST_REQUIRE(limit_order->for_sale.value == 7500); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, "bob"); + BOOST_CHECK_EQUAL(limit_order->orderid, 1); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 7500); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("15.000 GBG"), ASSET("10.000 GOLOS"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 1)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 1)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("15.000 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("10.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("977.500 GBG").amount.value); validate_database(); @@ -2927,19 +2970,19 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + GOLOS_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 3)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 3)) == limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("bob", 1)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("bob", 1)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("985.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("22.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("15.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("977.500 GBG").amount.value); validate_database(); @@ -2953,7 +2996,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); op.owner = "bob"; op.orderid = 4; @@ -2963,26 +3006,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("bob", 4)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 4)) == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 4)) == limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "bob"); - BOOST_REQUIRE(limit_order->orderid == 4); - BOOST_REQUIRE(limit_order->for_sale.value == 1000); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK_EQUAL(limit_order->seller, "bob"); + BOOST_CHECK_EQUAL(limit_order->orderid, 4); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 1000); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("12.000 GBG"), ASSET("10.000 GOLOS"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("975.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("33.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("25.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("965.500 GBG").amount.value); validate_database(); @@ -2993,7 +3036,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(can); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test filling limit order with better order when partial order is worse."); @@ -3005,7 +3048,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); op.owner = "bob"; op.orderid = 5; @@ -3015,26 +3058,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("alice", 5)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("bob", 5)) == - limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "alice"); - BOOST_REQUIRE(limit_order->orderid == 5); - BOOST_REQUIRE(limit_order->for_sale.value == 9091); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK(limit_order_idx.find(std::make_tuple("bob", 5)) == limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, "alice"); + BOOST_CHECK_EQUAL(limit_order->orderid, 5); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 9091); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("20.000 GOLOS"), ASSET("22.000 GBG"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("955.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("45.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("35.909 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("954.500 GBG").amount.value); validate_database(); } From f37b389e29f5bb34de3cf66f843536dd4a9f3339 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 18 Jul 2018 16:22:13 +0700 Subject: [PATCH 107/250] Refactor errors: limit_order_cancel_operation #790 --- libraries/protocol/steem_operations.cpp | 2 +- tests/tests/operation_tests.cpp | 43 +++++++++++++++++-------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index db4d1481d4..9d431fa5ea 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -451,7 +451,7 @@ namespace golos { namespace protocol { } void limit_order_cancel_operation::validate() const { - validate_account_name(owner); + GOLOS_CHECK_PARAM(owner, validate_account_name(owner)); } void convert_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 05d1a06961..f7d5af4dcc 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -3473,6 +3473,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(limit_order_cancel_validate) { try { BOOST_TEST_MESSAGE("Testing: limit_order_cancel_validate"); + limit_order_cancel_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.owner = "alice"; + op.orderid = 1; + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failure when owner is empty"); + CHECK_PARAM_INVALID(op, owner, ""); + + validate_database(); } FC_LOG_AND_RETHROW() } @@ -3495,7 +3506,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration( db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order_cancel_operation op; op.owner = "alice"; @@ -3506,26 +3517,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -3552,7 +3567,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration( db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "limit_order", make_limit_order_id("alice", 5)))); BOOST_TEST_MESSAGE("--- Test cancel order"); @@ -3565,22 +3582,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(create); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 5)) != + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 5)) != limit_order_idx.end()); tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 5)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 5)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("10.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); } FC_LOG_AND_RETHROW() From d9ba96ae45a47ed4f7ada5de37afb0c651c5c2aa Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 18 Jul 2018 20:09:35 +0700 Subject: [PATCH 108/250] Refactor errors: limit_order_create2_operation #790 --- libraries/chain/steem_evaluator.cpp | 15 +- libraries/protocol/steem_operations.cpp | 17 +- tests/tests/operation_tests.cpp | 259 ++++++++++++++---------- 3 files changed, 175 insertions(+), 116 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 654ed1dec2..96ba331233 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1907,16 +1907,18 @@ namespace golos { namespace chain { void limit_order_create2_evaluator::do_apply(const limit_order_create2_operation &o) { database &_db = db(); - FC_ASSERT(o.expiration > - _db.head_block_time(), "Limit order has to expire after head block time."); + GOLOS_CHECK_OP_PARAM(o, expiration, { + GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), + "Limit order has to expire after head block time."); + }); const auto &owner = _db.get_account(o.owner); - FC_ASSERT(_db.get_balance(owner, o.amount_to_sell.symbol) >= - o.amount_to_sell, "Account does not have sufficient funds for limit order."); - + GOLOS_CHECK_BALANCE(owner, MAIN_BALANCE, o.amount_to_sell); _db.adjust_balance(owner, -o.amount_to_sell); + GOLOS_CHECK_OBJECT_MISSING(_db, limit_order, o.owner, o.orderid); + const auto &order = _db.create([&](limit_order_object &obj) { obj.created = _db.head_block_time(); obj.seller = o.owner; @@ -1929,7 +1931,8 @@ namespace golos { namespace chain { bool filled = _db.apply_order(order); if (o.fill_or_kill) - FC_ASSERT(filled, "Cancelling order because it was not filled."); + GOLOS_CHECK_LOGIC(filled, logic_exception::cancelling_not_filled_order, + "Cancelling order because it was not filled."); } void limit_order_cancel_evaluator::do_apply(const limit_order_cancel_operation &o) { diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 9d431fa5ea..bb73ad765b 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -435,19 +435,22 @@ namespace golos { namespace protocol { } void limit_order_create2_operation::validate() const { - validate_account_name(owner); - FC_ASSERT(amount_to_sell.symbol == - exchange_rate.base.symbol, "Sell asset must be the base of the price"); - exchange_rate.validate(); + GOLOS_CHECK_PARAM(owner, validate_account_name(owner)); + GOLOS_CHECK_PARAM(exchange_rate, exchange_rate.validate()); - FC_ASSERT((is_asset_type(amount_to_sell, STEEM_SYMBOL) && + GOLOS_CHECK_LOGIC((is_asset_type(amount_to_sell, STEEM_SYMBOL) && is_asset_type(exchange_rate.quote, SBD_SYMBOL)) || (is_asset_type(amount_to_sell, SBD_SYMBOL) && is_asset_type(exchange_rate.quote, STEEM_SYMBOL)), + logic_exception::limit_order_must_be_for_golos_gbg_market, "Limit order must be for the GOLOS:GBG market"); - FC_ASSERT((amount_to_sell * exchange_rate).amount > - 0, "Amount to sell cannot round to 0 when traded"); + GOLOS_CHECK_PARAM(amount_to_sell, { + GOLOS_CHECK_VALUE(amount_to_sell.symbol == exchange_rate.base.symbol, + "Sell asset must be the base of the price"); + GOLOS_CHECK_VALUE((amount_to_sell * exchange_rate).amount > 0, + "Amount to sell cannot round to 0 when traded"); + }); } void limit_order_cancel_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index f7d5af4dcc..b97da23823 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -3083,6 +3083,45 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(limit_order_create2_validate) { + try { + BOOST_TEST_MESSAGE("Testing: limit_order_create2_validate"); + limit_order_create2_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.owner = "alice"; + op.amount_to_sell = ASSET("1.000 GOLOS"); + op.exchange_rate = price(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failed when 'owner' is empty"); + op.owner = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "owner")); + + BOOST_TEST_MESSAGE("--- failed when 'exchange_rate' is invalid"); + op.owner = "alice"; + op.exchange_rate = price(ASSET("1.000 GOLOS"), ASSET("1.000 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "exchange_rate")); + + BOOST_TEST_MESSAGE("--- failed when symbol not GBG or GOLOS"); + op.amount_to_sell = ASSET("1.000000 GESTS"); + op.exchange_rate = price(ASSET("1.000000 GESTS"), ASSET("1.000 GBG")); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(logic_exception, logic_exception::limit_order_must_be_for_golos_gbg_market)); + + BOOST_TEST_MESSAGE("--- failed when zero amount to sell"); + op.amount_to_sell = ASSET("0.000 GOLOS"); + op.exchange_rate = price(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "amount_to_sell")); + + validate_database(); + } + FC_LOG_AND_RETHROW() + } + BOOST_AUTO_TEST_CASE(limit_order_create2_authorities) { try { BOOST_TEST_MESSAGE("Testing: limit_order_create2_authorities"); @@ -3101,26 +3140,30 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -3153,14 +3196,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration( db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "bob", "fund", "10.000 GOLOS"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("bob", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("100.0000 GBG").amount.value); validate_database(); @@ -3172,14 +3217,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "exchange_rate"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("1000.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); @@ -3191,14 +3238,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "amount_to_sell"))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("1000.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); @@ -3210,19 +3259,19 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto limit_order = limit_order_idx.find(std::make_tuple("alice", op.orderid)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == op.owner); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == op.amount_to_sell.amount); - BOOST_REQUIRE(limit_order->sell_price == op.exchange_rate); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, op.owner); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, op.amount_to_sell.amount); + BOOST_CHECK_EQUAL(limit_order->sell_price, op.exchange_rate); + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); @@ -3233,19 +3282,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "limit_order", make_limit_order_id("alice", 1)))); limit_order = limit_order_idx.find(std::make_tuple("alice", op.orderid)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == op.owner); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == 10000); - BOOST_REQUIRE(limit_order->sell_price == op.exchange_rate); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, op.owner); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, 10000); + BOOST_CHECK_EQUAL(limit_order->sell_price, op.exchange_rate); + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); @@ -3257,14 +3308,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cancelling_not_filled_order))); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("alice", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); validate_database(); @@ -3281,38 +3334,38 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); auto recent_ops = get_last_operations(1); auto fill_order_op = recent_ops[0].get(); limit_order = limit_order_idx.find(std::make_tuple("alice", 1)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "alice"); - BOOST_REQUIRE(limit_order->orderid == op.orderid); - BOOST_REQUIRE(limit_order->for_sale == 5000); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, "alice"); + BOOST_CHECK_EQUAL(limit_order->orderid, op.orderid); + BOOST_CHECK_EQUAL(limit_order->for_sale, 5000); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("2.000 GOLOS"), ASSET("3.000 GBG"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE( + BOOST_CHECK( limit_order_idx.find(std::make_tuple("bob", op.orderid)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("7.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("992.500 GBG").amount.value); - BOOST_REQUIRE(fill_order_op.open_owner == "alice"); - BOOST_REQUIRE(fill_order_op.open_orderid == 1); - BOOST_REQUIRE(fill_order_op.open_pays.amount.value == + BOOST_CHECK_EQUAL(fill_order_op.open_owner, "alice"); + BOOST_CHECK_EQUAL(fill_order_op.open_orderid, 1); + BOOST_CHECK_EQUAL(fill_order_op.open_pays.amount.value, ASSET("5.000 GOLOS").amount.value); - BOOST_REQUIRE(fill_order_op.current_owner == "bob"); - BOOST_REQUIRE(fill_order_op.current_orderid == 1); - BOOST_REQUIRE(fill_order_op.current_pays.amount.value == + BOOST_CHECK_EQUAL(fill_order_op.current_owner, "bob"); + BOOST_CHECK_EQUAL(fill_order_op.current_orderid, 1); + BOOST_CHECK_EQUAL(fill_order_op.current_pays.amount.value, ASSET("7.500 GBG").amount.value); validate_database(); @@ -3324,26 +3377,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("bob", 1)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "bob"); - BOOST_REQUIRE(limit_order->orderid == 1); - BOOST_REQUIRE(limit_order->for_sale.value == 7500); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK_EQUAL(limit_order->seller, "bob"); + BOOST_CHECK_EQUAL(limit_order->orderid, 1); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 7500); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("3.000 GBG"), ASSET("2.000 GOLOS"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 1)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 1)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("990.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("15.000 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("10.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("977.500 GBG").amount.value); validate_database(); @@ -3357,19 +3410,19 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 3)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 3)) == limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("bob", 1)) == + BOOST_CHECK(limit_order_idx.find(std::make_tuple("bob", 1)) == limit_order_idx.end()); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("985.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("22.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("15.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("977.500 GBG").amount.value); validate_database(); @@ -3383,7 +3436,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); op.owner = "bob"; op.orderid = 4; @@ -3393,25 +3446,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("bob", 4)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("alice", 4)) == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK(limit_order_idx.find(std::make_tuple("alice", 4)) == limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "bob"); - BOOST_REQUIRE(limit_order->orderid == 4); - BOOST_REQUIRE(limit_order->for_sale.value == 1000); - BOOST_REQUIRE(limit_order->sell_price == op.exchange_rate); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->seller, "bob"); + BOOST_CHECK_EQUAL(limit_order->orderid, 4); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 1000); + BOOST_CHECK_EQUAL(limit_order->sell_price, op.exchange_rate); + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("975.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("33.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("25.000 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("965.500 GBG").amount.value); validate_database(); @@ -3422,7 +3475,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(can); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test filling limit order with better order when partial order is worse."); @@ -3434,7 +3487,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); op.owner = "bob"; op.orderid = 5; @@ -3444,26 +3497,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); limit_order = limit_order_idx.find(std::make_tuple("alice", 5)); - BOOST_REQUIRE(limit_order != limit_order_idx.end()); - BOOST_REQUIRE(limit_order_idx.find(std::make_tuple("bob", 5)) == + BOOST_CHECK(limit_order != limit_order_idx.end()); + BOOST_CHECK(limit_order_idx.find(std::make_tuple("bob", 5)) == limit_order_idx.end()); - BOOST_REQUIRE(limit_order->seller == "alice"); - BOOST_REQUIRE(limit_order->orderid == 5); - BOOST_REQUIRE(limit_order->for_sale.value == 9091); - BOOST_REQUIRE(limit_order->sell_price == + BOOST_CHECK_EQUAL(limit_order->seller, "alice"); + BOOST_CHECK_EQUAL(limit_order->orderid, 5); + BOOST_CHECK_EQUAL(limit_order->for_sale.value, 9091); + BOOST_CHECK_EQUAL(limit_order->sell_price, price(ASSET("1.000 GOLOS"), ASSET("1.100 GBG"))); - BOOST_REQUIRE(limit_order->get_market() == + BOOST_CHECK_EQUAL(limit_order->get_market(), std::make_pair(SBD_SYMBOL, STEEM_SYMBOL)); - BOOST_REQUIRE(alice.balance.amount.value == + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("955.000 GOLOS").amount.value); - BOOST_REQUIRE(alice.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(alice.sbd_balance.amount.value, ASSET("45.500 GBG").amount.value); - BOOST_REQUIRE(bob.balance.amount.value == + BOOST_CHECK_EQUAL(bob.balance.amount.value, ASSET("35.909 GOLOS").amount.value); - BOOST_REQUIRE(bob.sbd_balance.amount.value == + BOOST_CHECK_EQUAL(bob.sbd_balance.amount.value, ASSET("954.500 GBG").amount.value); validate_database(); } From f8f5d048999589cc660f8fbed3dd02102acca301 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 10:05:01 +0700 Subject: [PATCH 109/250] Refactor errors: feed_publish_operation #790 --- .../include/golos/protocol/exceptions.hpp | 6 +++ libraries/protocol/steem_operations.cpp | 7 +-- tests/tests/operation_tests.cpp | 49 ++++++++++++++----- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index d14fb5df24..6fb320c384 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -220,6 +220,9 @@ namespace golos { // limit order limit_order_must_be_for_golos_gbg_market, cancelling_not_filled_order, + + // feed_publish_operation + price_feed_must_be_for_golos_gbg_market, }; }; @@ -366,6 +369,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // limit order (limit_order_must_be_for_golos_gbg_market) (cancelling_not_filled_order) + + // feed_publis_operation + (price_feed_must_be_for_golos_gbg_market) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index bb73ad765b..734e3c66a5 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -412,13 +412,14 @@ namespace golos { namespace protocol { } void feed_publish_operation::validate() const { - validate_account_name(publisher); - FC_ASSERT((is_asset_type(exchange_rate.base, STEEM_SYMBOL) && + GOLOS_CHECK_PARAM(publisher, validate_account_name(publisher)); + GOLOS_CHECK_LOGIC((is_asset_type(exchange_rate.base, STEEM_SYMBOL) && is_asset_type(exchange_rate.quote, SBD_SYMBOL)) || (is_asset_type(exchange_rate.base, SBD_SYMBOL) && is_asset_type(exchange_rate.quote, STEEM_SYMBOL)), + logic_exception::price_feed_must_be_for_golos_gbg_market, "Price feed must be a GOLOS/GBG price"); - exchange_rate.validate(); + GOLOS_CHECK_PARAM(exchange_rate, exchange_rate.validate()); } void limit_order_create_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index b97da23823..9bc9ec48df 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2403,6 +2403,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(feed_publish_validate) { try { BOOST_TEST_MESSAGE("Testing: feed_publish_validate"); + feed_publish_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.publisher = "alice"; + op.exchange_rate = price(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'publisher' is empty"); + CHECK_PARAM_INVALID(op, publisher, ""); + + BOOST_TEST_MESSAGE("--- failed when 'exchange_rate' not for GOLOS/GBG market"); + CHECK_PARAM_INVALID_LOGIC(op, exchange_rate, price(ASSET("1.000000 GESTS"), ASSET("1.000 GBG")), + price_feed_must_be_for_golos_gbg_market); + + BOOST_TEST_MESSAGE("--- failed when 'exchange_rate' is invalid"); + CHECK_PARAM_INVALID(op, exchange_rate, price(ASSET("0.000 GOLOS"), ASSET("1.000 GBG"))); } FC_LOG_AND_RETHROW() } @@ -2424,28 +2440,32 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with witness account signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); validate_database(); } @@ -2470,12 +2490,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); witness_object &alice_witness = const_cast< witness_object & >( db->get_witness("alice")); - BOOST_REQUIRE(alice_witness.sbd_exchange_rate == op.exchange_rate); - BOOST_REQUIRE(alice_witness.last_sbd_exchange_update == db->head_block_time()); + BOOST_CHECK_EQUAL(alice_witness.sbd_exchange_rate, op.exchange_rate); + BOOST_CHECK_EQUAL(alice_witness.last_sbd_exchange_update, db->head_block_time()); validate_database(); BOOST_TEST_MESSAGE("--- Test failure publishing to non-existent witness"); @@ -2483,9 +2503,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.clear(); tx.signatures.clear(); op.publisher = "bob"; + tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + // In this case missing_object thrown at authority checking step + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(missing_object, "authority", "bob")); validate_database(); BOOST_TEST_MESSAGE("--- Test updating price feed"); @@ -2497,12 +2520,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); alice_witness = const_cast< witness_object & >( db->get_witness("alice")); - BOOST_REQUIRE(std::abs(alice_witness.sbd_exchange_rate.to_real() - - op.exchange_rate.to_real()) < 0.0000005); - BOOST_REQUIRE(alice_witness.last_sbd_exchange_update == db->head_block_time()); + BOOST_CHECK_LT(std::abs(alice_witness.sbd_exchange_rate.to_real() - + op.exchange_rate.to_real()), 0.0000005); + BOOST_CHECK_EQUAL(alice_witness.last_sbd_exchange_update, db->head_block_time()); validate_database(); } FC_LOG_AND_RETHROW() From 9dceb1612dd0cec928c87adfc26733a51270619c Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 18:38:33 +0700 Subject: [PATCH 110/250] Refactor errors: update log printers #790 --- tests/common/database_fixture.cpp | 31 +++++++++++++++++++++++++++++++ tests/common/database_fixture.hpp | 17 +++++++++++++++++ tests/common/helpers.hpp | 15 +++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 5839b61c25..69962978a5 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -10,6 +10,7 @@ #include #include "database_fixture.hpp" +#include "helpers.hpp" #define STEEM_NAMESPACE_PREFIX std::string("golos::protocol::") @@ -79,6 +80,16 @@ bool operator==(const fc::variant_object &left, const fc::variant_object &right) } // namespace fc +namespace fc { namespace ecc { + +std::ostream& operator<<(std::ostream& out, const public_key& v) { + out << v.to_base58(); + return out; +} + +} } // namespace fc::ecc + + namespace golos { namespace protocol { std::ostream& operator<<(std::ostream& out, const asset& v) { @@ -86,9 +97,29 @@ std::ostream& operator<<(std::ostream& out, const asset& v) { return out; } +std::ostream& operator<<(std::ostream& out, const public_key_type& v) { + out << std::string(v); + return out; +} + +std::ostream& operator<<(std::ostream& out, const authority& v) { + out << v.weight_threshold << " / " << v.account_auths << " / " << v.key_auths; + return out; +} + } } // namespace golos::protocol +namespace golos { namespace chain { + +std::ostream& operator<<(std::ostream& out, const shared_authority& v) { + out << static_cast(v); + return out; +} + +} } // namespace golos::chain + + namespace golos { namespace chain { using std::cout; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index d8fea2db5f..545d3ea50f 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -331,6 +332,13 @@ bool operator==(const fc::variant_object &left, const fc::variant_object &right) } // namespace fc +namespace fc { namespace ecc { + +std::ostream &operator<<(std::ostream &out, const public_key &v); + +} } // namespace fc::ecc + + namespace chainbase { template @@ -344,10 +352,19 @@ std::ostream& operator<<(std::ostream& out, const object_id &v) { namespace golos { namespace protocol { std::ostream& operator<<(std::ostream& out, const asset& v); +std::ostream& operator<<(std::ostream& out, const public_key_type& v); +std::ostream& operator<<(std::ostream& out, const authority& v); } } // namespace golos::protocol +namespace golos { namespace chain { + +std::ostream& operator<<(std::ostream& out, const shared_authority& v); + +} } // namespace golos::chain + + #ifndef STEEMIT_INIT_PRIVATE_KEY # define STEEMIT_INIT_PRIVATE_KEY (fc::ecc::private_key::regenerate(fc::sha256::hash(BLOCKCHAIN_NAME))) diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index 198fd7fd58..9e386b727d 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -69,4 +69,19 @@ std::ostream &operator<<(std::ostream &out, const flat_set &t) { return out; } +template +std::ostream &operator<<(std::ostream &out, const flat_map &t) { + out << "("; + if (!t.empty()) { + std::for_each(t.begin(), t.end()-1, + [&](const typename flat_map::value_type& v) { + out << v.first << ":" << v.second << ","; + }); + auto last = *t.rbegin(); + out << last.first << ":" << last.second; + } + out << ")"; + return out; +} + } } // namespace boost::container From a35ddd75aff3e2100a2da6a6c1585bc8ef057368 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 18:39:57 +0700 Subject: [PATCH 111/250] Refactor errors: account_create_operation #790 --- libraries/chain/steem_evaluator.cpp | 11 ++- libraries/protocol/steem_operations.cpp | 14 +-- tests/tests/operation_tests.cpp | 116 ++++++++++++++++-------- 3 files changed, 95 insertions(+), 46 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 94c7d0b2bd..6cb8bee5aa 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -187,14 +187,15 @@ namespace golos { namespace chain { void account_create_evaluator::do_apply(const account_create_operation &o) { const auto& creator = _db.get_account(o.creator); - FC_ASSERT(creator.balance >= o.fee, - "Insufficient balance to create account.", ("creator.balance", creator.balance)("required", o.fee)); + GOLOS_CHECK_BALANCE(creator, MAIN_BALANCE, o.fee); if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) { const auto& median_props = _db.get_witness_schedule_object().median_props; auto min_fee = median_props.account_creation_fee; - FC_ASSERT(o.fee >= min_fee, - "Insufficient Fee: ${f} required, ${p} provided.", ("f", min_fee)("p", o.fee)); + GOLOS_CHECK_OP_PARAM(o, fee, + GOLOS_CHECK_VALUE(o.fee >= min_fee, + "Insufficient Fee: ${f} required, ${p} provided.", ("f", min_fee)("p", o.fee)); + ); } if (_db.is_producing() || @@ -216,6 +217,8 @@ namespace golos { namespace chain { c.balance -= o.fee; }); + GOLOS_CHECK_OBJECT_MISSING(_db, account, o.new_account_name); + const auto& props = _db.get_dynamic_global_properties(); const auto& new_account = _db.create([&](account_object& acc) { acc.name = o.new_account_name; diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 594f622824..89fb33dcf2 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -29,12 +29,14 @@ namespace golos { namespace protocol { } void account_create_operation::validate() const { - validate_account_name(new_account_name); - FC_ASSERT(is_asset_type(fee, STEEM_SYMBOL), "Account creation fee must be GOLOS"); - owner.validate(); - active.validate(); - validate_account_json_metadata(json_metadata); - FC_ASSERT(fee >= asset(0, STEEM_SYMBOL), "Account creation fee cannot be negative"); + GOLOS_CHECK_PARAM(new_account_name, validate_account_name(new_account_name)); + GOLOS_CHECK_PARAM(owner, owner.validate()); + GOLOS_CHECK_PARAM(active, active.validate()); + GOLOS_CHECK_PARAM(fee, { + GOLOS_CHECK_VALUE(is_asset_type(fee, STEEM_SYMBOL), "Account creation fee must be GOLOS"); + GOLOS_CHECK_VALUE(fee >= asset(0, STEEM_SYMBOL), "Account creation fee cannot be negative"); + }); + GOLOS_CHECK_PARAM(json_metadata, validate_account_json_metadata(json_metadata)); } void account_create_with_delegation_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 2b89e8d059..2fd40e2553 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -42,6 +42,42 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_validate) { try { + BOOST_TEST_MESSAGE("Testing: account_create_validate"); + account_create_operation op; + + private_key_type priv_key = generate_private_key("temp_key"); + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.fee = ASSET("10.000 GOLOS"); + op.new_account_name = "bob"; + op.creator = STEEMIT_INIT_MINER_NAME; + op.owner = authority(1, priv_key.get_public_key(), 1); + op.active = authority(2, priv_key.get_public_key(), 2); + op.memo_key = priv_key.get_public_key(); + op.json_metadata = "{\"foo\":\"bar\"}"; + BOOST_CHECK_NO_THROW(op.validate()); + + BOOST_TEST_MESSAGE("--- failed when 'new_account_name' is empty"); + op.new_account_name = ""; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "new_account_name")); + + BOOST_TEST_MESSAGE("--- failed when 'fee' not in GOLOS"); + op.new_account_name = "bob"; + op.fee = ASSET("10.000 GBG"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "fee")); + + BOOST_TEST_MESSAGE("--- failed when 'fee' is negative"); + op.fee = ASSET("-10.000 GOLOS"); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "fee")); + + BOOST_TEST_MESSAGE("--- failed when 'json_metadata' is invalid"); + op.fee = ASSET("10.000 GOLOS"); + op.json_metadata = "[}"; + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "json_metadata")); } FC_LOG_AND_RETHROW() @@ -69,11 +105,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); tx.sign(init_account_priv_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.operations.clear(); @@ -82,18 +119,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(init_account_priv_key, db->get_chain_id()); tx.sign(init_account_priv_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(init_account_priv_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } FC_LOG_AND_RETHROW() @@ -126,7 +166,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(init_account_priv_key, db->get_chain_id()); tx.validate(); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const account_object &acct = db->get_account("alice"); const account_authority_object &acct_auth = db->get("alice"); @@ -134,46 +174,48 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto vest_shares = gpo.total_vesting_shares; auto vests = gpo.total_vesting_fund_steem; - BOOST_REQUIRE(acct.name == "alice"); - BOOST_REQUIRE(acct_auth.owner == authority(1, priv_key.get_public_key(), 1)); - BOOST_REQUIRE(acct_auth.active == authority(2, priv_key.get_public_key(), 2)); - BOOST_REQUIRE(acct.memo_key == priv_key.get_public_key()); - BOOST_REQUIRE(acct.proxy == ""); - BOOST_REQUIRE(acct.created == db->head_block_time()); - BOOST_REQUIRE(acct.balance.amount.value == ASSET("0.000 GOLOS").amount.value); - BOOST_REQUIRE(acct.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); - BOOST_REQUIRE(acct.id._id == acct_auth.id._id); + BOOST_CHECK_EQUAL(acct.name, "alice"); + BOOST_CHECK_EQUAL(acct_auth.owner, authority(1, priv_key.get_public_key(), 1)); + BOOST_CHECK_EQUAL(acct_auth.active, authority(2, priv_key.get_public_key(), 2)); + BOOST_CHECK_EQUAL(acct.memo_key, priv_key.get_public_key()); + BOOST_CHECK_EQUAL(acct.proxy, ""); + BOOST_CHECK_EQUAL(acct.created, db->head_block_time()); + BOOST_CHECK_EQUAL(acct.balance.amount.value, ASSET("0.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(acct.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(acct.id._id, acct_auth.id._id); /* This is being moved out of consensus... #ifndef IS_LOW_MEM - BOOST_REQUIRE( acct.json_metadata == op.json_metadata ); + BOOST_CHECK_EQUAL( acct.json_metadata, op.json_metadata ); #else - BOOST_REQUIRE( acct.json_metadata == "" ); + BOOST_CHECK_EQUAL( acct.json_metadata, "" ); #endif */ /// because init_witness has created vesting shares and blocks have been produced, 100 STEEM is worth less than 100 vesting shares due to rounding - BOOST_REQUIRE(acct.vesting_shares.amount.value == (op.fee * (vest_shares / vests)).amount.value); - BOOST_REQUIRE(acct.vesting_withdraw_rate.amount.value == ASSET("0.000000 GOLOS").amount.value); - BOOST_REQUIRE(acct.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE((init_starting_balance - ASSET("0.100 GOLOS")).amount.value == init.balance.amount.value); + BOOST_CHECK_EQUAL(acct.vesting_shares.amount.value, (op.fee * (vest_shares / vests)).amount.value); + BOOST_CHECK_EQUAL(acct.vesting_withdraw_rate.amount.value, ASSET("0.000000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(acct.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL((init_starting_balance - ASSET("0.100 GOLOS")).amount.value, init.balance.amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure of duplicate account creation"); - BOOST_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); - - BOOST_REQUIRE(acct.name == "alice"); - BOOST_REQUIRE(acct_auth.owner == authority(1, priv_key.get_public_key(), 1)); - BOOST_REQUIRE(acct_auth.active == authority(2, priv_key.get_public_key(), 2)); - BOOST_REQUIRE(acct.memo_key == priv_key.get_public_key()); - BOOST_REQUIRE(acct.proxy == ""); - BOOST_REQUIRE(acct.created == db->head_block_time()); - BOOST_REQUIRE(acct.balance.amount.value == ASSET("0.000 GOLOS ").amount.value); - BOOST_REQUIRE(acct.sbd_balance.amount.value == ASSET("0.000 GBG").amount.value); - BOOST_REQUIRE(acct.vesting_shares.amount.value == (op.fee * (vest_shares / vests)).amount.value); - BOOST_REQUIRE(acct.vesting_withdraw_rate.amount.value == ASSET("0.000000 GOLOS").amount.value); - BOOST_REQUIRE(acct.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE((init_starting_balance - ASSET("0.100 GOLOS")).amount.value == init.balance.amount.value); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "account", "alice"))); + + BOOST_CHECK_EQUAL(acct.name, "alice"); + BOOST_CHECK_EQUAL(acct_auth.owner, authority(1, priv_key.get_public_key(), 1)); + BOOST_CHECK_EQUAL(acct_auth.active, authority(2, priv_key.get_public_key(), 2)); + BOOST_CHECK_EQUAL(acct.memo_key, priv_key.get_public_key()); + BOOST_CHECK_EQUAL(acct.proxy, ""); + BOOST_CHECK_EQUAL(acct.created, db->head_block_time()); + BOOST_CHECK_EQUAL(acct.balance.amount.value, ASSET("0.000 GOLOS ").amount.value); + BOOST_CHECK_EQUAL(acct.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); + BOOST_CHECK_EQUAL(acct.vesting_shares.amount.value, (op.fee * (vest_shares / vests)).amount.value); + BOOST_CHECK_EQUAL(acct.vesting_withdraw_rate.amount.value, ASSET("0.000000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(acct.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL((init_starting_balance - ASSET("0.100 GOLOS")).amount.value, init.balance.amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when creator cannot cover fee"); @@ -184,7 +226,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(init_account_priv_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, STEEMIT_INIT_MINER_NAME, "fund", op.fee.to_string()))); validate_database(); } FC_LOG_AND_RETHROW() From 46cb4368dcc9b858fec5a2c379f0a3a85907a650 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 20 Jul 2018 19:07:44 +0700 Subject: [PATCH 112/250] Refactor errors: add database::throw_if_exists_account #790 --- libraries/chain/database.cpp | 6 ++++++ libraries/chain/include/golos/chain/database.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 8eb8270f61..0d92a8e97b 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -604,6 +604,12 @@ namespace golos { namespace chain { } } + void database::throw_if_exists_account(const account_name_type& account) const { + if (nullptr != find_account(account)) { + GOLOS_THROW_OBJECT_ALREADY_EXIST("account", account); + } + } + const witness_object &database::get_witness(const account_name_type &name) const { try { return get(name); diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index d272b6b115..375f0a44e6 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -153,6 +153,8 @@ namespace golos { namespace chain { void throw_if_exists_limit_order(const account_name_type &account, uint32_t id) const; + void throw_if_exists_account(const account_name_type &account) const; + const witness_object &get_witness(const account_name_type &name) const; const witness_object *find_witness(const account_name_type &name) const; From cfc5cb4d0cd168e304c41039a6dd6ce4acfef65e Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 13:31:46 +0700 Subject: [PATCH 113/250] Refactor errors: account_update_operation #790 --- libraries/chain/steem_evaluator.cpp | 12 ++-- .../include/golos/protocol/exceptions.hpp | 2 + libraries/protocol/steem_operations.cpp | 4 +- tests/common/database_fixture.hpp | 7 ++ tests/tests/operation_tests.cpp | 72 ++++++++++--------- 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 6cb8bee5aa..9332511608 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -324,8 +324,9 @@ namespace golos { namespace chain { void account_update_evaluator::do_apply(const account_update_operation &o) { database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) - FC_ASSERT(o.account != - STEEMIT_TEMP_ACCOUNT, "Cannot update temp account."); + GOLOS_CHECK_OP_PARAM(o, account, + GOLOS_CHECK_VALUE(o.account != STEEMIT_TEMP_ACCOUNT, + "Cannot update temp account.")); if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || _db.is_producing()) && o.posting) { // TODO: Add HF 15 @@ -338,9 +339,10 @@ namespace golos { namespace chain { if (o.owner) { #ifndef STEEMIT_BUILD_TESTNET if (_db.has_hardfork(STEEMIT_HARDFORK_0_11)) - FC_ASSERT(_db.head_block_time() - - account_auth.last_owner_update > - STEEMIT_OWNER_UPDATE_LIMIT, "Owner authority can only be updated once an hour."); + GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), + account_auth.last_owner_update + STEEMIT_OWNER_UPDATE_LIMIT, + bandwidth_exception::change_owner_authority_bandwidth, + "Owner authority can only be updated once an hour."); #endif if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index e41a107f0a..357271c957 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -161,6 +161,7 @@ namespace golos { post_bandwidth, comment_bandwidth, vote_bandwidth, + change_owner_authority_bandwidth, }; }; @@ -368,4 +369,5 @@ FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, (post_bandwidth) (comment_bandwidth) (vote_bandwidth) + (change_owner_authority_bandwidth) ); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 89fb33dcf2..c06f69e287 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -51,14 +51,14 @@ namespace golos { namespace protocol { } void account_update_operation::validate() const { - validate_account_name(account); + GOLOS_CHECK_PARAM(account, validate_account_name(account)); /*if( owner ) owner->validate(); if( active ) active->validate(); if( posting ) posting->validate();*/ - validate_account_json_metadata(json_metadata); + GOLOS_CHECK_PARAM(json_metadata, validate_account_json_metadata(json_metadata)); } void account_metadata_operation::validate() const { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 545d3ea50f..e0cb910da9 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -261,6 +261,13 @@ struct ErrorValidator { } }; +template<> +struct ErrorValidator { + void validate(const std::string& name, const fc::variant& props, int) { + BOOST_CHECK_EQUAL(name, "tx_missing_owner_auth"); + } +}; + #define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 2fd40e2553..29a4e5d3fc 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -245,20 +245,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.posting = authority(); op.posting->weight_threshold = 1; op.posting->add_authorities("abcdefghijklmnopq", 1); + BOOST_CHECK_NO_THROW(op.validate()); - try { - op.validate(); - - signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_FAIL("An exception was not thrown for an invalid account name"); - } - catch (fc::exception &) { - } + signed_transaction tx; + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.operations.push_back(op); + tx.sign(alice_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "abcdefghijklmnop"))); // droped 17-th symbol 'q' validate_database(); } @@ -286,31 +281,35 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE(" GOLOS when owner authority is not updated ---"); BOOST_TEST_MESSAGE("--- Test failure when no signature"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when wrong signature"); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when containing additional incorrect signature"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when containing duplicate signatures"); tx.signatures.clear(); tx.sign(active_key, db->get_chain_id()); tx.sign(active_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test success on active key"); tx.signatures.clear(); tx.sign(active_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test success on owner key alone"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, database::skip_transaction_dupe_check); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check)); BOOST_TEST_MESSAGE(" GOLOS when owner authority is updated ---"); BOOST_TEST_MESSAGE("--- Test failure when updating the owner authority with an active key"); @@ -319,27 +318,31 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.owner = authority(1, active_key.get_public_key(), 1); tx.operations.push_back(op); tx.sign(active_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_owner_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_owner_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when owner key and active key are present"); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_owner_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_owner_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate owner keys are present"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test success when updating the owner authority with an owner key"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); } @@ -366,21 +369,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const account_object &acct = db->get_account("alice"); const account_authority_object &acct_auth = db->get("alice"); - BOOST_REQUIRE(acct.name == "alice"); - BOOST_REQUIRE(acct_auth.owner == authority(1, new_private_key.get_public_key(), 1)); - BOOST_REQUIRE(acct_auth.active == authority(2, new_private_key.get_public_key(), 2)); - BOOST_REQUIRE(acct.memo_key == new_private_key.get_public_key()); + BOOST_CHECK_EQUAL(acct.name, "alice"); + BOOST_CHECK_EQUAL(acct_auth.owner, authority(1, new_private_key.get_public_key(), 1)); + BOOST_CHECK_EQUAL(acct_auth.active, authority(2, new_private_key.get_public_key(), 2)); + BOOST_CHECK_EQUAL(acct.memo_key, new_private_key.get_public_key()); /* This is being moved out of consensus #ifndef IS_LOW_MEM - BOOST_REQUIRE( acct.json_metadata == "{\"bar\":\"foo\"}" ); + BOOST_CHECK_EQUAL( acct.json_metadata, "{\"bar\":\"foo\"}" ); #else - BOOST_REQUIRE( acct.json_metadata == "" ); + BOOST_CHECK_EQUAL( acct.json_metadata, "" ); #endif */ @@ -392,7 +395,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.account = "bob"; tx.operations.push_back(op); tx.sign(new_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception) + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(missing_object, "authority", "bob")); validate_database(); @@ -405,7 +409,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.posting->add_authorities("dave", 1); tx.operations.push_back(op); tx.sign(new_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "dave"))); validate_database(); } FC_LOG_AND_RETHROW() From 5de3cdb93c8dc96943666cc0e3e6ec3a54e35614 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 20 Jul 2018 19:48:10 +0700 Subject: [PATCH 114/250] Fix delete of content on delete of comment. #860 --- libraries/chain/steem_evaluator.cpp | 2 +- plugins/social_network/social_network.cpp | 158 +++++++++++----------- 2 files changed, 78 insertions(+), 82 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 94c7d0b2bd..cc15011a36 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -642,7 +642,7 @@ namespace golos { namespace chain { a.post_count++; }); - const auto &new_comment = _db.create([&](comment_object &com) { + _db.create([&](comment_object &com) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) { GOLOS_CHECK_OP_PARAM(o, parent_permlink, validate_permlink_0_1(o.parent_permlink)); GOLOS_CHECK_OP_PARAM(o, permlink, validate_permlink_0_1(o.permlink)); diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 81378901a2..bd0401e3ab 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -42,21 +42,21 @@ struct content_depth_params { content_depth_params() { } - inline bool miss_content() const { + bool miss_content() const { return has_comment_title_depth && !comment_title_depth && has_comment_body_depth && !comment_body_depth && has_comment_json_metadata_depth && !comment_json_metadata_depth; } - inline bool need_clear() const { + bool need_clear() const { return has_comment_title_depth || has_comment_body_depth || has_comment_json_metadata_depth; } - inline bool should_delete_whole_content_object(const uint32_t delta) const { + bool should_delete_whole_content_object(const uint32_t delta) const { return delta > comment_title_depth && delta > comment_body_depth && delta > comment_json_metadata_depth; } - inline bool should_delete_part_of_content_object(const uint32_t delta) const { + bool should_delete_part_of_content_object(const uint32_t delta) const { return delta > comment_title_depth || delta > comment_body_depth || delta > comment_json_metadata_depth; } @@ -79,20 +79,12 @@ namespace golos { namespace plugins { namespace social_network { using boost::locale::conv::utf_to_utf; struct social_network::impl final { - impl(): database_(appbase::app().get_plugin().db()) { - helper = std::make_unique(database_, follow::fill_account_reputation, fill_promoted, fill_comment_content); + impl(): db(appbase::app().get_plugin().db()) { + helper = std::make_unique(db, follow::fill_account_reputation, fill_promoted, fill_comment_content); } ~impl() = default; - golos::chain::database& database() { - return database_; - } - - golos::chain::database& database() const { - return database_; - } - void select_active_votes ( std::vector& result, uint32_t& total_count, const std::string& author, const std::string& permlink, uint32_t limit @@ -122,27 +114,27 @@ namespace golos { namespace plugins { namespace social_network { void set_depth_parameters(const content_depth_params& params); // Looks for a comment_operation, fills the comment_content state objects. + void pre_operation(const operation_notification& o); + void post_operation(const operation_notification& o); void on_block(const signed_block& b); comment_api_object create_comment_api_object(const comment_object& o) const ; - const comment_content_object &get_comment_content(const comment_id_type& comment) const ; + const comment_content_object& get_comment_content(const comment_id_type& comment) const ; - const comment_content_object *find_comment_content(const comment_id_type& comment) const ; + const comment_content_object* find_comment_content(const comment_id_type& comment) const ; - private: - golos::chain::database& database_; + golos::chain::database& db; std::unique_ptr helper; content_depth_params depth_parameters; }; - const comment_content_object& social_network::impl::get_comment_content(const comment_id_type& comment) const { try { - return database().get(comment); + return db.get(comment); } catch(const std::out_of_range &e) { GOLOS_THROW_MISSING_OBJECT("comment_content", comment); } FC_CAPTURE_AND_RETHROW((comment)) @@ -152,9 +144,8 @@ namespace golos { namespace plugins { namespace social_network { return pimpl->get_comment_content(comment); } - const comment_content_object* social_network::impl::find_comment_content(const comment_id_type& comment) const { - return database().find(comment); + return db.find(comment); } const comment_content_object* social_network::find_comment_content(const comment_id_type& comment) const { @@ -172,17 +163,40 @@ namespace golos { namespace plugins { namespace social_network { helper->select_active_votes(result, total_count, author, permlink, limit); } - void social_network::impl::set_depth_parameters(const content_depth_params& params) { - depth_parameters = params; - } + template + struct delete_visitor { + using result_type = void; + + TImpl& impl; + + delete_visitor(TImpl& impl) : impl(impl) { + } + + template + void operator()(const T& o) const { + } + + void operator()(const delete_comment_operation& o) const { + const auto& comment = impl.db.get_comment(o.author, o.permlink); + const auto content = impl.find_comment_content(comment.id); + + if (content == nullptr) { + return; + } + impl.db.remove(*content); + } + }; + + template struct operation_visitor { using result_type = void; + TImpl& impl; golos::chain::database& db; - content_depth_params depth_parameters; + content_depth_params& depth_parameters; - operation_visitor(golos::chain::database& db, const content_depth_params& params) : db(db), depth_parameters(params) { + operation_visitor(TImpl& p): impl(p), db(p.db), depth_parameters(p.depth_parameters) { } std::wstring utf8_to_wstring(const std::string& str) const { @@ -193,34 +207,17 @@ namespace golos { namespace plugins { namespace social_network { return utf_to_utf(str.c_str(), str.c_str() + str.size()); } - const comment_content_object& get_comment_content(const comment_id_type& comment) const { - return db.get(comment); - } - - const comment_content_object* find_comment_content(const comment_id_type& comment) const { - return db.find(comment); - } - template void operator()(const T& o) const { } - void operator()(const delete_comment_operation& o) const { - const auto& comment = db.get_comment(o.author, o.permlink); - if (find_comment_content(comment.id) == nullptr) { - return; - } - auto& content = get_comment_content(comment.id); - db.remove(content); - } - void operator()(const golos::protocol::comment_operation& o) const { if (depth_parameters.miss_content()) { return; } const auto& comment = db.get_comment(o.author, o.permlink); - const auto comment_content = db.find(comment.id); + const auto comment_content = impl.find_comment_content(comment.id); if ( comment_content != nullptr) { // Edit case @@ -265,10 +262,8 @@ namespace golos { namespace plugins { namespace social_network { } else { // Creation case - comment_id_type id = comment.id; - db.create([&](comment_content_object& con) { - con.comment = id; + con.comment = comment.id; if (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0) { from_string(con.title, o.title); } @@ -290,40 +285,38 @@ namespace golos { namespace plugins { namespace social_network { }; - void social_network::impl::post_operation(const operation_notification& o) { + void social_network::impl::pre_operation(const operation_notification& o) { try { - auto& db = database(); - - operation_visitor ovisit(db, depth_parameters); + delete_visitor ovisit(*this); + o.op.visit(ovisit); + } FC_CAPTURE_AND_RETHROW() + } + void social_network::impl::post_operation(const operation_notification& o) { + try { + operation_visitor ovisit(*this); o.op.visit(ovisit); } FC_CAPTURE_AND_RETHROW() } + void social_network::impl::on_block(const signed_block& b) { try { - auto& db = database(); - const auto& idx = db.get_index().indices().get(); for (auto itr = idx.begin(); itr != idx.end();) { auto& content = *itr; ++itr; - const auto&cidx = db.get_index().indices().get(); - - auto comment = cidx.find(content.comment); + auto& comment = db.get(content.comment); + auto delta = db.head_block_num() - content.block_number; - - if (comment->mode == archived && depth_parameters.should_delete_part_of_content_object(delta)) { + if (comment.mode == archived && depth_parameters.should_delete_part_of_content_object(delta)) { if (depth_parameters.should_delete_whole_content_object(delta)) { - db.modify(content, [&](comment_content_object& con) { - con.title.clear(); - con.body.clear(); - con.json_metadata.clear(); - }); + db.remove(content); continue; } + db.modify(content, [&](comment_content_object& con) { if (delta > depth_parameters.comment_title_depth) { con.title.clear(); @@ -346,7 +339,6 @@ namespace golos { namespace plugins { namespace social_network { } FC_CAPTURE_AND_RETHROW() } - void social_network::plugin_startup() { wlog("social_network plugin: plugin_startup()"); } @@ -386,10 +378,14 @@ namespace golos { namespace plugins { namespace social_network { pimpl = std::make_unique(); JSON_RPC_REGISTER_API(name()); - auto& db = pimpl->database(); + auto& db = pimpl->db; add_plugin_index(db); + db.pre_apply_operation.connect([&](const operation_notification &o) { + pimpl->pre_operation(o); + }); + db.post_apply_operation.connect([&](const operation_notification &o) { pimpl->post_operation(o); }); @@ -398,7 +394,7 @@ namespace golos { namespace plugins { namespace social_network { pimpl->on_block(b); }); - content_depth_params params; + content_depth_params& params = pimpl->depth_parameters; if (options.count("comment-title-depth")) { params.comment_title_depth = options.at("comment-title-depth").as(); @@ -418,8 +414,6 @@ namespace golos { namespace plugins { namespace social_network { if (options.count("set-content-storing-depth-null-after-update")) { params.set_null_after_update = options.at("set-content-storing-depth-null-after-update").as(); } - - pimpl->set_depth_parameters(params); } social_network::~social_network() = default; @@ -436,7 +430,7 @@ namespace golos { namespace plugins { namespace social_network { std::vector& result, std::string author, std::string permlink, uint32_t limit ) const { account_name_type acc_name = account_name_type(author); - const auto& by_permlink_idx = database().get_index().indices().get(); + const auto& by_permlink_idx = db.get_index().indices().get(); auto itr = by_permlink_idx.find(std::make_tuple(acc_name, permlink)); while ( itr != by_permlink_idx.end() && @@ -461,7 +455,7 @@ namespace golos { namespace plugins { namespace social_network { auto author = args.args->at(0).as(); auto permlink = args.args->at(1).as(); auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); - return pimpl->database().with_weak_read_lock([&]() { + return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_content_replies(author, permlink, vote_limit); }); } @@ -488,7 +482,7 @@ namespace golos { namespace plugins { namespace social_network { auto author = args.args->at(0).as(); auto permlink = args.args->at(1).as(); auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); - return pimpl->database().with_weak_read_lock([&]() { + return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_all_content_replies(author, permlink, vote_limit); }); } @@ -499,7 +493,7 @@ namespace golos { namespace plugins { namespace social_network { auto from = GET_OPTIONAL_ARG(1, uint32_t, 0); auto limit = GET_OPTIONAL_ARG(2, uint64_t, DEFAULT_VOTE_LIMIT); - auto& db = pimpl->database(); + auto& db = pimpl->db; return db.with_weak_read_lock([&]() { std::vector result; @@ -530,7 +524,7 @@ namespace golos { namespace plugins { namespace social_network { } discussion social_network::impl::get_content(std::string author, std::string permlink, uint32_t limit) const { - const auto& by_permlink_idx = database().get_index().indices().get(); + const auto& by_permlink_idx = db.get_index().indices().get(); auto itr = by_permlink_idx.find(std::make_tuple(author, permlink)); if (itr != by_permlink_idx.end()) { return get_discussion(*itr, limit); @@ -543,7 +537,7 @@ namespace golos { namespace plugins { namespace social_network { auto author = args.args->at(0).as(); auto permlink = args.args->at(1).as(); auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); - return pimpl->database().with_weak_read_lock([&]() { + return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_content(author, permlink, vote_limit); }); } @@ -553,7 +547,7 @@ namespace golos { namespace plugins { namespace social_network { auto author = args.args->at(0).as(); auto permlink = args.args->at(1).as(); auto limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); - return pimpl->database().with_weak_read_lock([&]() { + return pimpl->db.with_weak_read_lock([&]() { std::vector result; uint32_t total_count; pimpl->select_active_votes(result, total_count, author, permlink, limit); @@ -569,15 +563,17 @@ namespace golos { namespace plugins { namespace social_network { ) const { std::vector result; #ifndef IS_LOW_MEM - auto& db = database(); const auto& last_update_idx = db.get_index().indices().get(); auto itr = last_update_idx.begin(); const account_name_type* parent_author = &start_parent_author; if (start_permlink.size()) { - const auto& comment = db.get_comment(start_parent_author, start_permlink); - itr = last_update_idx.iterator_to(comment); - parent_author = &comment.parent_author; + const auto& comment = db.find_comment(start_parent_author, start_permlink); + if (nullptr == comment) { + return result; + } + itr = last_update_idx.iterator_to(*comment); + parent_author = &comment->parent_author; } else if (start_parent_author.size()) { itr = last_update_idx.lower_bound(start_parent_author); } @@ -605,7 +601,7 @@ namespace golos { namespace plugins { namespace social_network { auto limit = args.args->at(2).as(); auto vote_limit = GET_OPTIONAL_ARG(3, uint32_t, DEFAULT_VOTE_LIMIT); FC_ASSERT(limit <= 100); - return pimpl->database().with_weak_read_lock([&]() { + return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_replies_by_last_update(start_parent_author, start_permlink, limit, vote_limit); }); } From 6586f6600ef35f0b9da280a1bd852a51e790f5fd Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 17:50:55 +0300 Subject: [PATCH 115/250] Refactor errors: macro for trivial ErrorValidator generation #790 1. Macro to autogenerate trivial ErrorValidator structs 2. Move operator<<() functions in one place (database_fixture.hpp) --- tests/common/database_fixture.hpp | 115 +++++++++++++++++------------- tests/common/helpers.hpp | 33 --------- 2 files changed, 64 insertions(+), 84 deletions(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 860506fcc2..1bf74e1893 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -224,49 +224,24 @@ struct ErrorValidator { } }; - -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_irrelevant_sig"); - } -}; - - -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_duplicate_sig"); - } -}; - -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_duplicate_transaction"); - } +#define SIMPLE_PROTOCOL_ERROR_VALIDATOR(E) SIMPLE_ERROR_VALIDATOR(golos::protocol, E) +#define SIMPLE_ERROR_VALIDATOR(NS, E) \ +template<> \ +struct ErrorValidator { \ + void validate(const std::string& name, const fc::variant& props, int) { \ + BOOST_CHECK_EQUAL(name, #E); \ + } \ }; -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_missing_posting_auth"); - } -}; - -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_missing_active_auth"); - } -}; +// Auto-generate trivial ErrorValidators +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_irrelevant_sig); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_duplicate_sig); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_duplicate_transaction); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_posting_auth); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_active_auth); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_owner_auth); +SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_other_auth); -template<> -struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, int) { - BOOST_CHECK_EQUAL(name, "tx_missing_owner_auth"); - } -}; #define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) @@ -320,30 +295,33 @@ struct ErrorValidator { ) +// ostream << +//------------------------------------------------------------- + namespace fc { std::ostream& operator<<(std::ostream& out, const fc::exception& e); std::ostream& operator<<(std::ostream& out, const fc::time_point& v); std::ostream& operator<<(std::ostream& out, const fc::uint128_t& v); std::ostream& operator<<(std::ostream& out, const fc::fixed_string& v); -std::ostream& operator<<(std::ostream &out, const fc::variant_object &v); +std::ostream& operator<<(std::ostream& out, const fc::variant_object& v); template -std::ostream& operator<<(std::ostream& out, const fc::safe &v) { +std::ostream& operator<<(std::ostream& out, const fc::safe& v) { out << v.value; return out; } -bool operator==(const fc::variant_object &left, const fc::variant_object &right); +bool operator==(const fc::variant_object& left, const fc::variant_object& right); -} // namespace fc +} // fc namespace fc { namespace ecc { -std::ostream &operator<<(std::ostream &out, const public_key &v); +std::ostream& operator<<(std::ostream& out, const public_key& v); -} } // namespace fc::ecc +} } // fc::ecc namespace chainbase { @@ -354,18 +332,49 @@ std::ostream& operator<<(std::ostream& out, const object_id &v) { return out; } -} // namespace chainbase +} // chainbase namespace std { template -std::ostream& operator<<(std::ostream& out, const std::pair &v) { +std::ostream& operator<<(std::ostream& out, const std::pair& v) { out << "<" << v.first << ":" << v.second << ">"; return out; } -} // namespace std +} // std + + +namespace boost { namespace container { + +template +std::ostream& operator<<(std::ostream& out, const flat_set& t) { + out << "("; + if (!t.empty()) { + std::for_each(t.begin(), t.end()-1, [&](const T& v) {out << v << ",";}); + out << *t.rbegin(); + } + out << ")"; + return out; +} + +template +std::ostream& operator<<(std::ostream& out, const flat_map& t) { + out << "("; + if (!t.empty()) { + std::for_each(t.begin(), t.end()-1, + [&](const typename flat_map::value_type& v) { + out << v.first << ":" << v.second << ","; + }); + auto last = *t.rbegin(); + out << last.first << ":" << last.second; + } + out << ")"; + return out; +} + +} } // boost::container namespace golos { namespace protocol { @@ -375,15 +384,19 @@ std::ostream& operator<<(std::ostream& out, const public_key_type& v); std::ostream& operator<<(std::ostream& out, const authority& v); std::ostream& operator<<(std::ostream& out, const price& v); -} } // namespace golos::protocol +} } // golos::protocol namespace golos { namespace chain { std::ostream& operator<<(std::ostream& out, const shared_authority& v); -} } // namespace golos::chain +} } // golos::chain + +/////////////////////////////////////////////////////////////// +// database_fixture +/////////////////////////////////////////////////////////////// #ifndef STEEMIT_INIT_PRIVATE_KEY diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index 9e386b727d..b91bd55011 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -52,36 +52,3 @@ CHECK; \ OP.NAME = t; \ } - - -// boost::container << -//------------------------------------------------------------- -namespace boost { namespace container { - -template -std::ostream &operator<<(std::ostream &out, const flat_set &t) { - out << "("; - if (!t.empty()) { - std::for_each(t.begin(), t.end()-1, [&](const T& v) {out << v << ",";}); - out << *t.rbegin(); - } - out << ")"; - return out; -} - -template -std::ostream &operator<<(std::ostream &out, const flat_map &t) { - out << "("; - if (!t.empty()) { - std::for_each(t.begin(), t.end()-1, - [&](const typename flat_map::value_type& v) { - out << v.first << ":" << v.second << ","; - }); - auto last = *t.rbegin(); - out << last.first << ":" << last.second; - } - out << ")"; - return out; -} - -} } // namespace boost::container From c9421af65075e7233832a2aad169693fea8861c0 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 20 Jul 2018 17:56:29 +0300 Subject: [PATCH 116/250] Refactor errors: fix review issues for proposal tests #790 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + BOOST_CHECK → BOOST_CHECK_EQUAL --- libraries/chain/database_proposal_object.cpp | 12 ++ .../chain/include/golos/chain/database.hpp | 2 +- libraries/chain/proposal_evaluator.cpp | 11 +- tests/tests/operation_tests.cpp | 108 +++++++++--------- tests/tests/proposal_tests.cpp | 39 ++++--- 5 files changed, 92 insertions(+), 80 deletions(-) diff --git a/libraries/chain/database_proposal_object.cpp b/libraries/chain/database_proposal_object.cpp index 5fb1e099f4..2eed410e41 100644 --- a/libraries/chain/database_proposal_object.cpp +++ b/libraries/chain/database_proposal_object.cpp @@ -21,6 +21,18 @@ namespace golos { namespace chain { return find(std::make_tuple(author, title)); } +// Yet another temporary PoC +// TODO: This can be generalized to generate all 3: get_, find_ and throw_if_exists_ +// methods with variable number of params (like DEFINE_/DECLARE_API + PLUGIN_API_VALIDATE_ARGS) +#define DB_DEFINE_THROW_IF_EXIST(O, T1, N1, T2, N2) \ + void database::throw_if_exists_##O(T1 N1, T2 N2) const { \ + if (nullptr != find_##O(N1, N2)) { \ + GOLOS_THROW_OBJECT_ALREADY_EXIST(#O, fc::mutable_variant_object()(#N1,N1)(#N2,N2)); \ + } \ + } + + DB_DEFINE_THROW_IF_EXIST(proposal, const account_name_type&, author, const std::string&, title); + void database::push_proposal(const proposal_object& proposal) { try { auto ops = proposal.operations(); auto session = start_undo_session(); diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 375f0a44e6..c84f94ed40 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -164,8 +164,8 @@ namespace golos { namespace chain { const account_object *find_account(const account_name_type &name) const; const proposal_object& get_proposal(const account_name_type&, const std::string&) const; - const proposal_object* find_proposal(const account_name_type&, const std::string&) const; + void throw_if_exists_proposal(const account_name_type&, const std::string&) const; const comment_object &get_comment(const account_name_type &author, const shared_string &permlink) const; diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index d1777817d4..bc593390e0 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -97,11 +97,6 @@ namespace golos { namespace chain { : evaluator_impl(db) { } -#define CHECK_ALREADY_EXIST(OP, N, X, Y) \ - if (_db.find_##N(o.X, o.Y)) { \ - GOLOS_THROW_OBJECT_ALREADY_EXIST(#N, fc::mutable_variant_object()(#X,o.X)(#Y,o.Y)); \ - } - void proposal_create_evaluator::do_apply(const proposal_create_operation& o) { try { safe_int_increment depth_increment(depth_); @@ -113,10 +108,7 @@ namespace golos { namespace chain { ("depth", STEEMIT_MAX_PROPOSAL_DEPTH)); } - CHECK_ALREADY_EXIST(o, proposal, author, title); - // if (nullptr == _db.find_proposal(o.author, o.title)) { - // GOLOS_THROW_OBJECT_ALREADY_EXIST("Proposal", fc::mutable_variant_object()("author",o.author)("title",o.title)); - // } + GOLOS_CHECK_OBJECT_MISSING(_db, proposal, o.author, o.title); const auto now = _db.head_block_time(); GOLOS_CHECK_OP_PARAM(o, expiration_time, { @@ -180,6 +172,7 @@ namespace golos { namespace chain { golos::chain::database::skip_tapos_check | golos::chain::database::skip_database_locking; + // This not only validates proposal operations but also pre-apply them to execute evaluators' checks _db.validate_transaction(trx, skip_steps); auto ops_size = fc::raw::pack_size(trx.operations); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e02125668e..bf6177f8bc 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1889,21 +1889,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); const witness_object& w = db->get_witness("alice"); - BOOST_CHECK(w.owner == "alice"); - BOOST_CHECK(w.created == db->head_block_time()); - BOOST_CHECK(to_string(w.url) == op.url); - BOOST_CHECK(w.signing_key == op.block_signing_key); - BOOST_CHECK(w.props.account_creation_fee == op.props.account_creation_fee); - BOOST_CHECK(w.props.maximum_block_size == op.props.maximum_block_size); - BOOST_CHECK(w.total_missed == 0); - BOOST_CHECK(w.last_aslot == 0); - BOOST_CHECK(w.last_confirmed_block_num == 0); - BOOST_CHECK(w.pow_worker == 0); - BOOST_CHECK(w.votes.value == 0); - BOOST_CHECK(w.virtual_last_update == 0); - BOOST_CHECK(w.virtual_position == 0); - BOOST_CHECK(w.virtual_scheduled_time == fc::uint128_t::max_value()); - BOOST_CHECK(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); // No fee + BOOST_CHECK_EQUAL(w.owner, "alice"); + BOOST_CHECK_EQUAL(w.created, db->head_block_time()); + BOOST_CHECK_EQUAL(to_string(w.url), op.url); + BOOST_CHECK_EQUAL(w.signing_key, op.block_signing_key); + BOOST_CHECK_EQUAL(w.props.account_creation_fee, op.props.account_creation_fee); + BOOST_CHECK_EQUAL(w.props.maximum_block_size, op.props.maximum_block_size); + BOOST_CHECK_EQUAL(w.total_missed, 0); + BOOST_CHECK_EQUAL(w.last_aslot, 0); + BOOST_CHECK_EQUAL(w.last_confirmed_block_num, 0); + BOOST_CHECK_EQUAL(w.pow_worker, 0); + BOOST_CHECK_EQUAL(w.votes.value, 0); + BOOST_CHECK_EQUAL(w.virtual_last_update, 0); + BOOST_CHECK_EQUAL(w.virtual_position, 0); + BOOST_CHECK_EQUAL(w.virtual_scheduled_time, fc::uint128_t::max_value()); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("10.000 GOLOS").amount.value); // No fee validate_database(); BOOST_TEST_MESSAGE("--- Test updating a witness"); @@ -1913,21 +1913,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.sign(alice_private_key, db->get_chain_id()); BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_CHECK(w.owner == "alice"); - BOOST_CHECK(w.created == db->head_block_time()); - BOOST_CHECK(to_string(w.url) == "bar.foo"); - BOOST_CHECK(w.signing_key == op.block_signing_key); - BOOST_CHECK(w.props.account_creation_fee == op.props.account_creation_fee); - BOOST_CHECK(w.props.maximum_block_size == op.props.maximum_block_size); - BOOST_CHECK(w.total_missed == 0); - BOOST_CHECK(w.last_aslot == 0); - BOOST_CHECK(w.last_confirmed_block_num == 0); - BOOST_CHECK(w.pow_worker == 0); - BOOST_CHECK(w.votes.value == 0); - BOOST_CHECK(w.virtual_last_update == 0); - BOOST_CHECK(w.virtual_position == 0); - BOOST_CHECK(w.virtual_scheduled_time == fc::uint128_t::max_value()); - BOOST_CHECK(alice.balance.amount.value == ASSET("10.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(w.owner, "alice"); + BOOST_CHECK_EQUAL(w.created, db->head_block_time()); + BOOST_CHECK_EQUAL(to_string(w.url), "bar.foo"); + BOOST_CHECK_EQUAL(w.signing_key, op.block_signing_key); + BOOST_CHECK_EQUAL(w.props.account_creation_fee, op.props.account_creation_fee); + BOOST_CHECK_EQUAL(w.props.maximum_block_size, op.props.maximum_block_size); + BOOST_CHECK_EQUAL(w.total_missed, 0); + BOOST_CHECK_EQUAL(w.last_aslot, 0); + BOOST_CHECK_EQUAL(w.last_confirmed_block_num, 0); + BOOST_CHECK_EQUAL(w.pow_worker, 0); + BOOST_CHECK_EQUAL(w.votes.value, 0); + BOOST_CHECK_EQUAL(w.virtual_last_update, 0); + BOOST_CHECK_EQUAL(w.virtual_position, 0); + BOOST_CHECK_EQUAL(w.virtual_scheduled_time, fc::uint128_t::max_value()); + BOOST_CHECK_EQUAL(alice.balance.amount.value, ASSET("10.000 GOLOS").amount.value); validate_database(); } FC_LOG_AND_RETHROW() @@ -6861,22 +6861,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) const account_object& bob_acc = db->get_account("bob"); const account_object& alice_acc = db->get_account("alice"); - BOOST_CHECK(alice_acc.delegated_vesting_shares == ASSET_GESTS(1e7)); - BOOST_CHECK(bob_acc.received_vesting_shares == ASSET_GESTS(1e7)); - BOOST_CHECK(bob_acc.available_vesting_shares(true) == + BOOST_CHECK_EQUAL(alice_acc.delegated_vesting_shares, ASSET_GESTS(1e7)); + BOOST_CHECK_EQUAL(bob_acc.received_vesting_shares, ASSET_GESTS(1e7)); + BOOST_CHECK_EQUAL(bob_acc.available_vesting_shares(true), bob_acc.vesting_shares - bob_acc.delegated_vesting_shares); - BOOST_CHECK(bob_acc.available_vesting_shares() == + BOOST_CHECK_EQUAL(bob_acc.available_vesting_shares(), bob_acc.vesting_shares - bob_acc.delegated_vesting_shares); - BOOST_CHECK(bob_acc.effective_vesting_shares() == + BOOST_CHECK_EQUAL(bob_acc.effective_vesting_shares(), bob_acc.vesting_shares - bob_acc.delegated_vesting_shares + bob_acc.received_vesting_shares); BOOST_TEST_MESSAGE("--- Test delegation object integrity"); auto delegation = db->find(std::make_tuple(op.creator, op.new_account_name)); BOOST_CHECK(delegation != nullptr); - BOOST_CHECK(delegation->delegator == op.creator); - BOOST_CHECK(delegation->delegatee == op.new_account_name); - BOOST_CHECK(delegation->vesting_shares == ASSET_GESTS(1e7)); - BOOST_CHECK(delegation->min_delegation_time == db->head_block_time() + GOLOS_CREATE_ACCOUNT_DELEGATION_TIME); + BOOST_CHECK_EQUAL(delegation->delegator, op.creator); + BOOST_CHECK_EQUAL(delegation->delegatee, op.new_account_name); + BOOST_CHECK_EQUAL(delegation->vesting_shares, ASSET_GESTS(1e7)); + BOOST_CHECK_EQUAL(delegation->min_delegation_time, db->head_block_time() + GOLOS_CREATE_ACCOUNT_DELEGATION_TIME); auto delegated = delegation->vesting_shares; auto exp_time = delegation->min_delegation_time; @@ -6933,9 +6933,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto itr = db->get_index().begin(); auto end = db->get_index().end(); BOOST_CHECK(itr != end); - BOOST_CHECK(itr->delegator == "alice"); - BOOST_CHECK(itr->vesting_shares == delegated); - BOOST_CHECK(itr->expiration == exp_time); + BOOST_CHECK_EQUAL(itr->delegator, "alice"); + BOOST_CHECK_EQUAL(itr->vesting_shares, delegated); + BOOST_CHECK_EQUAL(itr->expiration, exp_time); validate_database(); } FC_LOG_AND_RETHROW() @@ -7218,21 +7218,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->get("alice"); - BOOST_CHECK(meta.account == "alice"); - BOOST_CHECK(meta.json_metadata == json); - BOOST_CHECK(alice_acc.last_account_update == now); + BOOST_CHECK_EQUAL(meta.account, "alice"); + BOOST_CHECK_EQUAL(meta.json_metadata, json); + BOOST_CHECK_EQUAL(alice_acc.last_account_update, now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_CHECK(alice_api.json_metadata == json); + BOOST_CHECK_EQUAL(alice_api.json_metadata, json); BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create"); // bob is created before all metadata storing settings // therefore it should have account_metadata_object ACTOR(bob); // create_account with json_metadata = "" meta = db->get("bob"); // just checks presence, throws on fail - BOOST_CHECK(meta.account == "bob"); - BOOST_CHECK(meta.json_metadata == ""); + BOOST_CHECK_EQUAL(meta.account, "bob"); + BOOST_CHECK_EQUAL(meta.json_metadata, ""); BOOST_TEST_MESSAGE("--- Test existance of account_metadata_object after account_create_with_delegation"); generate_blocks(1); @@ -7249,8 +7249,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) push_tx_with_ops(tx, bob_private_key, cr); meta = db->get("sam"); - BOOST_CHECK(meta.account == "sam"); - BOOST_CHECK(meta.json_metadata == ""); + BOOST_CHECK_EQUAL(meta.account, "sam"); + BOOST_CHECK_EQUAL(meta.json_metadata, ""); validate_database(); } FC_LOG_AND_RETHROW() @@ -7283,11 +7283,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->find("alice"); BOOST_CHECK(meta == nullptr); - BOOST_CHECK(alice_acc.last_account_update == now); + BOOST_CHECK_EQUAL(alice_acc.last_account_update, now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_CHECK(alice_api.json_metadata == ""); + BOOST_CHECK_EQUAL(alice_api.json_metadata, ""); ACTOR(bob); // create_account with json_metadata = "" @@ -7338,11 +7338,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto alice_acc = db->get_account("alice"); auto meta = db->find("alice"); BOOST_CHECK(meta == nullptr); - BOOST_CHECK(alice_acc.last_account_update == now); + BOOST_CHECK_EQUAL(alice_acc.last_account_update, now); BOOST_TEST_MESSAGE("----- Test API"); account_api_object alice_api(alice_acc, *db); - BOOST_CHECK(alice_api.json_metadata == ""); + BOOST_CHECK_EQUAL(alice_api.json_metadata, ""); ACTOR(bob); // create_account with json_metadata = "" diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index 8cffd9877b..c3d1bb4747 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -243,7 +243,8 @@ BOOST_AUTO_TEST_CASE(create_proposal) { try { cop.proposed_operations.push_back(operation_wrapper(top)); cop.proposed_operations.push_back(operation_wrapper(vop)); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, cop), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, cop), + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::tx_with_both_posting_active_ops))); BOOST_TEST_MESSAGE("--- Simple proposal with a transfer operation"); @@ -309,7 +310,8 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop.title = cop.title; uop.active_approvals_to_add.insert("alice"); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, uop), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, uop), + CHECK_ERROR(tx_missing_active_auth, 0)); proposal_update_operation uop1; uop1.author = cop.author; @@ -317,14 +319,17 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop1.active_approvals_to_add.insert("alice"); uop1.active_approvals_to_remove.insert("alice"); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, alice_private_key, uop1), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, uop1), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::add_and_remove_same_approval))); proposal_update_operation uop2; uop2.author = cop.author; uop2.title = cop.title; uop2.key_approvals_to_add.insert(bob_public_key); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, alice_private_key, uop2), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, uop2), + CHECK_ERROR(tx_missing_other_auth, 0)); BOOST_TEST_MESSAGE("--- Add an approval to a proposal"); @@ -432,7 +437,9 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop10.author = cop.author; uop10.title = cop.title; uop10.active_approvals_to_add.insert("bob"); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, bob_private_key, uop10), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, uop10), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_add_approval_in_review_period))); BOOST_TEST_MESSAGE("--- Auto removing of a proposal if no approvals in a review period"); proposal_update_operation uop11; @@ -442,7 +449,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { push_tx_with_ops(tx, alice_private_key, uop11); generate_blocks(1); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); } FC_LOG_AND_RETHROW() } @@ -477,8 +484,7 @@ BOOST_AUTO_TEST_CASE(update_proposal1) { try { push_tx_with_ops(tx, alice_private_key, uop); generate_blocks(1); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); - + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -515,8 +521,7 @@ BOOST_AUTO_TEST_CASE(update_proposal2) { try { push_tx_with_ops(tx, alice_private_key, uop); generate_blocks(1); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); - + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -564,8 +569,7 @@ BOOST_AUTO_TEST_CASE(update_proposal3) { try { generate_blocks(p.expiration_time); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); - + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -719,7 +723,8 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop3.author = cop.author; uop3.title = cop.title; uop3.key_approvals_to_add.insert(dave_public_key); - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, dave_private_key, uop3), tx_invalid_operation); // TODO tx_invalid_operation -> tx_irrelevant_sig + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, dave_private_key, uop3), + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(tx_irrelevant_sig, 0))); // !!!TODO proposal_update_operation uop4; uop4.author = cop.author; @@ -728,7 +733,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { push_tx_with_ops(tx, dan_private_key, uop4); generate_blocks(1); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); BOOST_CHECK_EQUAL(poxx_account.balance.amount.value, 7500); BOOST_CHECK_EQUAL(edy_account.balance.amount.value, 2500); @@ -765,7 +770,9 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { dop.author = cop.author; dop.title = cop.title; dop.requester = "dave"; - BOOST_REQUIRE_THROW(push_tx_with_ops_throw(tx, dave_private_key, dop), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, dave_private_key, dop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::proposal_delete_not_allowed))); BOOST_TEST_MESSAGE("--- Authorized delete of proposal"); @@ -776,7 +783,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { push_tx_with_ops(tx, alice_private_key, dop1); generate_blocks(1); - BOOST_REQUIRE_THROW(db->get_proposal(cop.author, cop.title), fc::exception); + GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); } FC_LOG_AND_RETHROW() } From 51bdef63ce7a33bbd1e4cd4b71e7d2896f10e478 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 20:48:11 +0700 Subject: [PATCH 117/250] Refactor errors: account_witness_vote_operation #790 --- libraries/chain/steem_evaluator.cpp | 23 +++-- .../include/golos/protocol/exceptions.hpp | 12 +++ libraries/protocol/steem_operations.cpp | 4 +- tests/tests/operation_tests.cpp | 84 ++++++++++++------- 4 files changed, 85 insertions(+), 38 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..c907562e77 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1113,11 +1113,14 @@ namespace golos { namespace chain { void account_witness_vote_evaluator::do_apply(const account_witness_vote_operation &o) { database &_db = db(); const auto &voter = _db.get_account(o.account); - FC_ASSERT(voter.proxy.size() == - 0, "A proxy is currently set, please clear the proxy before voting for a witness."); + GOLOS_CHECK_LOGIC(voter.proxy.size() == 0, + logic_exception::cannot_vote_when_route_are_set, + "A proxy is currently set, please clear the proxy before voting for a witness."); if (o.approve) - FC_ASSERT(voter.can_vote, "Account has declined its voting rights."); + GOLOS_CHECK_LOGIC(voter.can_vote, + logic_exception::voter_declined_voting_rights, + "Account has declined its voting rights."); const auto &witness = _db.get_witness(o.witness); @@ -1125,11 +1128,15 @@ namespace golos { namespace chain { auto itr = by_account_witness_idx.find(boost::make_tuple(voter.id, witness.id)); if (itr == by_account_witness_idx.end()) { - FC_ASSERT(o.approve, "Vote doesn't exist, user must indicate a desire to approve witness."); + GOLOS_CHECK_LOGIC(o.approve, + logic_exception::witness_vote_does_not_exist, + "Vote doesn't exist, user must indicate a desire to approve witness."); if (_db.has_hardfork(STEEMIT_HARDFORK_0_2)) { - FC_ASSERT(voter.witnesses_voted_for < - STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, "Account has voted for too many witnesses."); // TODO: Remove after hardfork 2 + GOLOS_CHECK_LOGIC(voter.witnesses_voted_for < STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, + logic_exception::account_has_too_many_witness_votes, + "Account has voted for too many witnesses.", + ("max_votes", STEEMIT_MAX_ACCOUNT_WITNESS_VOTES)); // TODO: Remove after hardfork 2 _db.create([&](witness_vote_object &v) { v.witness = witness.id; @@ -1158,7 +1165,9 @@ namespace golos { namespace chain { }); } else { - FC_ASSERT(!o.approve, "Vote currently exists, user must indicate a desire to reject witness."); + GOLOS_CHECK_LOGIC(!o.approve, + logic_exception::witness_vote_already_exist, + "Vote currently exists, user must indicate a desire to reject witness."); if (_db.has_hardfork(STEEMIT_HARDFORK_0_2)) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_3)) { diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index ef18cc0142..1480c79b89 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -224,6 +224,12 @@ namespace golos { // feed_publish_operation price_feed_must_be_for_golos_gbg_market, + + // account_witness_vote_operation + cannot_vote_when_route_are_set, + witness_vote_does_not_exist, + witness_vote_already_exist, + account_has_too_many_witness_votes, }; }; @@ -373,6 +379,12 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // feed_publis_operation (price_feed_must_be_for_golos_gbg_market) + + // account_witness_vote_operation + (cannot_vote_when_route_are_set) + (witness_vote_does_not_exist) + (witness_vote_already_exist) + (account_has_too_many_witness_votes) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..293bc96a2c 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -255,8 +255,8 @@ namespace golos { namespace protocol { } void account_witness_vote_operation::validate() const { - validate_account_name(account); - validate_account_name(witness); + GOLOS_CHECK_PARAM_ACCOUNT(account); + GOLOS_CHECK_PARAM_ACCOUNT(witness); } void account_witness_proxy_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e02125668e..c0c00e783f 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1952,6 +1952,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_witness_vote_validate) { try { BOOST_TEST_MESSAGE("Testing: account_witness_vote_validate"); + account_witness_vote_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.account = "bob"; + op.witness = "alice"; + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'account' is empty"); + CHECK_PARAM_INVALID(op, account, ""); + + BOOST_TEST_MESSAGE("--- failed when 'witness' is empty"); + CHECK_PARAM_INVALID(op, witness, ""); validate_database(); } @@ -1977,34 +1989,39 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(bob_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test failure with proxy signature"); proxy("bob", "sam"); tx.signatures.clear(); tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -2037,10 +2054,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(sam_witness.votes == alice.vesting_shares.amount); - BOOST_REQUIRE( + BOOST_CHECK_EQUAL(sam_witness.votes, alice.vesting_shares.amount); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) != witness_vote_idx.end()); validate_database(); @@ -2052,17 +2069,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - BOOST_REQUIRE(sam_witness.votes.value == 0); - BOOST_REQUIRE( + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + BOOST_CHECK_EQUAL(sam_witness.votes.value, 0); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) == witness_vote_idx.end()); BOOST_TEST_MESSAGE("--- Test failure when attempting to revoke a non-existent vote"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); - BOOST_REQUIRE(sam_witness.votes.value == 0); - BOOST_REQUIRE( + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::witness_vote_does_not_exist))); + + BOOST_CHECK_EQUAL(sam_witness.votes.value, 0); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) == witness_vote_idx.end()); @@ -2075,13 +2095,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(sam_witness.votes == (bob.proxied_vsf_votes_total() + bob.vesting_shares.amount)); - BOOST_REQUIRE( + BOOST_CHECK_EQUAL(sam_witness.votes, (bob.proxied_vsf_votes_total() + bob.vesting_shares.amount)); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, bob.id)) != witness_vote_idx.end()); - BOOST_REQUIRE( + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) == witness_vote_idx.end()); @@ -2091,13 +2111,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.account = "alice"; tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_vote_when_route_are_set))); - BOOST_REQUIRE(sam_witness.votes == (bob.proxied_vsf_votes_total() + bob.vesting_shares.amount)); - BOOST_REQUIRE( + BOOST_CHECK_EQUAL(sam_witness.votes, (bob.proxied_vsf_votes_total() + bob.vesting_shares.amount)); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, bob.id)) != witness_vote_idx.end()); - BOOST_REQUIRE( + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) == witness_vote_idx.end()); @@ -2109,13 +2131,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(sam_witness.votes.value == 0); - BOOST_REQUIRE( + BOOST_CHECK_EQUAL(sam_witness.votes.value, 0); + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, bob.id)) == witness_vote_idx.end()); - BOOST_REQUIRE( + BOOST_CHECK( witness_vote_idx.find(std::make_tuple(sam_witness.id, alice.id)) == witness_vote_idx.end()); @@ -2126,8 +2148,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.approve = true; tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "witness", "dave"))); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when voting for an account that is not a witness"); @@ -2136,8 +2160,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.witness = "alice"; tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "witness", "alice"))); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); validate_database(); } FC_LOG_AND_RETHROW() From e56d648124fd17e21c49dce70334a84da343b36d Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 21:24:59 +0700 Subject: [PATCH 118/250] Refactor errors: account_witness_proxy_operation #790 --- libraries/chain/steem_evaluator.cpp | 17 ++- .../include/golos/protocol/exceptions.hpp | 10 ++ libraries/protocol/steem_operations.cpp | 8 +- tests/tests/operation_tests.cpp | 127 +++++++++++------- 4 files changed, 102 insertions(+), 60 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index c907562e77..e2899b43d3 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1062,9 +1062,13 @@ namespace golos { namespace chain { void account_witness_proxy_evaluator::do_apply(const account_witness_proxy_operation &o) { database &_db = db(); const auto &account = _db.get_account(o.account); - FC_ASSERT(account.proxy != o.proxy, "Proxy must change."); + GOLOS_CHECK_LOGIC(account.proxy != o.proxy, + logic_exception::proxy_must_change, + "Proxy must change."); - FC_ASSERT(account.can_vote, "Account has declined the ability to vote and cannot proxy votes."); + GOLOS_CHECK_LOGIC(account.can_vote, + logic_exception::voter_declined_voting_rights, + "Account has declined the ability to vote and cannot proxy votes."); /// remove all current votes std::array delta; @@ -1084,10 +1088,13 @@ namespace golos { namespace chain { auto cprox = &new_proxy; while (cprox->proxy.size() != 0) { const auto next_proxy = _db.get_account(cprox->proxy); - FC_ASSERT(proxy_chain.insert(next_proxy.id).second, "This proxy would create a proxy loop."); + GOLOS_CHECK_LOGIC(proxy_chain.insert(next_proxy.id).second, + logic_exception::proxy_would_create_loop, + "This proxy would create a proxy loop."); cprox = &next_proxy; - FC_ASSERT(proxy_chain.size() <= - STEEMIT_MAX_PROXY_RECURSION_DEPTH, "Proxy chain is too long."); + GOLOS_CHECK_LOGIC(proxy_chain.size() <= STEEMIT_MAX_PROXY_RECURSION_DEPTH, + logic_exception::proxy_chain_is_too_long, + "Proxy chain is too long."); } /// clear all individual vote records diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 1480c79b89..3c0ee8a6a2 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -230,6 +230,11 @@ namespace golos { witness_vote_does_not_exist, witness_vote_already_exist, account_has_too_many_witness_votes, + + // account_witness_proxy_operation + proxy_must_change, + proxy_would_create_loop, + proxy_chain_is_too_long, }; }; @@ -385,6 +390,11 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (witness_vote_does_not_exist) (witness_vote_already_exist) (account_has_too_many_witness_votes) + + // account_witness_proxy_operation + (proxy_must_change) + (proxy_would_create_loop) + (proxy_chain_is_too_long) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 293bc96a2c..d17f35e0da 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -260,11 +260,13 @@ namespace golos { namespace protocol { } void account_witness_proxy_operation::validate() const { - validate_account_name(account); + GOLOS_CHECK_PARAM_ACCOUNT(account); if (proxy.size()) { - validate_account_name(proxy); + GOLOS_CHECK_PARAM(proxy, { + validate_account_name(proxy); + GOLOS_CHECK_VALUE(proxy != account, "Cannot proxy to self"); + }); } - FC_ASSERT(proxy != account, "Cannot proxy to self"); } void custom_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index c0c00e783f..8d3821c10d 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2172,6 +2172,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_witness_proxy_validate) { try { BOOST_TEST_MESSAGE("Testing: account_witness_proxy_validate"); + account_witness_proxy_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.account = "bob"; + op.proxy = "alice"; + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'account' is empty"); + CHECK_PARAM_INVALID(op, account, ""); + + BOOST_TEST_MESSAGE("--- success when 'proxy' is empty"); + CHECK_PARAM_VALID(op, proxy, ""); + + BOOST_TEST_MESSAGE("--- failed when 'proxy' not valid"); + CHECK_PARAM_INVALID(op, proxy, "a"); + CHECK_PARAM_INVALID(op, proxy, "bob"); validate_database(); } @@ -2194,33 +2210,38 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(bob_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); tx.signatures.clear(); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- Test failure with proxy signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -2253,12 +2274,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(bob.proxy == "alice"); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(alice.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(alice.proxied_vsf_votes_total() == + BOOST_CHECK_EQUAL(bob.proxy, "alice"); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(alice.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(alice.proxied_vsf_votes_total(), bob.vesting_shares.amount); validate_database(); @@ -2271,23 +2292,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(bob.proxy == "sam"); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(alice.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(sam.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(sam.proxied_vsf_votes_total().value == bob.vesting_shares.amount); + BOOST_CHECK_EQUAL(bob.proxy, "sam"); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(alice.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(sam.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(sam.proxied_vsf_votes_total().value, bob.vesting_shares.amount); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when changing proxy to existing proxy"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, database::skip_transaction_dupe_check), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::proxy_must_change))); - BOOST_REQUIRE(bob.proxy == "sam"); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(sam.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(sam.proxied_vsf_votes_total() == bob.vesting_shares.amount); + BOOST_CHECK_EQUAL(bob.proxy, "sam"); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(sam.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(sam.proxied_vsf_votes_total(), bob.vesting_shares.amount); validate_database(); BOOST_TEST_MESSAGE("--- Test adding a grandparent proxy"); @@ -2300,14 +2323,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(bob.proxy == "sam"); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(sam.proxy == "dave"); - BOOST_REQUIRE(sam.proxied_vsf_votes_total() == bob.vesting_shares.amount); - BOOST_REQUIRE(dave.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(dave.proxied_vsf_votes_total() == + BOOST_CHECK_EQUAL(bob.proxy, "sam"); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(sam.proxy, "dave"); + BOOST_CHECK_EQUAL(sam.proxied_vsf_votes_total(), bob.vesting_shares.amount); + BOOST_CHECK_EQUAL(dave.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(dave.proxied_vsf_votes_total(), (sam.vesting_shares + bob.vesting_shares).amount); validate_database(); @@ -2322,17 +2345,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.proxy == "sam"); - BOOST_REQUIRE(alice.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(bob.proxy == "sam"); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(sam.proxy == "dave"); - BOOST_REQUIRE(sam.proxied_vsf_votes_total() == + BOOST_CHECK_EQUAL(alice.proxy, "sam"); + BOOST_CHECK_EQUAL(alice.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(bob.proxy, "sam"); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(sam.proxy, "dave"); + BOOST_CHECK_EQUAL(sam.proxied_vsf_votes_total(), (bob.vesting_shares + alice.vesting_shares).amount); - BOOST_REQUIRE(dave.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(dave.proxied_vsf_votes_total() == + BOOST_CHECK_EQUAL(dave.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(dave.proxied_vsf_votes_total(), (sam.vesting_shares + bob.vesting_shares + alice.vesting_shares).amount); validate_database(); @@ -2347,16 +2370,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(alice.proxy == "sam"); - BOOST_REQUIRE(alice.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(bob.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(bob.proxied_vsf_votes_total().value == 0); - BOOST_REQUIRE(sam.proxy == "dave"); - BOOST_REQUIRE(sam.proxied_vsf_votes_total() == alice.vesting_shares.amount); - BOOST_REQUIRE(dave.proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT); - BOOST_REQUIRE(dave.proxied_vsf_votes_total() == + BOOST_CHECK_EQUAL(alice.proxy, "sam"); + BOOST_CHECK_EQUAL(alice.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(bob.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(bob.proxied_vsf_votes_total().value, 0); + BOOST_CHECK_EQUAL(sam.proxy, "dave"); + BOOST_CHECK_EQUAL(sam.proxied_vsf_votes_total(), alice.vesting_shares.amount); + BOOST_CHECK_EQUAL(dave.proxy, STEEMIT_PROXY_TO_SELF_ACCOUNT); + BOOST_CHECK_EQUAL(dave.proxied_vsf_votes_total(), (sam.vesting_shares + alice.vesting_shares).amount); validate_database(); @@ -2369,7 +2392,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(vote); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); tx.operations.clear(); tx.signatures.clear(); @@ -2378,9 +2401,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_witness(STEEMIT_INIT_MINER_NAME).votes == + BOOST_CHECK_EQUAL(db->get_witness(STEEMIT_INIT_MINER_NAME).votes, (alice.vesting_shares + bob.vesting_shares).amount); validate_database(); @@ -2391,9 +2414,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(db->get_witness(STEEMIT_INIT_MINER_NAME).votes == bob.vesting_shares.amount); + BOOST_CHECK_EQUAL(db->get_witness(STEEMIT_INIT_MINER_NAME).votes, bob.vesting_shares.amount); validate_database(); } FC_LOG_AND_RETHROW() From 25c3bcfe8e0c7477ffbe14193cb3fa4175854596 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 19 Jul 2018 11:16:55 +0700 Subject: [PATCH 119/250] Refactor errors: convert_operation #790 --- libraries/chain/database.cpp | 18 ++++ .../chain/include/golos/chain/database.hpp | 6 ++ libraries/chain/steem_evaluator.cpp | 9 +- .../include/golos/protocol/exceptions.hpp | 6 ++ libraries/protocol/steem_operations.cpp | 5 +- tests/tests/operation_tests.cpp | 100 ++++++++++++------ 6 files changed, 104 insertions(+), 40 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 0d92a8e97b..1a1490d457 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -699,6 +699,24 @@ namespace golos { namespace chain { return find(boost::make_tuple(name, orderid)); } + const convert_request_object &database::get_convert_request(const account_name_type &name, uint32_t id) const { + try { + return get(boost::make_tuple(name, id)); + } catch(const std::out_of_range &e) { + GOLOS_THROW_MISSING_OBJECT("convert_request", fc::mutable_variant_object()("account",name)("request_id", id)); + } FC_CAPTURE_AND_RETHROW((name)(id)) + } + + const convert_request_object *database::find_convert_request(const account_name_type &name, uint32_t id) const { + return find(boost::make_tuple(name, id)); + } + + void database::throw_if_exists_convert_request(const account_name_type &name, uint32_t id) const { + if (nullptr != find_convert_request(name, id)) { + GOLOS_THROW_OBJECT_ALREADY_EXIST("convert_request", fc::mutable_variant_object()("account",name)("request_id",id)); + } + } + const savings_withdraw_object &database::get_savings_withdraw(const account_name_type &owner, uint32_t request_id) const { try { return get(boost::make_tuple(owner, request_id)); diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 375f0a44e6..b358086711 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -185,6 +185,12 @@ namespace golos { namespace chain { const limit_order_object *find_limit_order(const account_name_type &owner, uint32_t id) const; + const convert_request_object &get_convert_request(const account_name_type &owner, uint32_t id) const; + + const convert_request_object *find_convert_request(const account_name_type &owner, uint32_t id) const; + + void throw_if_exists_convert_request(const account_name_type &owner, uint32_t id) const; + const savings_withdraw_object &get_savings_withdraw(const account_name_type &owner, uint32_t request_id) const; const savings_withdraw_object *find_savings_withdraw(const account_name_type &owner, uint32_t request_id) const; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..9bcdfb9bac 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1856,19 +1856,22 @@ namespace golos { namespace chain { void convert_evaluator::do_apply(const convert_operation &o) { database &_db = db(); const auto &owner = _db.get_account(o.owner); - FC_ASSERT(_db.get_balance(owner, o.amount.symbol) >= - o.amount, "Account does not have sufficient balance for conversion."); + GOLOS_CHECK_BALANCE(owner, MAIN_BALANCE, o.amount); _db.adjust_balance(owner, -o.amount); const auto &fhistory = _db.get_feed_history(); - FC_ASSERT(!fhistory.current_median_history.is_null(), "Cannot convert SBD because there is no price feed."); + GOLOS_CHECK_LOGIC(!fhistory.current_median_history.is_null(), + logic_exception::no_price_feed_yet, + "Cannot convert SBD because there is no price feed."); auto steem_conversion_delay = STEEMIT_CONVERSION_DELAY_PRE_HF_16; if (_db.has_hardfork(STEEMIT_HARDFORK_0_16__551)) { steem_conversion_delay = STEEMIT_CONVERSION_DELAY; } + GOLOS_CHECK_OBJECT_MISSING(_db, convert_request, o.owner, o.requestid); + _db.create([&](convert_request_object &obj) { obj.owner = o.owner; obj.requestid = o.requestid; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index ef18cc0142..3e769658ae 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -224,6 +224,9 @@ namespace golos { // feed_publish_operation price_feed_must_be_for_golos_gbg_market, + + // convert operation + no_price_feed_yet, }; }; @@ -373,6 +376,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // feed_publis_operation (price_feed_must_be_for_golos_gbg_market) + + // convert operation + (no_price_feed_yet) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..08fa63dc0d 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -461,11 +461,10 @@ namespace golos { namespace protocol { } void convert_operation::validate() const { - validate_account_name(owner); + GOLOS_CHECK_PARAM_ACCOUNT(owner); /// only allow conversion from GBG to GOLOS, allowing the opposite can enable traders to abuse /// market fluxuations through converting large quantities without moving the price. - FC_ASSERT(is_asset_type(amount, SBD_SYMBOL), "Can only convert GBG to GOLOS"); - FC_ASSERT(amount.amount > 0, "Must convert some GBG"); + GOLOS_CHECK_PARAM(amount, GOLOS_CHECK_ASSET_GT0(amount, GBG)); } void report_over_production_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e02125668e..3a6aeff91d 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -42,6 +42,11 @@ fc::variant_object make_limit_order_id(const std::string& author, uint32_t order return fc::variant_object(res); } +fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid) { + auto res = fc::mutable_variant_object()("account",account)("request_id",requestid); + return fc::variant_object(res); +} + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) @@ -2584,6 +2589,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(convert_validate) { try { BOOST_TEST_MESSAGE("Testing: convert_validate"); + convert_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.owner = "alice"; + op.amount = ASSET("10.000 GBG"); + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'owner' is empty"); + CHECK_PARAM_INVALID(op, owner, ""); + + BOOST_TEST_MESSAGE("--- failed when 'amount' is invalid"); + CHECK_PARAM_INVALID(op, amount, ASSET("10.000000 GESTS")); + CHECK_PARAM_INVALID(op, amount, ASSET("-10.000 GBG")); + + validate_database(); } FC_LOG_AND_RETHROW() } @@ -2611,28 +2631,32 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(alice_post_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with owner signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); validate_database(); } @@ -2648,7 +2672,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) convert_operation op; signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); const auto &convert_request_idx = db->get_index().indices().get(); @@ -2660,15 +2683,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) const auto &new_alice = db->get_account("alice"); const auto &new_bob = db->get_account("bob"); - BOOST_TEST_MESSAGE("--- Test failure when account does not have the required GOLOS"); + BOOST_TEST_MESSAGE("--- Test failure when account does not have the required GOLOS (invalid parameter, only GBG)"); op.owner = "bob"; op.amount = ASSET("5.000 GOLOS"); tx.operations.push_back(op); tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + // Convert operation only available for GBG + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(invalid_parameter, "amount"))); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("3.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.sbd_balance.amount.value == ASSET("7.000 GBG").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("3.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.sbd_balance.amount.value, ASSET("7.000 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when account does not have the required GBG"); @@ -2676,12 +2702,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.amount = ASSET("5.000 GBG"); tx.operations.clear(); tx.signatures.clear(); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "5.000 GBG"))); - BOOST_REQUIRE(new_alice.balance.amount.value == ASSET("7.500 GOLOS").amount.value); - BOOST_REQUIRE(new_alice.sbd_balance.amount.value == ASSET("2.500 GBG").amount.value); + BOOST_CHECK_EQUAL(new_alice.balance.amount.value, ASSET("7.500 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_alice.sbd_balance.amount.value, ASSET("2.500 GBG").amount.value); validate_database(); BOOST_TEST_MESSAGE("--- Test failure when account does not exist"); @@ -2690,7 +2719,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.signatures.clear(); tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(missing_object, "authority", "sam")); BOOST_TEST_MESSAGE("--- Test success converting GBG to GOLOS"); op.owner = "bob"; @@ -2700,37 +2730,39 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("3.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.sbd_balance.amount.value == ASSET("4.000 GBG").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("3.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.sbd_balance.amount.value, ASSET("4.000 GBG").amount.value); auto convert_request = convert_request_idx.find(std::make_tuple(op.owner, op.requestid)); - BOOST_REQUIRE(convert_request != convert_request_idx.end()); - BOOST_REQUIRE(convert_request->owner == op.owner); - BOOST_REQUIRE(convert_request->requestid == op.requestid); - BOOST_REQUIRE(convert_request->amount.amount.value == op.amount.amount.value); - //BOOST_REQUIRE( convert_request->premium == 100000 ); - BOOST_REQUIRE(convert_request->conversion_date == db->head_block_time() + STEEMIT_CONVERSION_DELAY); + BOOST_CHECK(convert_request != convert_request_idx.end()); + BOOST_CHECK_EQUAL(convert_request->owner, op.owner); + BOOST_CHECK_EQUAL(convert_request->requestid, op.requestid); + BOOST_CHECK_EQUAL(convert_request->amount.amount.value, op.amount.amount.value); + //BOOST_CHECK_EQUAL( convert_request->premium, 100000 ); + BOOST_CHECK_EQUAL(convert_request->conversion_date, db->head_block_time() + STEEMIT_CONVERSION_DELAY); BOOST_TEST_MESSAGE("--- Test failure from repeated id"); - op.amount = ASSET("2.000 GOLOS"); + op.amount = ASSET("2.000 GBG"); tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + tx.sign(bob_private_key, db->get_chain_id()); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "convert_request", make_convert_request_id("bob", 0)))); - BOOST_REQUIRE(new_bob.balance.amount.value == ASSET("3.000 GOLOS").amount.value); - BOOST_REQUIRE(new_bob.sbd_balance.amount.value == ASSET("4.000 GBG").amount.value); + BOOST_CHECK_EQUAL(new_bob.balance.amount.value, ASSET("3.000 GOLOS").amount.value); + BOOST_CHECK_EQUAL(new_bob.sbd_balance.amount.value, ASSET("4.000 GBG").amount.value); convert_request = convert_request_idx.find(std::make_tuple(op.owner, op.requestid)); - BOOST_REQUIRE(convert_request != convert_request_idx.end()); - BOOST_REQUIRE(convert_request->owner == op.owner); - BOOST_REQUIRE(convert_request->requestid == op.requestid); - BOOST_REQUIRE(convert_request->amount.amount.value == ASSET("3.000 GBG").amount.value); - //BOOST_REQUIRE( convert_request->premium == 100000 ); - BOOST_REQUIRE(convert_request->conversion_date == db->head_block_time() + STEEMIT_CONVERSION_DELAY); + BOOST_CHECK(convert_request != convert_request_idx.end()); + BOOST_CHECK_EQUAL(convert_request->owner, op.owner); + BOOST_CHECK_EQUAL(convert_request->requestid, op.requestid); + BOOST_CHECK_EQUAL(convert_request->amount.amount.value, ASSET("3.000 GBG").amount.value); + //BOOST_CHECK_EQUAL( convert_request->premium, 100000 ); + BOOST_CHECK_EQUAL(convert_request->conversion_date, db->head_block_time() + STEEMIT_CONVERSION_DELAY); validate_database(); } FC_LOG_AND_RETHROW() From 3a6524eaf8ba2929d10b6349fb0e780f2bf70c36 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 13:21:48 +0700 Subject: [PATCH 120/250] Refactor errors: custom_operation, custom_json_operation and custom_binary_operation #790 --- libraries/chain/steem_evaluator.cpp | 6 +- libraries/protocol/authority.cpp | 3 +- .../golos/protocol/validate_helper.hpp | 3 + libraries/protocol/steem_operations.cpp | 33 ++++---- tests/common/database_fixture.hpp | 11 +++ tests/tests/operation_tests.cpp | 82 ++++++++----------- 6 files changed, 73 insertions(+), 65 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..11d504d8a3 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1626,7 +1626,7 @@ namespace golos { namespace chain { } catch (const fc::exception &e) { if (d.is_producing()) { - throw e; + throw; } } catch (...) { @@ -1637,7 +1637,7 @@ namespace golos { namespace chain { void custom_binary_evaluator::do_apply(const custom_binary_operation &o) { database &d = db(); - FC_ASSERT(d.has_hardfork(STEEMIT_HARDFORK_0_14__317)); + ASSERT_REQ_HF(STEEMIT_HARDFORK_0_14__317, "custom_binary_operation"); std::shared_ptr eval = d.get_custom_json_evaluator(o.id); if (!eval) { @@ -1649,7 +1649,7 @@ namespace golos { namespace chain { } catch (const fc::exception &e) { if (d.is_producing()) { - throw e; + throw; } } catch (...) { diff --git a/libraries/protocol/authority.cpp b/libraries/protocol/authority.cpp index d6d4e415f0..a28e49066c 100644 --- a/libraries/protocol/authority.cpp +++ b/libraries/protocol/authority.cpp @@ -1,4 +1,5 @@ #include +#include namespace golos { namespace protocol { @@ -43,7 +44,7 @@ namespace golos { void authority::validate() const { for (const auto &item : account_auths) { - FC_ASSERT(is_valid_account_name(item.first)); + GOLOS_CHECK_VALUE(is_valid_account_name(item.first), "Account name \"${account}\" is invalid", ("account",item.first)); } } diff --git a/libraries/protocol/include/golos/protocol/validate_helper.hpp b/libraries/protocol/include/golos/protocol/validate_helper.hpp index 99ee2f36f1..c3d25736ce 100644 --- a/libraries/protocol/include/golos/protocol/validate_helper.hpp +++ b/libraries/protocol/include/golos/protocol/validate_helper.hpp @@ -27,6 +27,9 @@ // utf-8 #define GOLOS_CHECK_VALUE_UTF8(F) \ GOLOS_CHECK_VALUE(fc::is_utf8(F), MUST_BE(F, "valid UTF8 string")); +// JSON +#define GOLOS_CHECK_VALUE_JSON(F) \ + GOLOS_CHECK_VALUE(fc::json::is_valid(json), MUST_BE(F, "valid JSON")) // compare field with value diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..af85033c68 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -269,29 +269,32 @@ namespace golos { namespace protocol { void custom_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed - FC_ASSERT(required_auths.size() > - 0, "at least on account must be specified"); + GOLOS_CHECK_PARAM(required_auths, + GOLOS_CHECK_VALUE(required_auths.size() > 0, "at least one account must be specified")); } void custom_json_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed - FC_ASSERT((required_auths.size() + required_posting_auths.size()) > - 0, "at least on account must be specified"); - FC_ASSERT(id.size() <= 32, "id is too long"); - FC_ASSERT(fc::is_utf8(json), "JSON Metadata not formatted in UTF8"); - FC_ASSERT(fc::json::is_valid(json), "JSON Metadata not valid JSON"); + GOLOS_CHECK_PARAM(required_auths, + GOLOS_CHECK_VALUE((required_auths.size() + required_posting_auths.size()) > 0, "at least on account must be specified")); + GOLOS_CHECK_PARAM(id, GOLOS_CHECK_VALUE_MAX_SIZE(id, 32)); + GOLOS_CHECK_PARAM(json, { + GOLOS_CHECK_VALUE_UTF8(json); + GOLOS_CHECK_VALUE_JSON(json); + }); } void custom_binary_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed - FC_ASSERT((required_owner_auths.size() + - required_active_auths.size() + - required_posting_auths.size()) > - 0, "at least on account must be specified"); - FC_ASSERT(id.size() <= 32, "id is too long"); - for (const auto &a : required_auths) { - a.validate(); - } + GOLOS_CHECK_PARAM(required_owner_auths, + GOLOS_CHECK_VALUE((required_owner_auths.size() + required_active_auths.size() + required_posting_auths.size()) > 0, + "at least one account must be specified")); + GOLOS_CHECK_PARAM(id, GOLOS_CHECK_VALUE_MAX_SIZE(id, 32)); + GOLOS_CHECK_PARAM(required_auths, { + for (const auto &a : required_auths) { + a.validate(); + } + }); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 1bf74e1893..ae2dd97ada 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -343,6 +343,17 @@ std::ostream& operator<<(std::ostream& out, const std::pair& v) { return out; } +template +std::ostream& operator<<(std::ostream& out, const std::vector &vec) { + out << "("; + if (!vec.empty()) { + std::for_each(vec.begin(), vec.end()-1, [&](const T& v) {out << v << ",";}); + out << *vec.rbegin(); + } + out << ")"; + return out; +} + } // std diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e02125668e..0bc972b81d 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2377,77 +2377,67 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) custom_operation op; op.required_auths.insert("alice"); op.required_auths.insert("bob"); - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - expected.insert("alice"); - expected.insert("bob"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice","bob"}), account_name_set()); } BOOST_AUTO_TEST_CASE(custom_json_authorities) { custom_json_operation op; op.required_auths.insert("alice"); op.required_posting_auths.insert("bob"); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set({"bob"})); + } - flat_set auths; - flat_set expected; + BOOST_AUTO_TEST_CASE(custom_json_validate) { + custom_json_operation op; - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "required_auths")); - expected.insert("alice"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); + op.required_auths.insert("alice"); + op.id = "id"; + op.json = "{}"; + CHECK_OP_VALID(op); - auths.clear(); - expected.clear(); - expected.insert("bob"); - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); + CHECK_PARAM_INVALID(op, id, std::string(33, 's')); + CHECK_PARAM_INVALID(op, json, "{]"); } BOOST_AUTO_TEST_CASE(custom_binary_authorities) { ACTORS((alice)) + auto alice_authority = db->get("alice").posting; + custom_binary_operation op; op.required_owner_auths.insert("alice"); op.required_active_auths.insert("bob"); op.required_posting_auths.insert("sam"); - op.required_auths.push_back(db->get("alice").posting); + op.required_auths.push_back(alice_authority); + + CHECK_OP_AUTHS(op, account_name_set({"alice"}), account_name_set({"bob"}), account_name_set({"sam"})); - flat_set acc_auths; - flat_set acc_expected; + vector expected = {alice_authority}; vector auths; - vector expected; + op.get_required_authorities(auths); + BOOST_CHECK_EQUAL(auths, expected); + } - acc_expected.insert("alice"); - op.get_required_owner_authorities(acc_auths); - BOOST_REQUIRE(acc_auths == acc_expected); + BOOST_AUTO_TEST_CASE(custom_binary_validate) { + custom_binary_operation op; - acc_auths.clear(); - acc_expected.clear(); - acc_expected.insert("bob"); - op.get_required_active_authorities(acc_auths); - BOOST_REQUIRE(acc_auths == acc_expected); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "required_owner_auths")); - acc_auths.clear(); - acc_expected.clear(); - acc_expected.insert("sam"); - op.get_required_posting_authorities(acc_auths); - BOOST_REQUIRE(acc_auths == acc_expected); + op.required_active_auths.insert("alice"); + op.id = "id"; + CHECK_OP_VALID(op); - expected.push_back(db->get("alice").posting); - op.get_required_authorities(auths); - BOOST_REQUIRE(auths == expected); + CHECK_PARAM_INVALID(op, id, std::string(33, 's')); + + authority auth; + auth.add_authority("a", 1); + op.required_auths.push_back(auth); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "required_auths")); } BOOST_AUTO_TEST_CASE(feed_publish_validate) { From 8941104370acbf19e150dbf2bcecfa0f78abfa34 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 09:44:03 +0300 Subject: [PATCH 121/250] Refactor errors: fix proposal tests #790 --- tests/tests/proposal_tests.cpp | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index c3d1bb4747..f0f0656829 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -33,6 +33,7 @@ using std::string; BOOST_FIXTURE_TEST_SUITE(proposal_tests, clean_database_fixture) +// validate + authority tests BOOST_AUTO_TEST_CASE(proposal_create_validate) { try { BOOST_TEST_MESSAGE("Testing: proposal_create_validate"); @@ -80,7 +81,7 @@ BOOST_AUTO_TEST_CASE(proposal_create_validate) { try { t2.amount = ASSET_GESTS(1.0); ops.push_back(operation_wrapper(t2)); // validation fails inside internal transaction, so error contains "amount" field - CHECK_PARAM_VALIDATION_FAIL(op, proposed_operations, ops, + CHECK_PARAM_VALIDATION_FAIL(op, proposed_operations, ops, CHECK_ERROR(invalid_parameter, "amount")); } FC_LOG_AND_RETHROW() } @@ -92,7 +93,6 @@ BOOST_AUTO_TEST_CASE(proposal_create_authorities) { try { op.title = "test"; using account_name_set = flat_set; CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); - } FC_LOG_AND_RETHROW() } @@ -203,15 +203,12 @@ BOOST_AUTO_TEST_CASE(proposal_delete_authorities) { try { op.requester = "bob"; op.author = "alice"; op.title = "test"; - using account_name_set = flat_set; - account_name_set auths; CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); - } FC_LOG_AND_RETHROW() } - +// apply tests BOOST_AUTO_TEST_CASE(create_proposal) { try { BOOST_TEST_MESSAGE("Testing: proposal_create_operation"); @@ -244,7 +241,8 @@ BOOST_AUTO_TEST_CASE(create_proposal) { try { cop.proposed_operations.push_back(operation_wrapper(vop)); GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, cop), - CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::tx_with_both_posting_active_ops))); + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::tx_with_both_posting_active_ops))); BOOST_TEST_MESSAGE("--- Simple proposal with a transfer operation"); @@ -449,7 +447,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { push_tx_with_ops(tx, alice_private_key, uop11); generate_blocks(1); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); } FC_LOG_AND_RETHROW() } @@ -484,7 +482,7 @@ BOOST_AUTO_TEST_CASE(update_proposal1) { try { push_tx_with_ops(tx, alice_private_key, uop); generate_blocks(1); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -521,7 +519,7 @@ BOOST_AUTO_TEST_CASE(update_proposal2) { try { push_tx_with_ops(tx, alice_private_key, uop); generate_blocks(1); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -569,7 +567,7 @@ BOOST_AUTO_TEST_CASE(update_proposal3) { try { generate_blocks(p.expiration_time); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); BOOST_CHECK_EQUAL(db->get_account("alice").balance.amount.value, 7500); BOOST_CHECK_EQUAL(db->get_account("bob").balance.amount.value, 2500); @@ -608,15 +606,13 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { generate_blocks(1); }; - auto get_active = [&](const std::string& name) { + auto get_active = [&](const string& name) { return authority(db->get(name).active); }; - - auto get_owner = [&](const std::string& name) { + auto get_owner = [&](const string& name) { return authority(db->get(name).owner); }; - - auto get_posting = [&](const std::string& name) { + auto get_posting = [&](const string& name) { return authority(db->get(name).posting); }; @@ -724,7 +720,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop3.title = cop.title; uop3.key_approvals_to_add.insert(dave_public_key); GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, dave_private_key, uop3), - CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(tx_irrelevant_sig, 0))); // !!!TODO + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(tx_irrelevant_sig, 0))); proposal_update_operation uop4; uop4.author = cop.author; @@ -733,7 +729,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { push_tx_with_ops(tx, dan_private_key, uop4); generate_blocks(1); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); BOOST_CHECK_EQUAL(poxx_account.balance.amount.value, 7500); BOOST_CHECK_EQUAL(edy_account.balance.amount.value, 2500); @@ -783,7 +779,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { push_tx_with_ops(tx, alice_private_key, dop1); generate_blocks(1); - GOLOS_CHECK_OBJECT_MISSING((*db), proposal, cop.author, cop.title); + BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); } FC_LOG_AND_RETHROW() } From 020332301e4e5f97b4fe4643ba8ab9f3a74b3a84 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 13:50:03 +0700 Subject: [PATCH 122/250] Refactor errors: report_over_production_operation #790 --- libraries/chain/steem_evaluator.cpp | 4 +++- libraries/protocol/steem_operations.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..3fcc42ac82 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1947,7 +1947,9 @@ namespace golos { namespace chain { void report_over_production_evaluator::do_apply(const report_over_production_operation &o) { database &_db = db(); - FC_ASSERT(!_db.has_hardfork(STEEMIT_HARDFORK_0_4), "report_over_production_operation is disabled."); + if (_db.has_hardfork(STEEMIT_HARDFORK_0_4)) { + FC_THROW_EXCEPTION(golos::unsupported_operation, "report_over_production_operation is disabled"); + } } void challenge_authority_evaluator::do_apply(const challenge_authority_operation &o) { diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..739a57e3db 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -469,12 +469,14 @@ namespace golos { namespace protocol { } void report_over_production_operation::validate() const { - validate_account_name(reporter); - validate_account_name(first_block.witness); - FC_ASSERT(first_block.witness == second_block.witness); - FC_ASSERT(first_block.timestamp == second_block.timestamp); - FC_ASSERT(first_block.signee() == second_block.signee()); - FC_ASSERT(first_block.id() != second_block.id()); + GOLOS_CHECK_PARAM_ACCOUNT(reporter); + GOLOS_CHECK_PARAM_ACCOUNT(first_block.witness); + GOLOS_CHECK_PARAM(first_block, { + GOLOS_CHECK_VALUE(first_block.witness == second_block.witness, "Witness for first and second blocks must be equal"); + GOLOS_CHECK_VALUE(first_block.timestamp == second_block.timestamp, "Timestamp for first and second blocks must be equal"); + GOLOS_CHECK_VALUE(first_block.signee() == second_block.signee(), "Signee for first and second blocks must be equal"); + GOLOS_CHECK_VALUE(first_block.id() != second_block.id(), "ID for first and second blocks must be different"); + }); } void escrow_transfer_operation::validate() const { From 383e1b1751b7f6cc1c4a205822d643190092b24f Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 10:07:43 +0300 Subject: [PATCH 123/250] Refactor errors: delegate_vesting_shares #790 --- libraries/chain/steem_evaluator.cpp | 41 ++-- .../include/golos/protocol/exceptions.hpp | 12 ++ .../golos/protocol/validate_helper.hpp | 9 +- libraries/protocol/steem_operations.cpp | 10 +- tests/common/database_fixture.hpp | 38 ++-- tests/tests/operation_tests.cpp | 187 ++++++++---------- 6 files changed, 149 insertions(+), 148 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..0171ef8a04 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2243,8 +2243,6 @@ namespace golos { namespace chain { } void delegate_vesting_shares_evaluator::do_apply(const delegate_vesting_shares_operation& op) { - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_18__535, "delegate_vesting_shares_operation"); //TODO: Delete after hardfork - const auto& delegator = _db.get_account(op.delegator); const auto& delegatee = _db.get_account(op.delegatee); auto delegation = _db.find(std::make_tuple(op.delegator, op.delegatee)); @@ -2260,31 +2258,37 @@ namespace golos { namespace chain { op.vesting_shares; auto increasing = delta.amount > 0; - FC_ASSERT((increasing ? delta : -delta) >= min_update, - "Delegation difference is not enough. min_update: ${min}", ("min", min_update)); + GOLOS_CHECK_OP_PARAM(op, vesting_shares, { + GOLOS_CHECK_LOGIC((increasing ? delta : -delta) >= min_update, + logic_exception::delegation_difference_too_low, + "Delegation difference is not enough. min_update: ${min}", ("min", min_update)); #ifdef STEEMIT_BUILD_TESTNET - // min_update depends on account_creation_fee, which can be 0 on testnet - FC_ASSERT(delta.amount != 0, "Delegation difference can't be 0"); + // min_update depends on account_creation_fee, which can be 0 on testnet + GOLOS_CHECK_LOGIC(delta.amount != 0, + logic_exception::delegation_difference_too_low, + "Delegation difference can't be 0"); #endif + }); if (increasing) { auto delegated = delegator.delegated_vesting_shares; - FC_ASSERT(delegator.available_vesting_shares(true) >= delta, - "Account does not have enough vesting shares to delegate.", - ("available", delegator.available_vesting_shares(true)) - ("delta", delta)("vesting_shares", delegator.vesting_shares)("delegated", delegated) - ("to_withdraw", delegator.to_withdraw)("withdrawn", delegator.withdrawn)); + GOLOS_CHECK_BALANCE(delegator, AVAILABLE_VESTING, delta); auto elapsed_seconds = (now - delegator.last_vote_time).to_seconds(); auto regenerated_power = (STEEMIT_100_PERCENT * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; auto current_power = std::min(delegator.voting_power + regenerated_power, STEEMIT_100_PERCENT); auto max_allowed = delegator.vesting_shares * current_power / STEEMIT_100_PERCENT; - FC_ASSERT(delegated + delta <= max_allowed, + GOLOS_CHECK_LOGIC(delegated + delta <= max_allowed, + logic_exception::delegation_limited_by_voting_power, "Account allowed to delegate a maximum of ${v} with current voting power = ${p}", ("v",max_allowed)("p",current_power)("delegated",delegated)("delta",delta)); if (!delegation) { - FC_ASSERT(op.vesting_shares >= min_delegation, - "Account must delegate a minimum of ${v}", ("v",min_delegation)("vesting_shares",op.vesting_shares)); + GOLOS_CHECK_OP_PARAM(op, vesting_shares, { + GOLOS_CHECK_LOGIC(op.vesting_shares >= min_delegation, + logic_exception::cannot_delegate_below_minimum, + "Account must delegate a minimum of ${v}", + ("v",min_delegation)("vesting_shares",op.vesting_shares)); + }); _db.create([&](vesting_delegation_object& o) { o.delegator = op.delegator; o.delegatee = op.delegatee; @@ -2296,9 +2300,12 @@ namespace golos { namespace chain { a.delegated_vesting_shares += delta; }); } else { - FC_ASSERT(op.vesting_shares.amount == 0 || op.vesting_shares >= min_delegation, - "Delegation must be removed or leave minimum delegation amount of ${v}", - ("v",min_delegation)("vesting_shares",op.vesting_shares)); + GOLOS_CHECK_OP_PARAM(op, vesting_shares, { + GOLOS_CHECK_LOGIC(op.vesting_shares.amount == 0 || op.vesting_shares >= min_delegation, + logic_exception::cannot_delegate_below_minimum, + "Delegation must be removed or leave minimum delegation amount of ${v}", + ("v",min_delegation)("vesting_shares",op.vesting_shares)); + }); _db.create([&](vesting_delegation_expiration_object& o) { o.delegator = op.delegator; o.vesting_shares = -delta; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index ef18cc0142..60fadcb81e 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -206,6 +206,12 @@ namespace golos { //account_create_with_delegation not_enough_delegation, + //delegate_vesting_shares + cannot_delegate_to_yourself, + delegation_difference_too_low, + delegation_limited_by_voting_power, + cannot_delegate_below_minimum, + //proposals proposal_depth_too_high, tx_with_both_posting_active_ops, @@ -352,6 +358,12 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) + //delegate_vesting_shares + (cannot_delegate_to_yourself) + (delegation_difference_too_low) + (delegation_limited_by_voting_power) + (cannot_delegate_below_minimum) + //account_create_with_delegation (not_enough_delegation) diff --git a/libraries/protocol/include/golos/protocol/validate_helper.hpp b/libraries/protocol/include/golos/protocol/validate_helper.hpp index 99ee2f36f1..0a0898c07b 100644 --- a/libraries/protocol/include/golos/protocol/validate_helper.hpp +++ b/libraries/protocol/include/golos/protocol/validate_helper.hpp @@ -21,12 +21,15 @@ // size #define GOLOS_CHECK_VALUE_MAX_SIZE(F, M) \ - GOLOS_CHECK_VALUE(F.size() <= M, MUST_BE2(F, "is too long", "<= " FC_STRINGIZE(M))); + GOLOS_CHECK_VALUE(F.size() <= (M), MUST_BE2(F, "is too long", "<= " FC_STRINGIZE(M))); #define GOLOS_CHECK_VALUE_NOT_EMPTY(F) \ GOLOS_CHECK_VALUE(!F.empty(), CANNOT_BE(F, "empty")); // utf-8 #define GOLOS_CHECK_VALUE_UTF8(F) \ GOLOS_CHECK_VALUE(fc::is_utf8(F), MUST_BE(F, "valid UTF8 string")); +// json +#define GOLOS_CHECK_VALUE_JSON(F) \ + GOLOS_CHECK_VALUE(fc::json::is_valid(F), MUST_BE(F, "valid JSON")); // compare field with value @@ -36,7 +39,7 @@ #define GOLOS_CHECK_VALUE_GE(F, X) GOLOS_CHECK_VALUE_I(F, >=, X) #define GOLOS_CHECK_VALUE_LE(F, X) GOLOS_CHECK_VALUE_I(F, <=, X) #define GOLOS_CHECK_VALUE_LEGE(F, L, H) \ - GOLOS_CHECK_VALUE(L <= F && F <= H , MUST_BE(F, "between " FC_STRINGIZE(L) " and" FC_STRINGIZE(H))) + GOLOS_CHECK_VALUE((L) <= F && F <= (H) , MUST_BE(F, "between " FC_STRINGIZE(L) " and" FC_STRINGIZE(H))) // check asset type #define GOLOS_CHECK_ASSET_TYPE(X, NAME) GOLOS_CHECK_ASSET_##NAME(X); @@ -58,7 +61,7 @@ // fields #define GOLOS_CHECK_VALUE_I(F, OP, X) GOLOS_CHECK_VALUE_II(F, OP, X, F) -#define GOLOS_CHECK_VALUE_II(F, OP, X, N) GOLOS_CHECK_VALUE(F OP X, MUST_BE(N, "" #OP FC_STRINGIZE(X))) +#define GOLOS_CHECK_VALUE_II(F, OP, X, N) GOLOS_CHECK_VALUE(F OP (X), MUST_BE(N, "" #OP FC_STRINGIZE(X))) // asset type #define GOLOS_CHECK_ASSET_TYPE_I(X, SYMBOL, SNAME) GOLOS_CHECK_VALUE(X.symbol == SYMBOL, MUST_BE(X, SNAME)) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..61d1fc81ba 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -614,11 +614,11 @@ namespace golos { namespace protocol { } void delegate_vesting_shares_operation::validate() const { - validate_account_name(delegator); - validate_account_name(delegatee); - FC_ASSERT(delegator != delegatee, "You cannot delegate GESTS to yourself"); - FC_ASSERT(is_asset_type(vesting_shares, VESTS_SYMBOL), "Delegation must be GESTS"); - FC_ASSERT(vesting_shares.amount >= 0, "Delegation cannot be negative"); + GOLOS_CHECK_PARAM_ACCOUNT(delegator); + GOLOS_CHECK_PARAM_ACCOUNT(delegatee); + GOLOS_CHECK_LOGIC(delegator != delegatee, logic_exception::cannot_delegate_to_yourself, + "You cannot delegate GESTS to yourself"); + GOLOS_CHECK_PARAM(vesting_shares, GOLOS_CHECK_ASSET_GE0(vesting_shares, GESTS)); } } } // golos::protocol diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 1bf74e1893..def694b05f 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -4,17 +4,14 @@ #include #include #include - #include - -#include -#include - #include #include #include #include +#include +#include #include @@ -80,7 +77,7 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); << req_throw_info << std::endl; \ } -#define GOLOS_CHECK_THROW_PROPS_IMPL( S, E, C, TL ) \ +#define GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, TL) \ try { \ BOOST_TEST_PASSPOINT(); \ S; \ @@ -98,10 +95,10 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); try { \ throw; \ } catch (const fc::exception& ex) { \ - BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ + BOOST_##TL( "exception '" BOOST_STRINGIZE( E ) "' is expected, " \ "but '" << ex.name() << "' is caught"); \ } catch (...) { \ - BOOST_##TL( "exception " BOOST_STRINGIZE( E ) " is expected, " \ + BOOST_##TL( "exception " BOOST_STRINGIZE( E ) " is expected, " \ "but unknown is caught"); \ } \ } \ @@ -110,14 +107,14 @@ extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); #define GOLOS_CHECK_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, ERROR) #define GOLOS_REQUIRE_THROW_PROPS(S, E, C) GOLOS_CHECK_THROW_PROPS_IMPL(S, E, C, FAIL) -#define GOLOS_CHECK_NO_THROW_IMPL( S, TL ) \ +#define GOLOS_CHECK_NO_THROW_IMPL(S, TL) \ try { \ BOOST_TEST_PASSPOINT(); \ S; \ - } catch( fc::exception const& ex ) { \ + } catch(fc::exception const& ex) { \ BOOST_##TL("no exception expected, but '" << ex.name() << "' thrown: \n" << \ ex.to_detail_string()); \ - } catch ( ... ) { \ + } catch (...) { \ BOOST_##TL("no exception expected, but unknown exception thrown"); \ } @@ -130,11 +127,10 @@ struct ErrorValidator {}; using ErrorValidateFunc = std::function; -#define CHECK_ERROR(exception, ...) [&](const std::string& name, const fc::variant& props) \ - {\ - ErrorValidator v; \ - v.validate(name, props, __VA_ARGS__); \ - } +#define CHECK_ERROR(exception, ...) [&](const std::string& name, const fc::variant& props) {\ + ErrorValidator v; \ + v.validate(name, props, __VA_ARGS__); \ +} template<> struct ErrorValidator { @@ -154,6 +150,13 @@ struct ErrorValidator { BOOST_CHECK_EQUAL(props["balance"].get_string(), balance); BOOST_CHECK_EQUAL(props["required"].get_string(), amount); } + void validate(const std::string& name, const fc::variant& props, + const std::string& account, const std::string& balance, const golos::protocol::asset& amount) { + BOOST_CHECK_EQUAL(name, "insufficient_funds"); + BOOST_CHECK_EQUAL(props["account"].get_string(), account); + BOOST_CHECK_EQUAL(props["balance"].get_string(), balance); + BOOST_CHECK_EQUAL(props["required"].get_string(), amount.to_string()); + } }; template<> @@ -243,7 +246,7 @@ SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_owner_auth); SIMPLE_PROTOCOL_ERROR_VALIDATOR(tx_missing_other_auth); -#define GOLOS_CHECK_ERROR_PROPS_IMPL( S, C, TL ) \ +#define GOLOS_CHECK_ERROR_PROPS_IMPL(S, C, TL) \ GOLOS_CHECK_THROW_PROPS_IMPL(S, golos::golos_exception, C(ex.name(), ex.get_log().at(0).get_data()), TL) #define GOLOS_WARN_ERROR_PROPS(S, C) GOLOS_CHECK_ERROR_PROPS_IMPL(S, C, WARN) @@ -602,7 +605,6 @@ namespace golos { namespace chain { plugin_type* _plg; fc::flat_set _account_names; - //fc::flat_map _added_accounts; }; namespace test { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index bf6177f8bc..6e49a11542 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -110,7 +110,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); @@ -124,20 +124,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(init_account_priv_key, db->get_chain_id()); tx.sign(init_account_priv_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(init_account_priv_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); } @@ -1256,26 +1256,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with witness signature"); @@ -1320,14 +1320,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.sign(alice_private_key, db->get_chain_id()); signature_type alice_sig = tx.signatures.back(); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); tx.sign(bob_private_key, db->get_chain_id()); signature_type bob_sig = tx.signatures.back(); tx.sign(sam_private_key, db->get_chain_id()); signature_type sam_sig = tx.signatures.back(); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_irrelevant_sig, 0)); tx.signatures.clear(); @@ -1494,26 +1494,26 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the account's authority"); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test success with from signature"); @@ -1614,7 +1614,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failed when 'account' is empty"); op.account = ""; - GOLOS_CHECK_ERROR_PROPS(op.validate(), + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "account")); BOOST_TEST_MESSAGE("--- failed when 'vesting_shares' not in GESTS"); @@ -1659,20 +1659,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); @@ -2785,7 +2785,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); @@ -2794,20 +2794,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); @@ -3213,7 +3213,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); @@ -3222,20 +3222,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); @@ -3643,7 +3643,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); BOOST_TEST_MESSAGE("--- Test failure when no signature."); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); BOOST_TEST_MESSAGE("--- Test success with account signature"); @@ -3652,20 +3652,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test failure with duplicate signature"); tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_duplicate_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with additional incorrect signature"); tx.signatures.clear(); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_irrelevant_sig, 0)); BOOST_TEST_MESSAGE("--- Test failure with incorrect signature"); tx.signatures.clear(); tx.sign(alice_post_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, database::skip_transaction_dupe_check), CHECK_ERROR(tx_missing_active_auth, 0)); validate_database(); @@ -6946,18 +6946,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) delegate_vesting_shares_operation op; op.delegator = "alice"; op.delegatee = "bob"; + op.vesting_shares = ASSET_GESTS(1e6); + BOOST_TEST_MESSAGE("--- Test success under normal conditions"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, vesting_shares, ASSET_GESTS(0)); + BOOST_TEST_MESSAGE("--- Test failure when delegate negative amount"); - op.vesting_shares = ASSET_GESTS(-1); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID(op, vesting_shares, ASSET_GESTS(-1)); BOOST_TEST_MESSAGE("--- Test failure when delegate to same acc"); - op.delegator = "bob"; - op.vesting_shares = ASSET_GESTS(1e6); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + CHECK_PARAM_INVALID_LOGIC(op, delegator, "bob", logic_exception::cannot_delegate_to_yourself); - BOOST_TEST_MESSAGE("--- Test success under normal conditions"); - op.delegator = "alice"; - op.validate(); + BOOST_TEST_MESSAGE("--- Test failure when account not set"); + CHECK_PARAM_INVALID(op, delegator, ""); + CHECK_PARAM_INVALID(op, delegatee, ""); } FC_LOG_AND_RETHROW() } @@ -6965,42 +6967,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(delegate_vesting_shares_authorities) { try { BOOST_TEST_MESSAGE("Testing: delegate_vesting_shares_authorities"); - signed_transaction tx; - ACTORS((alice)(bob)) - generate_blocks(1); - vest("alice", ASSET_GOLOS(10000)); - delegate_vesting_shares_operation op; - op.vesting_shares = ASSET_GESTS(300); - op.delegator = "alice"; - op.delegatee = "bob"; - - BOOST_TEST_MESSAGE("--- Test failure when no signatures"); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(op); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); - - BOOST_TEST_MESSAGE("--- Test success with delegator signature"); - sign(tx, alice_private_key); - db->push_transaction(tx, 0); - - BOOST_TEST_MESSAGE("--- Test failure when duplicate signatures"); - op.delegatee = "sam"; - sign_tx_with_ops(tx, alice_private_key, op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_duplicate_sig); - - BOOST_TEST_MESSAGE("--- Test failure when signed by an additional signature not in the creator's authority"); - tx.signatures.clear(); - tx.sign(init_account_priv_key, db->get_chain_id()); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_irrelevant_sig); - - BOOST_TEST_MESSAGE("--- Test failure when signed by a signature not in the creator's authority"); - tx.signatures.clear(); - tx.sign(init_account_priv_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), tx_missing_active_auth); - validate_database(); + op.delegator = "bob"; + op.delegatee = "alice"; + op.vesting_shares = ASSET_GESTS(1e6); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -7030,25 +7001,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) generate_blocks(1); const auto& alice_acc = db->get_account("alice"); const auto& bob_acc = db->get_account("bob"); - BOOST_REQUIRE(alice_acc.delegated_vesting_shares == ASSET_GESTS(1e6)); - BOOST_REQUIRE(bob_acc.received_vesting_shares == ASSET_GESTS(1e6)); + BOOST_CHECK_EQUAL(alice_acc.delegated_vesting_shares, ASSET_GESTS(1e6)); + BOOST_CHECK_EQUAL(bob_acc.received_vesting_shares, ASSET_GESTS(1e6)); BOOST_TEST_MESSAGE("--- Test that the delegation object is correct"); auto delegation = db->find(std::make_tuple(op.delegator, op.delegatee)); - BOOST_REQUIRE(delegation != nullptr); - BOOST_REQUIRE(delegation->delegator == op.delegator); - BOOST_REQUIRE(delegation->delegatee == op.delegatee); - BOOST_REQUIRE(delegation->vesting_shares == ASSET_GESTS(1e6)); + BOOST_CHECK(delegation != nullptr); + BOOST_CHECK_EQUAL(delegation->delegator, op.delegator); + BOOST_CHECK_EQUAL(delegation->delegatee, op.delegatee); + BOOST_CHECK_EQUAL(delegation->vesting_shares, ASSET_GESTS(1e6)); validate_database(); BOOST_TEST_MESSAGE("--- Test delegation change"); op.vesting_shares = ASSET_GESTS(2e7); push_tx_with_ops(tx, alice_private_key, op); generate_blocks(1); - BOOST_REQUIRE(delegation != nullptr); - BOOST_REQUIRE(delegation->vesting_shares == ASSET_GESTS(2e7)); - BOOST_REQUIRE(alice_acc.delegated_vesting_shares == ASSET_GESTS(2e7)); - BOOST_REQUIRE(bob_acc.received_vesting_shares == ASSET_GESTS(2e7)); + BOOST_CHECK(delegation != nullptr); + BOOST_CHECK_EQUAL(delegation->vesting_shares, ASSET_GESTS(2e7)); + BOOST_CHECK_EQUAL(alice_acc.delegated_vesting_shares, ASSET_GESTS(2e7)); + BOOST_CHECK_EQUAL(bob_acc.received_vesting_shares, ASSET_GESTS(2e7)); // TODO: test min delta evaluator logic @@ -7075,16 +7046,17 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto itr = vote_idx.find(std::make_tuple(alice_comment.id, bob_acc.id)); auto rshares = bob_acc.effective_vesting_shares().amount.value * (old_voting_power - bob_acc.voting_power) / STEEMIT_100_PERCENT; - BOOST_REQUIRE(rshares == itr->rshares); - BOOST_REQUIRE(rshares == alice_comment.net_rshares.value); + BOOST_CHECK_EQUAL(rshares, itr->rshares); + BOOST_CHECK_EQUAL(rshares, alice_comment.net_rshares.value); BOOST_TEST_MESSAGE("--- Test that delegation limited by current voting power"); auto max_allowed = bob_acc.vesting_shares * bob_acc.voting_power / STEEMIT_100_PERCENT; op.delegator = "bob"; op.delegatee = "alice"; op.vesting_shares = asset(max_allowed.amount + 1, VESTS_SYMBOL); - sign_tx_with_ops(tx, bob_private_key, op); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::delegation_limited_by_voting_power))); op.vesting_shares = max_allowed; push_tx_with_ops(tx, bob_private_key, op); @@ -7100,13 +7072,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = ASSET_GESTS(0); op.delegator = "sam"; op.delegatee = "dave"; - sign_tx_with_ops(tx, sam_private_key, op); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::delegation_difference_too_low))); BOOST_TEST_MESSAGE("--- Test failure delegating more vesting shares than account has"); op.vesting_shares = asset(sam_vest.amount + 1, VESTS_SYMBOL); - sign_tx_with_ops(tx, sam_private_key, op); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "sam", "available vesting shares", op.vesting_shares))); BOOST_TEST_MESSAGE("--- Test failure delegating vesting shares that are part of a power down"); sam_vest = asset(sam_vest.amount / 2, VESTS_SYMBOL); @@ -7115,11 +7089,12 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) withdraw.vesting_shares = sam_vest; op.vesting_shares = asset(sam_vest.amount + 2, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, withdraw); - sign_tx_with_ops(tx, sam_private_key, op); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "sam", "available vesting shares", op.vesting_shares))); BOOST_TEST_MESSAGE("--- Test available_vesting_shares calculation with active power down"); - BOOST_REQUIRE(sam_acc.available_vesting_shares(true) == + BOOST_CHECK_EQUAL(sam_acc.available_vesting_shares(true), sam_acc.vesting_shares - sam_acc.delegated_vesting_shares - asset(sam_acc.to_withdraw, VESTS_SYMBOL)); withdraw.vesting_shares = ASSET_GESTS(0); @@ -7130,8 +7105,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = sam_vest; withdraw.vesting_shares = asset(sam_vest.amount, VESTS_SYMBOL); push_tx_with_ops(tx, sam_private_key, op); - sign_tx_with_ops(tx, sam_private_key, withdraw); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, withdraw), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "sam", "having vesting shares", sam_vest))); BOOST_TEST_MESSAGE("--- Remove a delegation and ensure it is returned after 1 week"); op.vesting_shares = ASSET_GESTS(0); @@ -7139,26 +7115,27 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) auto exp_obj = db->get_index().begin(); auto end = db->get_index().end(); - BOOST_REQUIRE(exp_obj != end); - BOOST_REQUIRE(exp_obj->delegator == "sam"); - BOOST_REQUIRE(exp_obj->vesting_shares == sam_vest); - BOOST_REQUIRE(exp_obj->expiration == db->head_block_time() + STEEMIT_CASHOUT_WINDOW_SECONDS); - BOOST_REQUIRE(db->get_account("sam").delegated_vesting_shares == sam_vest); - BOOST_REQUIRE(db->get_account("dave").received_vesting_shares == ASSET_GESTS(0)); + BOOST_CHECK(exp_obj != end); + BOOST_CHECK_EQUAL(exp_obj->delegator, "sam"); + BOOST_CHECK_EQUAL(exp_obj->vesting_shares, sam_vest); + BOOST_CHECK_EQUAL(exp_obj->expiration, db->head_block_time() + STEEMIT_CASHOUT_WINDOW_SECONDS); + BOOST_CHECK_EQUAL(db->get_account("sam").delegated_vesting_shares, sam_vest); + BOOST_CHECK_EQUAL(db->get_account("dave").received_vesting_shares, ASSET_GESTS(0)); delegation = db->find(std::make_tuple(op.delegator, op.delegatee)); - BOOST_REQUIRE(delegation == nullptr); + BOOST_CHECK(delegation == nullptr); generate_blocks(exp_obj->expiration + STEEMIT_BLOCK_INTERVAL); exp_obj = db->get_index().begin(); end = db->get_index().end(); - BOOST_REQUIRE(exp_obj == end); - BOOST_REQUIRE(db->get_account("sam").delegated_vesting_shares == ASSET_GESTS(0)); + BOOST_CHECK(exp_obj == end); + BOOST_CHECK_EQUAL(db->get_account("sam").delegated_vesting_shares, ASSET_GESTS(0)); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() // delegation + BOOST_AUTO_TEST_SUITE(account_metadata) BOOST_AUTO_TEST_CASE(account_metadata_validate) { From 7aeec5c6abe8c03ae21e27dc30e52a761d4fffee Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 15:21:15 +0700 Subject: [PATCH 124/250] Refactor errors: delete_comment_operation #790 --- libraries/chain/steem_evaluator.cpp | 15 +-- .../include/golos/protocol/exceptions.hpp | 4 + libraries/protocol/steem_operations.cpp | 4 +- tests/common/helpers.hpp | 19 ++-- tests/tests/operation_tests.cpp | 91 +++++++++++++++++++ 5 files changed, 114 insertions(+), 19 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index bf8ac4f20d..d1de75457f 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -413,17 +413,20 @@ namespace golos { namespace chain { database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) { const auto &auth = _db.get_account(o.author); - FC_ASSERT(!(auth.owner_challenged || - auth.active_challenged), "Operation cannot be processed because account is currently challenged."); + GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), + logic_exception::account_is_currently_challenged, + "Operation cannot be processed because account is currently challenged."); } const auto &comment = _db.get_comment(o.author, o.permlink); - FC_ASSERT(comment.children == - 0, "Cannot delete a comment with replies."); + GOLOS_CHECK_LOGIC(comment.children == 0, + logic_exception::cannot_delete_comment_with_replies, + "Cannot delete a comment with replies."); if (_db.is_producing()) { - FC_ASSERT(comment.net_rshares <= - 0, "Cannot delete a comment with network positive votes."); + GOLOS_CHECK_LOGIC(comment.net_rshares <= 0, + logic_exception::cannot_delete_comment_with_positive_votes, + "Cannot delete a comment with network positive votes."); } if (comment.net_rshares > 0) { return; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index ef18cc0142..9be1df23a6 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -198,6 +198,8 @@ namespace golos { discussion_is_frozen, comment_is_archived, comment_editable_during_first_24_hours, + cannot_delete_comment_with_replies, + cannot_delete_comment_with_positive_votes, // withdraw_vesting insufficient_fee_for_powerdown_registered_account, @@ -347,6 +349,8 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (discussion_is_frozen) (comment_is_archived) (comment_editable_during_first_24_hours) + (cannot_delete_comment_with_replies) + (cannot_delete_comment_with_positive_votes) // withdraw_vesting (insufficient_fee_for_powerdown_registered_account) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 19e593c5d6..3648a9622c 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -144,8 +144,8 @@ namespace golos { namespace protocol { } void delete_comment_operation::validate() const { - validate_permlink(permlink); - validate_account_name(author); + GOLOS_CHECK_PARAM_ACCOUNT(author); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); } void challenge_authority_operation::validate() const { diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index b91bd55011..fbf85f671d 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -28,17 +28,14 @@ // Check operation authorities -#define CHECK_OP_AUTHS(OP, OWNER, ACTIVE, POSTING) {\ - account_name_set auths; \ - OP.get_required_owner_authorities(auths); \ - BOOST_CHECK_EQUAL(auths, OWNER); \ - auths.clear(); \ - OP.get_required_active_authorities(auths); \ - BOOST_CHECK_EQUAL(auths, ACTIVE); \ - auths.clear(); \ - OP.get_required_posting_authorities(auths); \ - BOOST_CHECK_EQUAL(auths, POSTING); \ - auths.clear(); \ +#define CHECK_OP_AUTHS(OP, OWNER, ACTIVE, POSTING) { \ + account_name_set owner_auths, active_auths, posting_auths; \ + OP.get_required_owner_authorities(owner_auths); \ + BOOST_CHECK_EQUAL(owner_auths, OWNER); \ + OP.get_required_active_authorities(active_auths); \ + BOOST_CHECK_EQUAL(active_auths, ACTIVE); \ + OP.get_required_posting_authorities(posting_auths); \ + BOOST_CHECK_EQUAL(posting_auths, POSTING); \ } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e02125668e..5c75ec0c50 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6765,6 +6765,97 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(delete_comment_validate) { + try { + BOOST_TEST_MESSAGE("Testing: delete_comment_validate"); + + delete_comment_operation op; + + BOOST_TEST_MESSAGE("--- success on valid parameters"); + op.author = "alice"; + op.permlink = "foo"; + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- failed when 'author' is invalid"); + CHECK_PARAM_INVALID(op, author, ""); + CHECK_PARAM_INVALID(op, author, "a"); + + BOOST_TEST_MESSAGE("--- failed when 'permlink' is invalid"); + CHECK_PARAM_INVALID(op, permlink, std::string(STEEMIT_MAX_PERMLINK_LENGTH, ' ')); + } + FC_LOG_AND_RETHROW() + } + + BOOST_AUTO_TEST_CASE(delete_comment_authorities) { + try { + BOOST_TEST_MESSAGE("Testing: delete_comment_authorities"); + delete_comment_operation op; + op.author = "alice"; + op.permlink = "foo"; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set({"alice"})); + } + FC_LOG_AND_RETHROW() + } + + BOOST_AUTO_TEST_CASE(delete_comment_apply) { + try { + BOOST_TEST_MESSAGE("Testing: delete_comment_apply"); + ACTORS((alice)(bob)) + + signed_transaction tx; + delete_comment_operation op; + + BOOST_TEST_MESSAGE("--- failed when comment missing"); + op.author = "alice"; + op.permlink = "foo"; + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "comment", make_comment_id("alice", "foo")))); + validate_database(); + + BOOST_TEST_MESSAGE("--- prepare testing comments"); + { + comment_operation op; + op.author = "alice"; + op.permlink = "lorem"; + op.parent_author = ""; + op.parent_permlink = "ipsum"; + op.title = "Lorem Ipsum"; + op.body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + op.json_metadata = "{\"foo\":\"bar\"}"; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + + op.author = "bob"; + op.permlink = "bar"; + op.parent_author = "alice"; + op.parent_permlink = "lorem"; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); + validate_database(); + } + + BOOST_TEST_MESSAGE("--- failed when comment has replies"); + op.author = "alice"; + op.permlink = "lorem"; + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_delete_comment_with_replies))); + validate_database(); + + BOOST_TEST_MESSAGE("--- success delete comment"); + op.author = "bob"; + op.permlink = "bar"; + BOOST_CHECK_NO_THROW(push_tx_with_ops_throw(tx, bob_private_key, op)); + validate_database(); + + BOOST_TEST_MESSAGE("--- success delete comment after delete replies"); + op.author = "alice"; + op.permlink = "lorem"; + BOOST_CHECK_NO_THROW(push_tx_with_ops_throw(tx, alice_private_key, op)); + validate_database(); + } + FC_LOG_AND_RETHROW() + } + BOOST_AUTO_TEST_SUITE(delegation) BOOST_AUTO_TEST_CASE(account_create_with_delegation_validate) { From 647e05e6b822cdf7c5c401bae550b11e4d46518d Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 15:30:17 +0700 Subject: [PATCH 125/250] Refactor errors: custom operations (review fixes) #790 --- libraries/chain/steem_evaluator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 11d504d8a3..c12a062017 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1637,7 +1637,6 @@ namespace golos { namespace chain { void custom_binary_evaluator::do_apply(const custom_binary_operation &o) { database &d = db(); - ASSERT_REQ_HF(STEEMIT_HARDFORK_0_14__317, "custom_binary_operation"); std::shared_ptr eval = d.get_custom_json_evaluator(o.id); if (!eval) { From 61926b1b839194f528076ec16e8dab692d530c94 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 12:40:14 +0300 Subject: [PATCH 126/250] Refactor errors: decline_voting_rights + disabled reset_account, set_reset_account #790 --- libraries/chain/steem_evaluator.cpp | 42 ++++---- libraries/protocol/steem_operations.cpp | 27 ++--- tests/tests/operation_tests.cpp | 126 ++++++++---------------- 3 files changed, 75 insertions(+), 120 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index b1135efd18..e6bb46ac5c 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2207,35 +2207,31 @@ namespace golos { namespace chain { }); } - void decline_voting_rights_evaluator::do_apply(const decline_voting_rights_operation &o) { - database &_db = db(); - FC_ASSERT(_db.has_hardfork(STEEMIT_HARDFORK_0_14__324)); - - const auto &account = _db.get_account(o.account); - const auto &request_idx = _db.get_index().indices().get(); + void decline_voting_rights_evaluator::do_apply(const decline_voting_rights_operation& o) { + const auto& account = _db.get_account(o.account); + const auto& request_idx = _db.get_index().indices().get(); auto itr = request_idx.find(account.id); + auto exist = itr != request_idx.end(); if (o.decline) { - FC_ASSERT(itr == - request_idx.end(), "Cannot create new request because one already exists."); - - _db.create([&](decline_voting_rights_request_object &req) { + if (exist) { + GOLOS_THROW_OBJECT_ALREADY_EXIST("account", o.account); + } + _db.create([&](decline_voting_rights_request_object& req) { req.account = account.id; - req.effective_date = _db.head_block_time() + - STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; + req.effective_date = _db.head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; }); } else { - FC_ASSERT(itr != - request_idx.end(), "Cannot cancel the request because it does not exist."); + if (!exist) { + GOLOS_THROW_MISSING_OBJECT("account", o.account); + } _db.remove(*itr); } } - void reset_account_evaluator::do_apply(const reset_account_operation &op) { - FC_ASSERT(false, "Reset Account Operation is currently disabled."); -/* - database& _db = db(); - const auto& acnt = _db.get_account(op.account_to_reset); + void reset_account_evaluator::do_apply(const reset_account_operation& op) { + GOLOS_ASSERT(false, golos::unsupported_operation, "Reset Account Operation is currently disabled."); +/* const auto& acnt = _db.get_account(op.account_to_reset); auto band = _db.find(std::make_tuple(op.account_to_reset, bandwidth_type::old_forum)); if (band != nullptr) FC_ASSERT((_db.head_block_time() - band->last_bandwidth_update) > fc::days(60), @@ -2245,11 +2241,9 @@ namespace golos { namespace chain { */ } - void set_reset_account_evaluator::do_apply(const set_reset_account_operation &op) { - FC_ASSERT(false, "Set Reset Account Operation is currently disabled."); -/* - database& _db = db(); - const auto& acnt = _db.get_account(op.account); + void set_reset_account_evaluator::do_apply(const set_reset_account_operation& op) { + GOLOS_ASSERT(false, golos::unsupported_operation, "Set Reset Account Operation is currently disabled."); +/* const auto& acnt = _db.get_account(op.account); _db.get_account(op.reset_account); FC_ASSERT(acnt.reset_account == op.current_reset_account, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 99ff41688a..46247e195d 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -598,25 +598,30 @@ namespace golos { namespace protocol { } void decline_voting_rights_operation::validate() const { - validate_account_name(account); + GOLOS_CHECK_PARAM_ACCOUNT(account); } void reset_account_operation::validate() const { - validate_account_name(reset_account); - validate_account_name(account_to_reset); - FC_ASSERT(!new_owner_authority.is_impossible(), "new owner authority cannot be impossible"); - FC_ASSERT(new_owner_authority.weight_threshold, "new owner authority cannot be trivial"); - new_owner_authority.validate(); + // This op is disabled. Maybe just remove it completely? + GOLOS_CHECK_PARAM_ACCOUNT(reset_account); + GOLOS_CHECK_PARAM_ACCOUNT(account_to_reset); + GOLOS_CHECK_PARAM(new_owner_authority, { + GOLOS_CHECK_VALUE(!new_owner_authority.is_impossible(), "New owner authority cannot be impossible"); + GOLOS_CHECK_VALUE(new_owner_authority.weight_threshold, "New owner authority cannot be trivial"); + new_owner_authority.validate(); + }); } void set_reset_account_operation::validate() const { - validate_account_name(account); + // This op is disabled. Maybe just remove it completely? + GOLOS_CHECK_PARAM_ACCOUNT(account); if (current_reset_account.size()) { - validate_account_name(current_reset_account); + GOLOS_CHECK_PARAM_ACCOUNT(current_reset_account); } - validate_account_name(reset_account); - FC_ASSERT(current_reset_account != - reset_account, "new reset account cannot be current reset account"); + GOLOS_CHECK_PARAM_ACCOUNT(reset_account); + GOLOS_CHECK_LOGIC(current_reset_account != reset_account, + logic_exception::cannot_set_same_reset_account, + "New reset account cannot be current reset account"); } void delegate_vesting_shares_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 67c847a3b9..8c868274e7 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6443,25 +6443,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(decline_voting_rights_validate) { try { + BOOST_TEST_MESSAGE("Testing: decline_voting_rights_validate"); + decline_voting_rights_operation op; + op.account = "alice"; + CHECK_OP_VALID(op); + CHECK_PARAM_INVALID(op, account, ""); + } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE(decline_voting_rights_authorities) { try { BOOST_TEST_MESSAGE("Testing: decline_voting_rights_authorities"); - decline_voting_rights_operation op; op.account = "alice"; - - flat_set auths; - flat_set expected; - - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - expected.insert("alice"); - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set({"alice"}), account_name_set(), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -6481,78 +6476,49 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) proxy.proxy = "alice"; signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(proxy); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - + push_tx_with_ops(tx, bob_private_key, proxy); decline_voting_rights_operation op; op.account = "alice"; - BOOST_TEST_MESSAGE("--- success"); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, op); - const auto &request_idx = db->get_index().indices().get(); + const auto& request_idx = db->get_index().indices().get(); auto itr = request_idx.find(db->get_account("alice").id); - BOOST_REQUIRE(itr != request_idx.end()); - BOOST_REQUIRE(itr->effective_date == db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD); - + BOOST_CHECK(itr != request_idx.end()); + BOOST_CHECK_EQUAL(itr->effective_date, db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD); BOOST_TEST_MESSAGE("--- failure revoking voting rights with existing request"); generate_block(); - tx.clear(); - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(object_already_exist, "account", "alice"))); BOOST_TEST_MESSAGE("--- successs cancelling a request"); op.decline = false; - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, op); itr = request_idx.find(db->get_account("alice").id); - BOOST_REQUIRE(itr == request_idx.end()); - + BOOST_CHECK(itr == request_idx.end()); BOOST_TEST_MESSAGE("--- failure cancelling a request that doesn't exist"); generate_block(); - tx.clear(); - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "alice"))); BOOST_TEST_MESSAGE("--- check account can vote during waiting period"); op.decline = true; - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, op); generate_blocks( - db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); + db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); BOOST_REQUIRE(db->get_account("alice").can_vote); witness_create("alice", alice_private_key, "foo.bar", alice_private_key.get_public_key(), 0); account_witness_vote_operation witness_vote; witness_vote.account = "alice"; witness_vote.witness = "alice"; - tx.clear(); - tx.operations.push_back(witness_vote); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, witness_vote); comment_operation comment; comment.author = "alice"; @@ -6565,55 +6531,45 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) vote.author = "alice"; vote.permlink = "test"; vote.weight = STEEMIT_100_PERCENT; - tx.clear(); - tx.operations.push_back(comment); - tx.operations.push_back(vote); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, comment, vote); validate_database(); - BOOST_TEST_MESSAGE("--- check account cannot vote after request is processed"); generate_block(); - BOOST_REQUIRE(!db->get_account("alice").can_vote); + BOOST_CHECK(!db->get_account("alice").can_vote); validate_database(); itr = request_idx.find(db->get_account("alice").id); - BOOST_REQUIRE(itr == request_idx.end()); + BOOST_CHECK(itr == request_idx.end()); - const auto &witness_idx = db->get_index().indices().get(); + const auto& witness_idx = db->get_index().indices().get(); auto witness_itr = witness_idx.find( - boost::make_tuple(db->get_account("alice").id, db->get_witness("alice").id)); - BOOST_REQUIRE(witness_itr == witness_idx.end()); + boost::make_tuple(db->get_account("alice").id, db->get_witness("alice").id)); + BOOST_CHECK(witness_itr == witness_idx.end()); - tx.clear(); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(witness_vote); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, witness_vote), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); db->get( boost::make_tuple(db->get_comment("alice", string("test")).id, db->get_account("alice").id) ); vote.weight = 0; - tx.clear(); - tx.operations.push_back(vote); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, vote), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); vote.weight = STEEMIT_1_PERCENT * 50; - tx.clear(); - tx.operations.push_back(vote); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, vote), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); proxy.account = "alice"; proxy.proxy = "bob"; - tx.clear(); - tx.operations.push_back(proxy); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, proxy), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); } FC_LOG_AND_RETHROW() } From f86b8e680eaef26c2eaecd812825a6fa4ba35dcb Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 13:00:38 +0300 Subject: [PATCH 127/250] Refactor errors: set_reset_account missing exception #790 --- libraries/protocol/include/golos/protocol/exceptions.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index baa412e849..8a73e62308 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -206,6 +206,9 @@ namespace golos { //account_create_with_delegation not_enough_delegation, + //set_reset_account_operation + cannot_set_same_reset_account, + //delegate_vesting_shares cannot_delegate_to_yourself, delegation_difference_too_low, @@ -372,6 +375,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) + //set_reset_account_operation + (cannot_set_same_reset_account) + //delegate_vesting_shares (cannot_delegate_to_yourself) (delegation_difference_too_low) From 16490d5cba52d21740d68de6bc5c34225620cbc9 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 14:13:45 +0300 Subject: [PATCH 128/250] Refactor errors: decline_voting_rights (review fixes) #790 --- libraries/chain/steem_evaluator.cpp | 4 +- tests/common/database_fixture.hpp | 6 --- tests/tests/operation_tests.cpp | 82 +++++++++++++++-------------- tests/tests/proposal_tests.cpp | 62 +++++++++++----------- 4 files changed, 75 insertions(+), 79 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index e6bb46ac5c..9918f18ad5 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2215,7 +2215,7 @@ namespace golos { namespace chain { if (o.decline) { if (exist) { - GOLOS_THROW_OBJECT_ALREADY_EXIST("account", o.account); + GOLOS_THROW_OBJECT_ALREADY_EXIST("decline_voting_rights_request", o.account); } _db.create([&](decline_voting_rights_request_object& req) { req.account = account.id; @@ -2223,7 +2223,7 @@ namespace golos { namespace chain { }); } else { if (!exist) { - GOLOS_THROW_MISSING_OBJECT("account", o.account); + GOLOS_THROW_MISSING_OBJECT("decline_voting_rights_request", o.account); } _db.remove(*itr); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index bd87ccc85c..02d636aca1 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -567,12 +567,6 @@ namespace golos { namespace chain { template void push_tx_with_ops(signed_transaction& tx, const fc::ecc::private_key& k, Ops... ops) { - sign_tx_with_ops(tx, k, ops...); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - } - - template - void push_tx_with_ops_throw(signed_transaction& tx, const fc::ecc::private_key& k, Ops... ops) { sign_tx_with_ops(tx, k, ops...); db->push_transaction(tx, 0); } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 8c868274e7..58c15028d4 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6476,13 +6476,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) proxy.proxy = "alice"; signed_transaction tx; - push_tx_with_ops(tx, bob_private_key, proxy); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, proxy)); decline_voting_rights_operation op; op.account = "alice"; BOOST_TEST_MESSAGE("--- success"); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); const auto& request_idx = db->get_index().indices().get(); auto itr = request_idx.find(db->get_account("alice").id); @@ -6491,34 +6491,36 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failure revoking voting rights with existing request"); generate_block(); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), - CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(object_already_exist, "account", "alice"))); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "decline_voting_rights_request", "alice"))); BOOST_TEST_MESSAGE("--- successs cancelling a request"); op.decline = false; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); itr = request_idx.find(db->get_account("alice").id); BOOST_CHECK(itr == request_idx.end()); BOOST_TEST_MESSAGE("--- failure cancelling a request that doesn't exist"); generate_block(); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), - CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "alice"))); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "decline_voting_rights_request", "alice"))); BOOST_TEST_MESSAGE("--- check account can vote during waiting period"); op.decline = true; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks( db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); - BOOST_REQUIRE(db->get_account("alice").can_vote); + BOOST_CHECK(db->get_account("alice").can_vote); witness_create("alice", alice_private_key, "foo.bar", alice_private_key.get_public_key(), 0); account_witness_vote_operation witness_vote; witness_vote.account = "alice"; witness_vote.witness = "alice"; - push_tx_with_ops(tx, alice_private_key, witness_vote); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, witness_vote)); comment_operation comment; comment.author = "alice"; @@ -6531,7 +6533,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) vote.author = "alice"; vote.permlink = "test"; vote.weight = STEEMIT_100_PERCENT; - push_tx_with_ops(tx, alice_private_key, comment, vote); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, comment, vote)); validate_database(); BOOST_TEST_MESSAGE("--- check account cannot vote after request is processed"); @@ -6547,7 +6549,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) boost::make_tuple(db->get_account("alice").id, db->get_witness("alice").id)); BOOST_CHECK(witness_itr == witness_idx.end()); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, witness_vote), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, witness_vote), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); @@ -6556,18 +6558,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ); vote.weight = 0; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, vote), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, vote), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); vote.weight = STEEMIT_1_PERCENT * 50; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, vote), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, vote), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); proxy.account = "alice"; proxy.proxy = "bob"; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, proxy), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, proxy), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::voter_declined_voting_rights))); } @@ -6884,7 +6886,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), tx_invalid_operation, {}); BOOST_TEST_MESSAGE("--- Test success under normal conditions"); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); const account_object& bob_acc = db->get_account("bob"); const account_object& alice_acc = db->get_account("alice"); @@ -6919,21 +6921,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegation = ASSET_GESTS(0); op.new_account_name = "sam"; fund("alice", op.fee); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_TEST_MESSAGE("--- Test success using minimum GOLOS fee"); op.fee = min_fee; op.delegation = (required_fee - min_fee) * gp.get_vesting_share_price(); op.new_account_name = "pam"; fund("alice", op.fee); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_TEST_MESSAGE("--- Test success using both GESTS and GOLOS to reach target delegation"); op.fee = asset(required_fee.amount / 2 + 1, STEEM_SYMBOL); op.delegation = asset(required_gests.amount / 2 + 1, VESTS_SYMBOL); op.new_account_name = "ram"; fund("alice", op.fee); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_TEST_MESSAGE("--- Test failure when insufficient funds to process transaction"); op.fee = ASSET_GOLOS(10); @@ -6955,7 +6957,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) delegate.delegator = "alice"; delegate.delegatee = "bob"; delegate.vesting_shares = ASSET_GESTS(0); - push_tx_with_ops(tx, alice_private_key, delegate); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, delegate)); auto itr = db->get_index().begin(); auto end = db->get_index().end(); @@ -7024,7 +7026,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = ASSET_GESTS(1e6); op.delegator = "alice"; op.delegatee = "bob"; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(1); const auto& alice_acc = db->get_account("alice"); const auto& bob_acc = db->get_account("bob"); @@ -7041,7 +7043,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- Test delegation change"); op.vesting_shares = ASSET_GESTS(2e7); - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(1); BOOST_CHECK(delegation != nullptr); BOOST_CHECK_EQUAL(delegation->vesting_shares, ASSET_GESTS(2e7)); @@ -7057,7 +7059,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) comment_op.parent_permlink = "test"; comment_op.title = "bar"; comment_op.body = "foo bar"; - push_tx_with_ops(tx, alice_private_key, comment_op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, comment_op)); auto old_voting_power = bob_acc.voting_power; vote_operation vote_op; @@ -7065,7 +7067,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) vote_op.author = "alice"; vote_op.permlink = "foo"; vote_op.weight = STEEMIT_100_PERCENT; - push_tx_with_ops(tx, bob_private_key, vote_op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, vote_op)); generate_blocks(1); auto& alice_comment = db->get_comment("alice", string("foo")); @@ -7081,11 +7083,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.delegator = "bob"; op.delegatee = "alice"; op.vesting_shares = asset(max_allowed.amount + 1, VESTS_SYMBOL); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::delegation_limited_by_voting_power))); op.vesting_shares = max_allowed; - push_tx_with_ops(tx, bob_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); generate_block(); ACTORS((sam)(dave)) @@ -7099,13 +7101,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.vesting_shares = ASSET_GESTS(0); op.delegator = "sam"; op.delegatee = "dave"; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::delegation_difference_too_low))); BOOST_TEST_MESSAGE("--- Test failure delegating more vesting shares than account has"); op.vesting_shares = asset(sam_vest.amount + 1, VESTS_SYMBOL); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(insufficient_funds, "sam", "available vesting shares", op.vesting_shares))); @@ -7115,8 +7117,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) withdraw.account = "sam"; withdraw.vesting_shares = sam_vest; op.vesting_shares = asset(sam_vest.amount + 2, VESTS_SYMBOL); - push_tx_with_ops(tx, sam_private_key, withdraw); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, op), + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, withdraw)); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(insufficient_funds, "sam", "available vesting shares", op.vesting_shares))); @@ -7125,20 +7127,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) sam_acc.vesting_shares - sam_acc.delegated_vesting_shares - asset(sam_acc.to_withdraw, VESTS_SYMBOL)); withdraw.vesting_shares = ASSET_GESTS(0); - push_tx_with_ops(tx, sam_private_key, withdraw); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, withdraw)); BOOST_TEST_MESSAGE("--- Test failure powering down vesting shares that are delegated"); sam_vest.amount += 1000; op.vesting_shares = sam_vest; withdraw.vesting_shares = asset(sam_vest.amount, VESTS_SYMBOL); - push_tx_with_ops(tx, sam_private_key, op); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, sam_private_key, withdraw), + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, withdraw), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(insufficient_funds, "sam", "having vesting shares", sam_vest))); BOOST_TEST_MESSAGE("--- Remove a delegation and ensure it is returned after 1 week"); op.vesting_shares = ASSET_GESTS(0); - push_tx_with_ops(tx, sam_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); auto exp_obj = db->get_index().begin(); auto end = db->get_index().end(); @@ -7217,7 +7219,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) account_metadata_operation op; op.account = "alice"; op.json_metadata = json; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(10); auto alice_acc = db->get_account("alice"); @@ -7250,7 +7252,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) cr.owner = authority(1, priv_key.get_public_key(), 1); cr.active = authority(1, priv_key.get_public_key(), 1); cr.memo_key = priv_key.get_public_key(); - push_tx_with_ops(tx, bob_private_key, cr); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cr)); meta = db->get("sam"); BOOST_CHECK_EQUAL(meta.account, "sam"); @@ -7281,7 +7283,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) account_metadata_operation op; op.account = "alice"; op.json_metadata = json; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(10); auto alice_acc = db->get_account("alice"); @@ -7307,7 +7309,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) cr.owner = authority(1, priv_key.get_public_key(), 1); cr.active = authority(1, priv_key.get_public_key(), 1); cr.memo_key = priv_key.get_public_key(); - push_tx_with_ops(tx, bob_private_key, cr); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cr)); meta = db->find("sam"); BOOST_CHECK(meta == nullptr); @@ -7336,7 +7338,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) account_metadata_operation op; op.account = "alice"; op.json_metadata = json; - push_tx_with_ops(tx, alice_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(10); auto alice_acc = db->get_account("alice"); @@ -7362,7 +7364,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) cr.owner = authority(1, priv_key.get_public_key(), 1); cr.active = authority(1, priv_key.get_public_key(), 1); cr.memo_key = priv_key.get_public_key(); - push_tx_with_ops(tx, bob_private_key, cr); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cr)); meta = db->find("sam"); BOOST_CHECK(meta != nullptr); diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index f0f0656829..6390c75fcb 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE(create_proposal) { try { cop.proposed_operations.push_back(operation_wrapper(top)); cop.proposed_operations.push_back(operation_wrapper(vop)); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, cop), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, cop), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::tx_with_both_posting_active_ops))); @@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(create_proposal) { try { cop1.review_period_time = db->head_block_time() + fc::hours(3); cop1.proposed_operations.push_back(operation_wrapper(top1)); - push_tx_with_ops(tx, bob_private_key, cop1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop1)); generate_blocks(1); const auto& p = db->get_proposal(cop1.author, cop1.title); @@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { cop.review_period_time = db->head_block_time() + fc::hours(3); cop.proposed_operations.push_back(operation_wrapper(top)); - push_tx_with_ops(tx, bob_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop)); generate_blocks(1); const auto& p = db->get_proposal(cop.author, cop.title); @@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop.title = cop.title; uop.active_approvals_to_add.insert("alice"); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, uop), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, uop), CHECK_ERROR(tx_missing_active_auth, 0)); proposal_update_operation uop1; @@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop1.active_approvals_to_add.insert("alice"); uop1.active_approvals_to_remove.insert("alice"); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, uop1), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, uop1), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::add_and_remove_same_approval))); @@ -326,7 +326,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop2.title = cop.title; uop2.key_approvals_to_add.insert(bob_public_key); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, uop2), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, uop2), CHECK_ERROR(tx_missing_other_auth, 0)); BOOST_TEST_MESSAGE("--- Add an approval to a proposal"); @@ -335,14 +335,14 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop3.author = cop.author; uop3.title = cop.title; uop3.active_approvals_to_add.insert("alice"); - push_tx_with_ops(tx, alice_private_key, uop3); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop3)); generate_blocks(1); proposal_update_operation uop4; uop4.author = cop.author; uop4.title = cop.title; uop4.key_approvals_to_add.insert(bob_public_key); - push_tx_with_ops(tx, bob_private_key, uop4); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, uop4)); generate_blocks(1); BOOST_CHECK_EQUAL(p.required_active_approvals.size(), 1); @@ -363,14 +363,14 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop5.author = cop.author; uop5.title = cop.title; uop5.active_approvals_to_remove.insert("alice"); - push_tx_with_ops(tx, alice_private_key, uop5); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop5)); generate_blocks(1); proposal_update_operation uop6; uop6.author = cop.author; uop6.title = cop.title; uop6.key_approvals_to_remove.insert(bob_public_key); - push_tx_with_ops(tx, bob_private_key, uop6); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, uop6)); generate_blocks(1); BOOST_CHECK_EQUAL(p.required_active_approvals.size(), 1); @@ -389,14 +389,14 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop7.author = cop.author; uop7.title = cop.title; uop7.active_approvals_to_add.insert("alice"); - push_tx_with_ops(tx, alice_private_key, uop7); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop7)); generate_blocks(1); proposal_update_operation uop8; uop8.author = cop.author; uop8.title = cop.title; uop8.key_approvals_to_add.insert(bob_public_key); - push_tx_with_ops(tx, bob_private_key, uop8); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, uop8)); generate_blocks(1); BOOST_CHECK_EQUAL(p.required_active_approvals.size(), 1); @@ -417,7 +417,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop9.author = cop.author; uop9.title = cop.title; uop9.key_approvals_to_remove.insert(bob_public_key); - push_tx_with_ops(tx, bob_private_key, uop9); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, uop9)); generate_blocks(1); BOOST_CHECK_EQUAL(p.required_active_approvals.size(), 1); @@ -435,7 +435,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop10.author = cop.author; uop10.title = cop.title; uop10.active_approvals_to_add.insert("bob"); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, bob_private_key, uop10), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, uop10), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::cannot_add_approval_in_review_period))); @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(update_proposal) { try { uop11.author = cop.author; uop11.title = cop.title; uop11.active_approvals_to_remove.insert("alice"); - push_tx_with_ops(tx, alice_private_key, uop11); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop11)); generate_blocks(1); BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); @@ -472,14 +472,14 @@ BOOST_AUTO_TEST_CASE(update_proposal1) { try { cop.expiration_time = db->head_block_time() + fc::hours(6); cop.proposed_operations.push_back(operation_wrapper(top)); - push_tx_with_ops(tx, bob_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop)); generate_blocks(1); proposal_update_operation uop; uop.author = cop.author; uop.title = cop.title; uop.active_approvals_to_add.insert("alice"); - push_tx_with_ops(tx, alice_private_key, uop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop)); generate_blocks(1); BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); @@ -509,14 +509,14 @@ BOOST_AUTO_TEST_CASE(update_proposal2) { try { cop.expiration_time = db->head_block_time() + fc::hours(6); cop.proposed_operations.push_back(operation_wrapper(top)); - push_tx_with_ops(tx, bob_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop)); generate_blocks(1); proposal_update_operation uop; uop.author = cop.author; uop.title = cop.title; uop.key_approvals_to_add.insert(alice_public_key); - push_tx_with_ops(tx, alice_private_key, uop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop)); generate_blocks(1); BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); @@ -547,14 +547,14 @@ BOOST_AUTO_TEST_CASE(update_proposal3) { try { cop.expiration_time = db->head_block_time() + fc::hours(6); cop.proposed_operations.push_back(operation_wrapper(top)); - push_tx_with_ops(tx, bob_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop)); generate_blocks(1); proposal_update_operation uop; uop.author = cop.author; uop.title = cop.title; uop.key_approvals_to_add.insert(alice_public_key); - push_tx_with_ops(tx, alice_private_key, uop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop)); generate_blocks(1); BOOST_CHECK_NO_THROW(db->get_proposal(cop.author, cop.title)); @@ -602,7 +602,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { account_update_operation op; op.account = account; op.active = auth; - push_tx_with_ops(tx, account_private_key, op); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, account_private_key, op)); generate_blocks(1); }; @@ -674,7 +674,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { cop.memo = "Some memo about transfer"; cop.expiration_time = db->head_block_time() + fc::hours(6); cop.proposed_operations.push_back(operation_wrapper(op)); - push_tx_with_ops(tx, edy_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, edy_private_key, cop)); generate_blocks(1); BOOST_REQUIRE_NO_THROW(db->get_proposal(cop.author, cop.title)); @@ -683,7 +683,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop.author = cop.author; uop.title = cop.title; uop.key_approvals_to_add.insert(alice_public_key); - push_tx_with_ops(tx, alice_private_key, uop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, uop)); generate_blocks(1); const auto& poxx_account = db->get_account("poxx"); @@ -697,7 +697,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop1.author = cop.author; uop1.title = cop.title; uop1.key_approvals_to_add.insert(bob_public_key); - push_tx_with_ops(tx, bob_private_key, uop1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, uop1)); generate_blocks(1); BOOST_REQUIRE_NO_THROW(db->get_proposal(cop.author, cop.title)); @@ -708,7 +708,7 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop2.author = cop.author; uop2.title = cop.title; uop2.key_approvals_to_add.insert(cindy_public_key); - push_tx_with_ops(tx, cindy_private_key, uop2); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, cindy_private_key, uop2)); generate_blocks(1); BOOST_REQUIRE_NO_THROW(db->get_proposal(cop.author, cop.title)); @@ -719,14 +719,14 @@ BOOST_AUTO_TEST_CASE(nested_signatures) { try { uop3.author = cop.author; uop3.title = cop.title; uop3.key_approvals_to_add.insert(dave_public_key); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, dave_private_key, uop3), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, dave_private_key, uop3), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(tx_irrelevant_sig, 0))); proposal_update_operation uop4; uop4.author = cop.author; uop4.title = cop.title; uop4.key_approvals_to_add.insert(dan_public_key); - push_tx_with_ops(tx, dan_private_key, uop4); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, dan_private_key, uop4)); generate_blocks(1); BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); @@ -757,7 +757,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { cop.expiration_time = db->head_block_time() + fc::hours(6); cop.proposed_operations.push_back(operation_wrapper(top)); - push_tx_with_ops(tx, bob_private_key, cop); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, cop)); generate_blocks(1); BOOST_TEST_MESSAGE("--- Unauthorized trying of delete of proposal"); @@ -766,7 +766,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { dop.author = cop.author; dop.title = cop.title; dop.requester = "dave"; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, dave_private_key, dop), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, dave_private_key, dop), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::proposal_delete_not_allowed))); @@ -776,7 +776,7 @@ BOOST_AUTO_TEST_CASE(delete_proposal) { try { dop1.author = cop.author; dop1.title = cop.title; dop1.requester = "alice"; - push_tx_with_ops(tx, alice_private_key, dop1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, dop1)); generate_blocks(1); BOOST_CHECK(nullptr == db->find_proposal(cop.author, cop.title)); From 3346e14aa8b7a5d876a9bb5de60654f126562db2 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 14:23:36 +0300 Subject: [PATCH 129/250] Refactor errors: cancel_transfer_from_savings_operation #790 --- libraries/chain/database.cpp | 4 +- libraries/chain/steem_evaluator.cpp | 13 ++-- libraries/protocol/steem_operations.cpp | 2 +- tests/tests/operation_tests.cpp | 80 +++++++------------------ 4 files changed, 30 insertions(+), 69 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 1a1490d457..7b5c976d5f 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -717,10 +717,10 @@ namespace golos { namespace chain { } } - const savings_withdraw_object &database::get_savings_withdraw(const account_name_type &owner, uint32_t request_id) const { + const savings_withdraw_object& database::get_savings_withdraw(const account_name_type& owner, uint32_t request_id) const { try { return get(boost::make_tuple(owner, request_id)); - } catch(const std::out_of_range &e) { + } catch(const std::out_of_range& e) { GOLOS_THROW_MISSING_OBJECT("savings_withdraw", fc::mutable_variant_object()("account",owner)("request_id", request_id)); } FC_CAPTURE_AND_RETHROW((owner)(request_id)) } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 9918f18ad5..81aa6274ba 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2195,14 +2195,13 @@ namespace golos { namespace chain { }); } - void cancel_transfer_from_savings_evaluator::do_apply(const cancel_transfer_from_savings_operation &op) { - database &_db = db(); - const auto &swo = _db.get_savings_withdraw(op.from, op.request_id); - _db.adjust_savings_balance(_db.get_account(swo.from), swo.amount); + void cancel_transfer_from_savings_evaluator::do_apply(const cancel_transfer_from_savings_operation& op) { + const auto& name = op.from; + const auto& from = _db.get_account(name); + const auto& swo = _db.get_savings_withdraw(name, op.request_id); + _db.adjust_savings_balance(from, swo.amount); _db.remove(swo); - - const auto &from = _db.get_account(op.from); - _db.modify(from, [&](account_object &a) { + _db.modify(from, [&](account_object& a) { a.savings_withdraw_requests--; }); } diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 46247e195d..6814c82300 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -594,7 +594,7 @@ namespace golos { namespace protocol { } void cancel_transfer_from_savings_operation::validate() const { - validate_account_name(from); + GOLOS_CHECK_PARAM_ACCOUNT(from); } void decline_voting_rights_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 58c15028d4..60ebf62156 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6329,20 +6329,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(cancel_transfer_from_savings_validate) { try { BOOST_TEST_MESSAGE("Testing: cancel_transfer_from_savings_validate"); - cancel_transfer_from_savings_operation op; op.from = "alice"; op.request_id = 0; + BOOST_TEST_MESSAGE("--- sucess on valid params"); + CHECK_OP_VALID(op); + BOOST_TEST_MESSAGE("--- failure when 'from' is invalid"); + CHECK_PARAM_INVALID(op, from, ""); - - BOOST_TEST_MESSAGE("--- failure when 'from' is empty"); - op.from = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - - BOOST_TEST_MESSAGE("--- sucess when 'from' is not empty"); - op.from = "alice"; - op.validate(); } FC_LOG_AND_RETHROW() } @@ -6350,29 +6344,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(cancel_transfer_from_savings_authorities) { try { BOOST_TEST_MESSAGE("Testing: cancel_transfer_from_savings_authorities"); - cancel_transfer_from_savings_operation op; op.from = "alice"; - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); - - auths.clear(); - expected.clear(); - op.from = "bob"; - op.get_required_active_authorities(auths); - expected.insert("bob"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -6398,46 +6372,34 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) withdraw.amount = ASSET("3.000 GOLOS"); signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(save); - tx.operations.push_back(withdraw); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, save, withdraw)); validate_database(); - - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 1); - BOOST_REQUIRE(db->get_account("bob").savings_withdraw_requests == 0); - + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 1); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_withdraw_requests, 0); BOOST_TEST_MESSAGE("--- Failure when there is no pending request"); cancel_transfer_from_savings_operation op; op.from = "alice"; op.request_id = 0; - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "savings_withdraw", + fc::mutable_variant_object()("account","alice")("request_id",op.request_id)))); validate_database(); - - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 1); - BOOST_REQUIRE(db->get_account("bob").savings_withdraw_requests == 0); - + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 1); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_withdraw_requests, 0); BOOST_TEST_MESSAGE("--- Success"); op.request_id = 1; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_balance == ASSET("10.000 GOLOS")); - BOOST_REQUIRE(db->get_account("alice").savings_withdraw_requests == 0); - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").savings_balance == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").savings_withdraw_requests == 0); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("10.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 0); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_balance, ASSET("0.000 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").savings_withdraw_requests, 0); validate_database(); } FC_LOG_AND_RETHROW() From a0e3665bb97ac4dbfe76cf214ac0f7048837aaf8 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 17:16:37 +0300 Subject: [PATCH 130/250] Refactor errors: transfer_to/from_savings operations #790 --- libraries/chain/database.cpp | 19 +- .../chain/include/golos/chain/database.hpp | 6 +- libraries/chain/steem_evaluator.cpp | 33 +- libraries/protocol/steem_operations.cpp | 28 +- tests/tests/operation_tests.cpp | 340 +++++------------- 5 files changed, 123 insertions(+), 303 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 7b5c976d5f..f66b27b2ad 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -699,15 +699,15 @@ namespace golos { namespace chain { return find(boost::make_tuple(name, orderid)); } - const convert_request_object &database::get_convert_request(const account_name_type &name, uint32_t id) const { + const convert_request_object& database::get_convert_request(const account_name_type& name, uint32_t id) const { try { return get(boost::make_tuple(name, id)); - } catch(const std::out_of_range &e) { + } catch(const std::out_of_range& e) { GOLOS_THROW_MISSING_OBJECT("convert_request", fc::mutable_variant_object()("account",name)("request_id", id)); } FC_CAPTURE_AND_RETHROW((name)(id)) } - const convert_request_object *database::find_convert_request(const account_name_type &name, uint32_t id) const { + const convert_request_object* database::find_convert_request(const account_name_type& name, uint32_t id) const { return find(boost::make_tuple(name, id)); } @@ -733,18 +733,25 @@ namespace golos { namespace chain { } FC_CAPTURE_AND_RETHROW((name)) } - const savings_withdraw_object *database::find_savings_withdraw(const account_name_type &owner, uint32_t request_id) const { + const savings_withdraw_object* database::find_savings_withdraw(const account_name_type& owner, uint32_t request_id) const { return find(boost::make_tuple(owner, request_id)); } - const dynamic_global_property_object &database::get_dynamic_global_properties() const { + const dynamic_global_property_object& database::get_dynamic_global_properties() const { try { return get(); - } catch(const std::out_of_range &e) { + } catch(const std::out_of_range& e) { GOLOS_THROW_INTERNAL_ERROR("Missing dynamic_global_properties"); } FC_CAPTURE_AND_RETHROW() } + void database::throw_if_exists_savings_withdraw(const account_name_type& owner, uint32_t request_id) const { + if (nullptr != find_savings_withdraw(owner, request_id)) { + GOLOS_THROW_OBJECT_ALREADY_EXIST("savings_withdraw", + fc::mutable_variant_object()("owner",owner)("request_id",request_id)); + } + } + const feed_history_object &database::get_feed_history() const { try { return get(); diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index cc29b3d93b..8c398fb355 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -191,9 +191,9 @@ namespace golos { namespace chain { void throw_if_exists_convert_request(const account_name_type &owner, uint32_t id) const; - const savings_withdraw_object &get_savings_withdraw(const account_name_type &owner, uint32_t request_id) const; - - const savings_withdraw_object *find_savings_withdraw(const account_name_type &owner, uint32_t request_id) const; + const savings_withdraw_object& get_savings_withdraw(const account_name_type& owner, uint32_t request_id) const; + const savings_withdraw_object* find_savings_withdraw(const account_name_type& owner, uint32_t request_id) const; + void throw_if_exists_savings_withdraw(const account_name_type& owner, uint32_t request_id) const; const account_authority_object &get_authority(const account_name_type &name) const; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 81aa6274ba..7daf83eaf4 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2153,10 +2153,9 @@ namespace golos { namespace chain { } } - void transfer_to_savings_evaluator::do_apply(const transfer_to_savings_operation &op) { - database &_db = db(); - const auto &from = _db.get_account(op.from); - const auto &to = _db.get_account(op.to); + void transfer_to_savings_evaluator::do_apply(const transfer_to_savings_operation& op) { + const auto& from = _db.get_account(op.from); + const auto& to = _db.get_account(op.to); GOLOS_CHECK_BALANCE(from, MAIN_BALANCE, op.amount); @@ -2164,21 +2163,21 @@ namespace golos { namespace chain { _db.adjust_savings_balance(to, op.amount); } - void transfer_from_savings_evaluator::do_apply(const transfer_from_savings_operation &op) { - database &_db = db(); - const auto &from = _db.get_account(op.from); - _db.get_account(op.to); // Verify to account exists + void transfer_from_savings_evaluator::do_apply(const transfer_from_savings_operation& op) { + const auto& from = _db.get_account(op.from); + _db.get_account(op.to); // Verify `to` account exists - GOLOS_CHECK_LOGIC(from.savings_withdraw_requests < STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT, - golos::logic_exception::reached_limit_for_pending_withdraw_requests, - "Account has reached limit for pending withdraw requests.", - ("limit",STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT)); + GOLOS_CHECK_LOGIC(from.savings_withdraw_requests < STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT, + golos::logic_exception::reached_limit_for_pending_withdraw_requests, + "Account has reached limit for pending withdraw requests.", + ("limit",STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT)); GOLOS_CHECK_BALANCE(from, SAVINGS, op.amount); - _db.adjust_savings_balance(from, -op.amount); - _db.create([&](savings_withdraw_object &s) { + GOLOS_CHECK_OBJECT_MISSING(_db, savings_withdraw, op.from, op.request_id); + + _db.create([&](savings_withdraw_object& s) { s.from = op.from; s.to = op.to; s.amount = op.amount; @@ -2186,11 +2185,9 @@ namespace golos { namespace chain { from_string(s.memo, op.memo); } s.request_id = op.request_id; - s.complete = - _db.head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME; + s.complete = _db.head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME; }); - - _db.modify(from, [&](account_object &a) { + _db.modify(from, [&](account_object& a) { a.savings_withdraw_requests++; }); } diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 6814c82300..5288d6be1f 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -570,27 +570,23 @@ namespace golos { namespace protocol { } void transfer_to_savings_operation::validate() const { - GOLOS_CHECK_PARAM(from, validate_account_name(from)); - GOLOS_CHECK_PARAM(to, validate_account_name(to)); - GOLOS_CHECK_PARAM(amount, { - GOLOS_CHECK_VALUE(amount.amount > 0, "Amount must be positive"); - GOLOS_CHECK_VALUE(amount.symbol == STEEM_SYMBOL || - amount.symbol == SBD_SYMBOL, "Available currency GOLOS or GBG"); - }); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM(amount, GOLOS_CHECK_ASSET_GT0(amount, GOLOS_OR_GBG)); GOLOS_CHECK_PARAM(memo, { - GOLOS_CHECK_VALUE(memo.size() < STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); - GOLOS_CHECK_VALUE(fc::is_utf8(memo), "Memo is not UTF8"); + GOLOS_CHECK_VALUE_MAX_SIZE(memo, STEEMIT_MAX_MEMO_SIZE - 1); //-1 to satisfy <= check (vs <) + GOLOS_CHECK_VALUE_UTF8(memo); }); } void transfer_from_savings_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - FC_ASSERT(amount.amount > 0); - FC_ASSERT(amount.symbol == STEEM_SYMBOL || - amount.symbol == SBD_SYMBOL); - FC_ASSERT(memo.size() < STEEMIT_MAX_MEMO_SIZE, "Memo is too large"); - FC_ASSERT(fc::is_utf8(memo), "Memo is not UTF8"); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM(amount, GOLOS_CHECK_ASSET_GT0(amount, GOLOS_OR_GBG)); + GOLOS_CHECK_PARAM(memo, { + GOLOS_CHECK_VALUE_MAX_SIZE(memo, STEEMIT_MAX_MEMO_SIZE - 1); //-1 to satisfy <= check. TODO: unify <=/< + GOLOS_CHECK_VALUE_UTF8(memo); + }); } void cancel_transfer_from_savings_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 60ebf62156..85239def25 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -31,6 +31,8 @@ using std::string; using account_name_set = flat_set; +#define BAD_UTF8_STRING "\xc3\x28" + fc::variant_object make_comment_id(const std::string& author, const std::string& permlink) { auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); @@ -1839,8 +1841,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failure when url is empty or too long or have invalid utf8"); CHECK_PARAM_INVALID(op, url, ""); - // CHECK_PARAM_INVALID(op, url, string(1+STEEMIT_MAX_WITNESS_URL_LENGTH, ' ')); // needs HF - CHECK_PARAM_INVALID(op, url, "\xc3\x28"); + // CHECK_PARAM_INVALID(op, url, string(1+STEEMIT_MAX_WITNESS_URL_LENGTH, ' ')); + CHECK_PARAM_INVALID(op, url, BAD_UTF8_STRING); BOOST_TEST_MESSAGE("--- failure when fee in not GOLOS or negative"); CHECK_PARAM_INVALID(op, fee, ASSET_GBG(1)); @@ -5784,6 +5786,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE(transfer_to_savings) + BOOST_AUTO_TEST_CASE(transfer_to_savings_validate) { try { BOOST_TEST_MESSAGE("Testing: transfer_to_savings_validate"); @@ -5793,54 +5798,27 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); + BOOST_TEST_MESSAGE("--- success with valid parameters"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, amount, ASSET_GBG(1)); + CHECK_PARAM_VALID(op, memo, string(STEEMIT_MAX_MEMO_SIZE-1, ' ')); // valid is < MAX_SIZE + CHECK_PARAM_VALID(op, memo, u8"тест"); - BOOST_TEST_MESSAGE("failure when 'from' is empty"); - op.from = ""; - GOLOS_CHECK_ERROR_PROPS(op.validate(), - CHECK_ERROR(golos::invalid_parameter, "from")); - - - BOOST_TEST_MESSAGE("failure when 'to' is empty"); - op.from = "alice"; - op.to = ""; - GOLOS_CHECK_ERROR_PROPS(op.validate(), - CHECK_ERROR(golos::invalid_parameter, "to")); - - - BOOST_TEST_MESSAGE("sucess when 'to' is not empty"); - op.to = "bob"; - BOOST_CHECK_NO_THROW(op.validate()); - - - BOOST_TEST_MESSAGE("failure when amount is VESTS"); - op.to = "alice"; - op.amount = ASSET("1.000 VESTS"); - GOLOS_CHECK_ERROR_PROPS(op.validate(), - CHECK_ERROR(golos::invalid_parameter, "amount")); - - - BOOST_TEST_MESSAGE("success when amount is SBD"); - op.amount = ASSET("1.000 GBG"); - BOOST_CHECK_NO_THROW(op.validate()); - - - BOOST_TEST_MESSAGE("success when amount is STEEM"); - op.amount = ASSET("1.000 GOLOS"); - BOOST_CHECK_NO_THROW(op.validate()); - + BOOST_TEST_MESSAGE("--- failure when 'from' or `to` is empty"); + CHECK_PARAM_INVALID(op, from, ""); + CHECK_PARAM_INVALID(op, to, ""); - BOOST_TEST_MESSAGE("failure when amount is negative"); - op.memo = std::string(); - op.amount = ASSET("-1.000 GOLOS"); - GOLOS_CHECK_ERROR_PROPS(op.validate(), - CHECK_ERROR(golos::invalid_parameter, "amount")); + BOOST_TEST_MESSAGE("--- failure when amount is GESTS"); + CHECK_PARAM_INVALID(op, amount, ASSET("1.000 GESTS")); // unsupported asset + CHECK_PARAM_INVALID(op, amount, ASSET_GESTS(1)); // gests + BOOST_TEST_MESSAGE("--- failure when amount is negative"); + CHECK_PARAM_INVALID(op, amount, ASSET_GOLOS(-1)); + CHECK_PARAM_INVALID(op, amount, ASSET_GBG(-1)); - BOOST_TEST_MESSAGE("failure when memo too large"); - op.amount = ASSET("1.000 GOLOS"); - op.memo = string(STEEMIT_MAX_MEMO_SIZE, ' '); - GOLOS_CHECK_ERROR_PROPS(op.validate(), - CHECK_ERROR(golos::invalid_parameter, "memo")); + BOOST_TEST_MESSAGE("--- failure when memo invalid"); + CHECK_PARAM_INVALID(op, memo, string(STEEMIT_MAX_MEMO_SIZE, ' ')); + CHECK_PARAM_INVALID(op, memo, BAD_UTF8_STRING); } FC_LOG_AND_RETHROW() } @@ -5848,31 +5826,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(transfer_to_savings_authorities) { try { BOOST_TEST_MESSAGE("Testing: transfer_to_savings_authorities"); - transfer_to_savings_operation op; op.from = "alice"; op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); - - auths.clear(); - expected.clear(); - op.from = "bob"; - op.get_required_active_authorities(auths); - expected.insert("bob"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -5883,10 +5841,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ACTORS((alice)(bob)); generate_block(); - fund("alice", ASSET("10.000 GOLOS")); fund("alice", ASSET("10.000 GBG")); - BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("10.000 GBG")); @@ -5897,96 +5853,62 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.from = "alice"; op.to = "alice"; op.amount = ASSET("20.000 GOLOS"); - - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(insufficient_funds, "alice", "fund", "20.000 GOLOS"))); validate_database(); - BOOST_TEST_MESSAGE("--- failure when transferring to non-existent account"); op.to = "sam"; op.amount = ASSET("1.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "sam"))); validate_database(); - BOOST_TEST_MESSAGE("--- success transferring STEEM to self"); op.to = "alice"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.000 GOLOS")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("1.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- success transferring SBD to self"); op.amount = ASSET("1.000 GBG"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("9.000 GBG")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("1.000 GBG")); validate_database(); - BOOST_TEST_MESSAGE("--- success transferring STEEM to other"); op.to = "bob"; op.amount = ASSET("1.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("8.000 GOLOS")); BOOST_CHECK_EQUAL(db->get_account("bob").savings_balance, ASSET("1.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- success transferring SBD to other"); op.amount = ASSET("1.000 GBG"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("8.000 GBG")); BOOST_CHECK_EQUAL(db->get_account("bob").savings_sbd_balance, ASSET("1.000 GBG")); validate_database(); - BOOST_TEST_MESSAGE("--- failure when transferring without authorities"); op.from = "bob"; op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx, 0), tx_missing_active_auth, {}); + GOLOS_CHECK_THROW_PROPS(push_tx_with_ops(tx, alice_private_key, op), tx_missing_active_auth, {}); validate_database(); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // transfer_to_savings + + + BOOST_AUTO_TEST_SUITE(transfer_from_savings) BOOST_AUTO_TEST_CASE(transfer_from_savings_validate) { try { @@ -5997,38 +5919,27 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.request_id = 0; op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); + BOOST_TEST_MESSAGE("--- success with valid parameters"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, amount, ASSET_GBG(1)); + CHECK_PARAM_VALID(op, memo, string(STEEMIT_MAX_MEMO_SIZE-1, ' ')); // valid is < MAX_SIZE + CHECK_PARAM_VALID(op, memo, u8"тест"); + BOOST_TEST_MESSAGE("--- failure when 'from' or 'to' is empty"); + CHECK_PARAM_INVALID(op, from, ""); + CHECK_PARAM_INVALID(op, to, ""); - BOOST_TEST_MESSAGE("failure when 'from' is empty"); - op.from = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - - BOOST_TEST_MESSAGE("failure when 'to' is empty"); - op.from = "alice"; - op.to = ""; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - - BOOST_TEST_MESSAGE("sucess when 'to' is not empty"); - op.to = "bob"; - op.validate(); - - - BOOST_TEST_MESSAGE("failure when amount is VESTS"); - op.to = "alice"; - op.amount = ASSET("1.000 VESTS"); - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - + BOOST_TEST_MESSAGE("--- failure when amount is GESTS"); + CHECK_PARAM_INVALID(op, amount, ASSET("1.000 GESTS")); // unsupported asset + CHECK_PARAM_INVALID(op, amount, ASSET_GESTS(1)); // gests - BOOST_TEST_MESSAGE("success when amount is SBD"); - op.amount = ASSET("1.000 GBG"); - op.validate(); + BOOST_TEST_MESSAGE("--- failure when amount is negative"); + CHECK_PARAM_INVALID(op, amount, ASSET_GOLOS(-1)); + CHECK_PARAM_INVALID(op, amount, ASSET_GBG(-1)); - - BOOST_TEST_MESSAGE("success when amount is STEEM"); - op.amount = ASSET("1.000 GOLOS"); - op.validate(); + BOOST_TEST_MESSAGE("--- failure when memo invalid"); + CHECK_PARAM_INVALID(op, memo, string(STEEMIT_MAX_MEMO_SIZE, ' ')); + CHECK_PARAM_INVALID(op, memo, BAD_UTF8_STRING); } FC_LOG_AND_RETHROW() } @@ -6036,42 +5947,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(transfer_from_savings_authorities) { try { BOOST_TEST_MESSAGE("Testing: transfer_from_savings_authorities"); - transfer_from_savings_operation op; op.from = "alice"; op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); - - auths.clear(); - expected.clear(); - op.from = "bob"; - op.get_required_active_authorities(auths); - expected.insert("bob"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set()); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE(transfer_from_savings_apply) { - try { + try { BOOST_TEST_MESSAGE("Testing: transfer_from_savings_apply"); ACTORS((alice)(bob)); generate_block(); - fund("alice", ASSET("10.000 GOLOS")); fund("alice", ASSET("10.000 GBG")); @@ -6081,17 +5971,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) save.amount = ASSET("10.000 GOLOS"); signed_transaction tx; - tx.operations.push_back(save); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, save)); save.amount = ASSET("10.000 GBG"); - tx.clear(); - tx.operations.push_back(save); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, save)); BOOST_TEST_MESSAGE("--- failure when account has insufficient funds"); transfer_from_savings_operation op; @@ -6099,34 +5981,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.to = "bob"; op.amount = ASSET("20.000 GOLOS"); op.request_id = 0; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(insufficient_funds, "alice", "savings", "20.000 GOLOS"))); - BOOST_TEST_MESSAGE("--- failure withdrawing to non-existant account"); op.to = "sam"; op.amount = ASSET("1.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "sam"))); - BOOST_TEST_MESSAGE("--- success withdrawing GOLOS to self"); op.to = "alice"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("9.000 GOLOS")); @@ -6139,15 +6007,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); - BOOST_TEST_MESSAGE("--- success withdrawing GBG to self"); op.amount = ASSET("1.000 GBG"); op.request_id = 1; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("0.000 GBG")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("9.000 GBG")); @@ -6160,27 +6023,18 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); - BOOST_TEST_MESSAGE("--- failure withdrawing with repeat request id"); op.amount = ASSET("2.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - - // TODO try to add dublicate transaction throws logic_error - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "savings_withdraw", + fc::mutable_variant_object()("owner","alice")("request_id",op.request_id)))); BOOST_TEST_MESSAGE("--- success withdrawing GOLOS to other"); op.to = "bob"; op.amount = ASSET("1.000 GOLOS"); op.request_id = 3; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("0.000 GOLOS")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_balance, ASSET("8.000 GOLOS")); @@ -6193,15 +6047,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); - BOOST_TEST_MESSAGE("--- success withdrawing GBG to other"); op.amount = ASSET("1.000 GBG"); op.request_id = 4; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").sbd_balance, ASSET("0.000 GBG")); BOOST_CHECK_EQUAL(db->get_account("alice").savings_sbd_balance, ASSET("8.000 GBG")); @@ -6214,7 +6063,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(db->get_savings_withdraw("alice", op.request_id).complete, db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME); validate_database(); - BOOST_TEST_MESSAGE("--- withdraw on timeout"); generate_blocks(db->head_block_time() + STEEMIT_SAVINGS_WITHDRAW_TIME - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); @@ -6234,7 +6082,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, 0); validate_database(); - BOOST_TEST_MESSAGE("--- savings withdraw request limit"); tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); op.to = "alice"; @@ -6242,20 +6089,14 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) for (int i = 0; i < STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT; i++) { op.request_id = i; - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, i + 1); } op.request_id = STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT; - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, - CHECK_ERROR(logic_exception, golos::logic_exception::reached_limit_for_pending_withdraw_requests))); + CHECK_ERROR(logic_exception, logic_exception::reached_limit_for_pending_withdraw_requests))); BOOST_CHECK_EQUAL(db->get_account("alice").savings_withdraw_requests, STEEMIT_SAVINGS_WITHDRAW_REQUEST_LIMIT); validate_database(); @@ -6264,67 +6105,46 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) } BOOST_AUTO_TEST_CASE(transfer_from_savings_memo_storing_flag) { - try { + try { BOOST_TEST_MESSAGE("Testing: transfer_from_savings_memo_storing_flag"); ACTORS((alice)(bob)); generate_block(); - fund("alice", ASSET("10.000 GOLOS")); transfer_to_savings_operation save; save.from = "alice"; save.to = "alice"; save.amount = ASSET("10.000 GOLOS"); - signed_transaction tx; - tx.operations.push_back(save); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, save)); // Default is true - transfer_from_savings_operation op; op.from = "alice"; op.to = "alice"; op.amount = ASSET("1.000 GOLOS"); op.request_id = 1; op.memo = "{\"test\":123}"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); db->set_store_memo_in_savings_withdraws(true); - op.request_id = 2; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == op.memo); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), op.memo); db->set_store_memo_in_savings_withdraws(false); - op.request_id = 3; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(to_string(db->get_savings_withdraw("alice", op.request_id).memo) == ""); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + BOOST_CHECK_EQUAL(to_string(db->get_savings_withdraw("alice", op.request_id).memo), ""); validate_database(); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // transfer_from_savings + BOOST_AUTO_TEST_CASE(cancel_transfer_from_savings_validate) { try { From 14376bb37727afb1d84710f99a27580ddee55b4c Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 22:13:39 +0700 Subject: [PATCH 131/250] Refactor errors: fix delete_comment_operation #790 --- tests/tests/operation_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 4b32ae33d5..72ecf3e033 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6799,7 +6799,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failed when comment missing"); op.author = "alice"; op.permlink = "foo"; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "comment", make_comment_id("alice", "foo")))); validate_database(); @@ -6827,7 +6827,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failed when comment has replies"); op.author = "alice"; op.permlink = "lorem"; - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::cannot_delete_comment_with_replies))); validate_database(); @@ -6835,13 +6835,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- success delete comment"); op.author = "bob"; op.permlink = "bar"; - BOOST_CHECK_NO_THROW(push_tx_with_ops_throw(tx, bob_private_key, op)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); validate_database(); BOOST_TEST_MESSAGE("--- success delete comment after delete replies"); op.author = "alice"; op.permlink = "lorem"; - BOOST_CHECK_NO_THROW(push_tx_with_ops_throw(tx, alice_private_key, op)); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); validate_database(); } FC_LOG_AND_RETHROW() From cbc30e31583b84a43218a37eff5c2cbc02ddcbd4 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 23 Jul 2018 18:43:02 +0300 Subject: [PATCH 132/250] Refactor errors: prove_authority + disabled challenge_authority #790 + authority account_name checks simplification --- libraries/chain/steem_evaluator.cpp | 49 +++--- libraries/protocol/authority.cpp | 146 +++--------------- .../include/golos/protocol/exceptions.hpp | 12 +- .../golos/protocol/steem_operations.hpp | 6 +- libraries/protocol/steem_operations.cpp | 10 +- tests/tests/operation_tests.cpp | 35 +++++ 6 files changed, 101 insertions(+), 157 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 7daf83eaf4..6f473dbb03 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1959,31 +1959,29 @@ namespace golos { namespace chain { } void limit_order_cancel_evaluator::do_apply(const limit_order_cancel_operation &o) { - database &_db = db(); _db.cancel_order(_db.get_limit_order(o.owner, o.orderid)); } void report_over_production_evaluator::do_apply(const report_over_production_operation &o) { - database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_4)) { FC_THROW_EXCEPTION(golos::unsupported_operation, "report_over_production_operation is disabled"); } } - void challenge_authority_evaluator::do_apply(const challenge_authority_operation &o) { - database &_db = db(); + void challenge_authority_evaluator::do_apply(const challenge_authority_operation& o) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__307)) - FC_ASSERT(false, "Challenge authority operation is currently disabled."); - const auto &challenged = _db.get_account(o.challenged); - const auto &challenger = _db.get_account(o.challenger); + GOLOS_ASSERT(false, golos::unsupported_operation, "Challenge authority operation is currently disabled."); + // TODO: update error handling if enable this operation + + const auto& challenged = _db.get_account(o.challenged); + const auto& challenger = _db.get_account(o.challenger); if (o.require_owner) { - FC_ASSERT(challenged.reset_account == - o.challenger, "Owner authority can only be challenged by its reset account."); + FC_ASSERT(challenged.reset_account == o.challenger, + "Owner authority can only be challenged by its reset account."); FC_ASSERT(challenger.balance >= STEEMIT_OWNER_CHALLENGE_FEE); FC_ASSERT(!challenged.owner_challenged); - FC_ASSERT(_db.head_block_time() - challenged.last_owner_proved > - STEEMIT_OWNER_CHALLENGE_COOLDOWN); + FC_ASSERT(_db.head_block_time() - challenged.last_owner_proved > STEEMIT_OWNER_CHALLENGE_COOLDOWN); _db.adjust_balance(challenger, -STEEMIT_OWNER_CHALLENGE_FEE); _db.create_vesting(_db.get_account(o.challenged), STEEMIT_OWNER_CHALLENGE_FEE); @@ -1992,32 +1990,31 @@ namespace golos { namespace chain { a.owner_challenged = true; }); } else { - FC_ASSERT(challenger.balance >= - STEEMIT_ACTIVE_CHALLENGE_FEE, "Account does not have sufficient funds to pay challenge fee."); - FC_ASSERT(!(challenged.owner_challenged || - challenged.active_challenged), "Account is already challenged."); - FC_ASSERT( - _db.head_block_time() - challenged.last_active_proved > - STEEMIT_ACTIVE_CHALLENGE_COOLDOWN, "Account cannot be challenged because it was recently challenged."); + FC_ASSERT(challenger.balance >= STEEMIT_ACTIVE_CHALLENGE_FEE, + "Account does not have sufficient funds to pay challenge fee."); + FC_ASSERT(!(challenged.owner_challenged || challenged.active_challenged), + "Account is already challenged."); + FC_ASSERT(_db.head_block_time() - challenged.last_active_proved > STEEMIT_ACTIVE_CHALLENGE_COOLDOWN, + "Account cannot be challenged because it was recently challenged."); _db.adjust_balance(challenger, -STEEMIT_ACTIVE_CHALLENGE_FEE); _db.create_vesting(_db.get_account(o.challenged), STEEMIT_ACTIVE_CHALLENGE_FEE); - _db.modify(challenged, [&](account_object &a) { + _db.modify(challenged, [&](account_object& a) { a.active_challenged = true; }); } } - void prove_authority_evaluator::do_apply(const prove_authority_operation &o) { - database &_db = db(); - const auto &challenged = _db.get_account(o.challenged); - FC_ASSERT(challenged.owner_challenged || - challenged.active_challenged, "Account is not challeneged. No need to prove authority."); + void prove_authority_evaluator::do_apply(const prove_authority_operation& o) { + const auto& challenged = _db.get_account(o.challenged); + GOLOS_CHECK_LOGIC(challenged.owner_challenged || challenged.active_challenged, + logic_exception::account_is_not_challeneged, + "Account is not challeneged. No need to prove authority."); - _db.modify(challenged, [&](account_object &a) { + _db.modify(challenged, [&](account_object& a) { a.active_challenged = false; - a.last_active_proved = _db.head_block_time(); + a.last_active_proved = _db.head_block_time(); // TODO: if enable `challenge_authority` then check, is it ok to set active always if (o.require_owner) { a.owner_challenged = false; a.last_owner_proved = _db.head_block_time(); diff --git a/libraries/protocol/authority.cpp b/libraries/protocol/authority.cpp index a28e49066c..2bb95d9e69 100644 --- a/libraries/protocol/authority.cpp +++ b/libraries/protocol/authority.cpp @@ -1,22 +1,22 @@ #include #include -namespace golos { - namespace protocol { + +namespace golos { namespace protocol { // authority methods - void authority::add_authority(const public_key_type &k, weight_type w) { + void authority::add_authority(const public_key_type& k, weight_type w) { key_auths[k] = w; } - void authority::add_authority(const account_name_type &k, weight_type w) { + void authority::add_authority(const account_name_type& k, weight_type w) { account_auths[k] = w; } vector authority::get_keys() const { vector result; result.reserve(key_auths.size()); - for (const auto &k : key_auths) { + for (const auto& k : key_auths) { result.push_back(k.first); } return result; @@ -24,10 +24,10 @@ namespace golos { bool authority::is_impossible() const { uint64_t auth_weights = 0; - for (const auto &item : account_auths) { + for (const auto& item : account_auths) { auth_weights += item.second; } - for (const auto &item : key_auths) { + for (const auto& item : key_auths) { auth_weights += item.second; } return auth_weights < weight_threshold; @@ -49,7 +49,11 @@ namespace golos { } - bool is_valid_account_name(const string &name) { +// local inlines to simplify validation checks +inline bool is_letter(char x) { return 'a' <= x && x <= 'z'; } // lowercase only +inline bool is_digit (char x) { return '0' <= x && x <= '9'; } + + bool is_valid_account_name(const string& name) { #if STEEMIT_MIN_ACCOUNT_NAME_LENGTH < 3 #error This is_valid_account_name implementation implicitly enforces minimum name length of 3. #endif @@ -72,121 +76,18 @@ namespace golos { if (end - begin < 3) { return false; } - switch (name[begin]) { - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - break; - default: - return false; + if (!is_letter(name[begin])) { + return false; } - switch (name[end - 1]) { - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - return false; + auto t = name[end - 1]; + if (!is_letter(t) && !is_digit(t)) { + return false; } for (size_t i = begin + 1; i < end - 1; i++) { - switch (name[i]) { - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - break; - default: - return false; - } + t = name[i]; + if (is_letter(t) || is_digit(t) || t == '-') + continue; + return false; } if (end == len) { break; @@ -196,11 +97,10 @@ namespace golos { return true; } - bool operator==(const authority &a, const authority &b) { + bool operator==(const authority& a, const authority& b) { return (a.weight_threshold == b.weight_threshold) && (a.account_auths == b.account_auths) && (a.key_auths == b.key_auths); } - } -} // golos::protocol +} } // golos::protocol diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 8a73e62308..ece8e5214d 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -206,6 +206,11 @@ namespace golos { //account_create_with_delegation not_enough_delegation, + // challenge_authority_operation + cannot_challenge_yourself, + // prove_authority_evaluator + account_is_not_challeneged, + //set_reset_account_operation cannot_set_same_reset_account, @@ -245,7 +250,7 @@ namespace golos { proxy_would_create_loop, proxy_chain_is_too_long, - // convert operation + // convert operation no_price_feed_yet, }; }; @@ -375,6 +380,11 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) + //challenge_authority_operation + (cannot_challenge_yourself) + //prove_authority_evaluator + (account_is_not_challeneged) + //set_reset_account_operation (cannot_set_same_reset_account) diff --git a/libraries/protocol/include/golos/protocol/steem_operations.hpp b/libraries/protocol/include/golos/protocol/steem_operations.hpp index 1f0b73168e..0a131cc642 100644 --- a/libraries/protocol/include/golos/protocol/steem_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_operations.hpp @@ -160,7 +160,7 @@ namespace golos { namespace protocol { void validate() const; - void get_required_active_authorities(flat_set &a) const { + void get_required_active_authorities(flat_set& a) const { a.insert(challenger); } }; @@ -171,13 +171,13 @@ namespace golos { namespace protocol { void validate() const; - void get_required_active_authorities(flat_set &a) const { + void get_required_active_authorities(flat_set& a) const { if (!require_owner) { a.insert(challenged); } } - void get_required_owner_authorities(flat_set &a) const { + void get_required_owner_authorities(flat_set& a) const { if (require_owner) { a.insert(challenged); } diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 5288d6be1f..0d321202fe 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -149,13 +149,15 @@ namespace golos { namespace protocol { } void challenge_authority_operation::validate() const { - validate_account_name(challenger); - validate_account_name(challenged); - FC_ASSERT(challenged != challenger, "cannot challenge yourself"); + GOLOS_CHECK_PARAM_ACCOUNT(challenger); + GOLOS_CHECK_PARAM_ACCOUNT(challenged); + GOLOS_CHECK_LOGIC(challenged != challenger, + logic_exception::cannot_challenge_yourself, + "cannot challenge yourself"); } void prove_authority_operation::validate() const { - validate_account_name(challenged); + GOLOS_CHECK_PARAM_ACCOUNT(challenged); } void vote_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 85239def25..a031884c9c 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -4441,6 +4441,41 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE(prove_authority) + // Technically it can be called, but will fail early due disabled challenge_authority_operation + BOOST_AUTO_TEST_CASE(prove_authority_validate) { try { + BOOST_TEST_MESSAGE("Testing: prove_authority_validate"); + prove_authority_operation op; + op.challenged = "bob"; + CHECK_OP_VALID(op); + CHECK_PARAM_INVALID(op, challenged, ""); + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(prove_authority_authorities) { try { + BOOST_TEST_MESSAGE("Testing: prove_authority_authorities"); + prove_authority_operation op; + op.challenged = "bob"; + op.require_owner = true; + CHECK_OP_AUTHS(op, account_name_set({"bob"}), account_name_set(), account_name_set()); + op.require_owner = false; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(prove_authority_apply) { try { + BOOST_TEST_MESSAGE("Testing: prove_authority_apply"); + ACTOR(bob) + prove_authority_operation op; + op.challenged = "bob"; + signed_transaction tx; + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::account_is_not_challeneged))); + validate_database(); + } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // prove_authority + + BOOST_AUTO_TEST_CASE(escrow_transfer_validate) { try { BOOST_TEST_MESSAGE("Testing: escrow_transfer_validate"); From c8b1f43a6a78e182d2d4338f2a16ede6fa166fb0 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 18:15:57 +0700 Subject: [PATCH 133/250] Refactor errors: comment_options_operation #790 --- libraries/chain/steem_evaluator.cpp | 59 ++++++++++--------- .../include/golos/protocol/exceptions.hpp | 16 +++++ libraries/protocol/steem_operations.cpp | 59 ++++++++++--------- tests/tests/operation_tests.cpp | 53 ++++++++--------- 4 files changed, 105 insertions(+), 82 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 57a6c63c5b..b37efea26e 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -475,17 +475,21 @@ namespace golos { namespace chain { void operator()(const comment_payout_beneficiaries &cpb) const { if (_db.is_producing()) { - FC_ASSERT(cpb.beneficiaries.size() <= STEEMIT_MAX_COMMENT_BENEFICIARIES, - "Cannot specify more than ${m} beneficiaries.", ("m", STEEMIT_MAX_COMMENT_BENEFICIARIES)); + GOLOS_CHECK_LOGIC(cpb.beneficiaries.size() <= STEEMIT_MAX_COMMENT_BENEFICIARIES, + logic_exception::cannot_specify_more_beneficiaries, + "Cannot specify more than ${m} beneficiaries.", ("m", STEEMIT_MAX_COMMENT_BENEFICIARIES)); } - FC_ASSERT(_c.beneficiaries.size() == 0, "Comment already has beneficiaries specified."); - FC_ASSERT(_c.abs_rshares == 0, "Comment must not have been voted on before specifying beneficiaries."); + GOLOS_CHECK_LOGIC(_c.beneficiaries.size() == 0, + logic_exception::comment_already_has_beneficiaries, + "Comment already has beneficiaries specified."); + GOLOS_CHECK_LOGIC(_c.abs_rshares == 0, + logic_exception::comment_must_not_have_been_voted, + "Comment must not have been voted on before specifying beneficiaries."); _db.modify(_c, [&](comment_object &c) { for (auto &b : cpb.beneficiaries) { - auto acc = _db.find< account_object, by_name >( b.account ); - FC_ASSERT( acc != nullptr, "Beneficiary \"${a}\" must exist.", ("a", b.account) ); + _db.get_account(b.account); // check beneficiary exists c.beneficiaries.push_back(b); } }); @@ -496,30 +500,31 @@ namespace golos { namespace chain { database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) { const auto &auth = _db.get_account(o.author); - FC_ASSERT(!(auth.owner_challenged || auth.active_challenged), - "Operation cannot be processed because account is currently challenged."); + GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), + logic_exception::account_is_currently_challenged, + "Operation cannot be processed because account is currently challenged."); } const auto &comment = _db.get_comment(o.author, o.permlink); if (!o.allow_curation_rewards || !o.allow_votes || o.max_accepted_payout < comment.max_accepted_payout) { - FC_ASSERT(comment.abs_rshares == 0, - "One of the included comment options requires the comment to have no rshares allocated to it."); - } - - if (!_db.has_hardfork(STEEMIT_HARDFORK_0_17__432)) {// TODO: Remove after hardfork 17 - FC_ASSERT(o.extensions.size() == 0, - "Operation extensions for the comment_options_operation are not currently supported."); - } - - FC_ASSERT(comment.allow_curation_rewards >= o.allow_curation_rewards, - "Curation rewards cannot be re-enabled."); - FC_ASSERT(comment.allow_votes >= o.allow_votes, - "Voting cannot be re-enabled."); - FC_ASSERT(comment.max_accepted_payout >= o.max_accepted_payout, - "A comment cannot accept a greater payout."); - FC_ASSERT(comment.percent_steem_dollars >= o.percent_steem_dollars, - "A comment cannot accept a greater percent SBD."); + GOLOS_CHECK_LOGIC(comment.abs_rshares == 0, + logic_exception::comment_options_requires_no_rshares, + "One of the included comment options requires the comment to have no rshares allocated to it."); + } + + GOLOS_CHECK_LOGIC(comment.allow_curation_rewards >= o.allow_curation_rewards, + logic_exception::curation_rewards_cannot_be_reenabled, + "Curation rewards cannot be re-enabled."); + GOLOS_CHECK_LOGIC(comment.allow_votes >= o.allow_votes, + logic_exception::voting_cannot_be_reenabled, + "Voting cannot be re-enabled."); + GOLOS_CHECK_LOGIC(comment.max_accepted_payout >= o.max_accepted_payout, + logic_exception::comment_cannot_accept_greater_payout, + "A comment cannot accept a greater payout."); + GOLOS_CHECK_LOGIC(comment.percent_steem_dollars >= o.percent_steem_dollars, + logic_exception::comment_cannot_accept_greater_percent_GBG, + "A comment cannot accept a greater percent SBD."); _db.modify(comment, [&](comment_object &c) { c.max_accepted_payout = o.max_accepted_payout; @@ -539,7 +544,7 @@ namespace golos { namespace chain { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__55)) - GOLOS_CHECK_LOGIC(o.title.size() + o.body.size() + o.json_metadata.size(), + GOLOS_CHECK_LOGIC(o.title.size() + o.body.size() + o.json_metadata.size(), logic_exception::cannot_update_comment_because_nothing_changed, "Cannot update comment because nothing appears to be changing."); @@ -549,7 +554,7 @@ namespace golos { namespace chain { const auto &auth = _db.get_account(o.author); /// prove it exists if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) - GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), + GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), logic_exception::account_is_currently_challenged, "Operation cannot be processed because account is currently challenged."); diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 3e0a877c50..14d1815c2e 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -200,6 +200,14 @@ namespace golos { comment_editable_during_first_24_hours, cannot_delete_comment_with_replies, cannot_delete_comment_with_positive_votes, + comment_options_requires_no_rshares, + curation_rewards_cannot_be_reenabled, + voting_cannot_be_reenabled, + comment_cannot_accept_greater_payout, + comment_cannot_accept_greater_percent_GBG, + cannot_specify_more_beneficiaries, + comment_already_has_beneficiaries, + comment_must_not_have_been_voted, // withdraw_vesting insufficient_fee_for_powerdown_registered_account, @@ -374,6 +382,14 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (comment_editable_during_first_24_hours) (cannot_delete_comment_with_replies) (cannot_delete_comment_with_positive_votes) + (comment_options_requires_no_rshares) + (curation_rewards_cannot_be_reenabled) + (voting_cannot_be_reenabled) + (comment_cannot_accept_greater_payout) + (comment_cannot_accept_greater_percent_GBG) + (cannot_specify_more_beneficiaries) + (comment_already_has_beneficiaries) + (comment_must_not_have_been_voted) // withdraw_vesting (insufficient_fee_for_powerdown_registered_account) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 25a3dc6b0c..c5a3eb7496 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -107,37 +107,40 @@ namespace golos { namespace protocol { }; void comment_payout_beneficiaries::validate() const { - uint32_t sum = 0; - - FC_ASSERT(beneficiaries.size(), "Must specify at least one beneficiary"); - FC_ASSERT(beneficiaries.size() < 128, - "Cannot specify more than 127 beneficiaries."); // Require size serializtion fits in one byte. - - validate_account_name(beneficiaries[0].account); - FC_ASSERT(beneficiaries[0].weight <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to one account"); - sum += beneficiaries[0].weight; - FC_ASSERT(sum <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to a comment"); // Have to check incrementally to avoid overflow - - for (size_t i = 1; i < beneficiaries.size(); i++) { - validate_account_name( beneficiaries[i].account); - FC_ASSERT(beneficiaries[i].weight <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to one account"); - sum += beneficiaries[i].weight; - FC_ASSERT(sum <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to a comment"); // Have to check incrementally to avoid overflow - FC_ASSERT(beneficiaries[i - 1] < beneficiaries[i], - "Benficiaries must be specified in sorted order (account ascending)"); - } + fc::safe sum = 0; + + GOLOS_CHECK_PARAM(beneficiaries, { + GOLOS_CHECK_VALUE(beneficiaries.size(), "Must specify at least one beneficiary"); + GOLOS_CHECK_VALUE(beneficiaries.size() < 128, + "Cannot specify more than 127 beneficiaries."); // Require size serializtion fits in one byte. + + try { + for (auto beneficiar: beneficiaries) { + validate_account_name(beneficiaries[0].account); + GOLOS_CHECK_VALUE(beneficiar.weight <= STEEMIT_100_PERCENT, + "Cannot allocate more than 100% of rewards to one account"); + sum += beneficiar.weight; + } + + GOLOS_CHECK_VALUE(sum <= STEEMIT_100_PERCENT, + "Cannot allocate more than 100% of rewards to a comment"); + } catch(const fc::overflow_exception& e) { + GOLOS_CHECK_VALUE(false, "Cannot allocate more than 100% of rewards to a comment"); // Have to check incrementally to avoid overflow + } + + for (size_t i = 1; i < beneficiaries.size(); i++) { + GOLOS_CHECK_VALUE(beneficiaries[i - 1] < beneficiaries[i], + "Benficiaries ${first} and ${second} not in sorted order (account ascending)", + ("first", beneficiaries[i-1].account)("second", beneficiaries[i].account)); + } + }); } void comment_options_operation::validate() const { - validate_account_name(author); - FC_ASSERT(percent_steem_dollars <= STEEMIT_100_PERCENT, "Percent cannot exceed 100%"); - FC_ASSERT(max_accepted_payout.symbol == SBD_SYMBOL, "Max accepted payout must be in GBG"); - FC_ASSERT(max_accepted_payout.amount.value >= 0, "Cannot accept less than 0 payout"); - validate_permlink(permlink); + GOLOS_CHECK_PARAM_ACCOUNT(author); + GOLOS_CHECK_PARAM(percent_steem_dollars, GOLOS_CHECK_VALUE_LE(percent_steem_dollars, STEEMIT_100_PERCENT)); + GOLOS_CHECK_PARAM(max_accepted_payout, GOLOS_CHECK_ASSET_GE0(max_accepted_payout, GBG)); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); for (auto &e : extensions) { e.visit(comment_options_extension_validate_visitor()); } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 72ecf3e033..cd61a043e7 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6600,7 +6600,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) comment_payout_beneficiaries b; b.beneficiaries.push_back(beneficiary_route_type(account_name_type("bob"), STEEMIT_100_PERCENT + 1)); op.extensions.insert(b); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "beneficiaries")); BOOST_TEST_MESSAGE("--- Testing more than 100% total weight"); b.beneficiaries.clear(); @@ -6608,7 +6609,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type(account_name_type("sam"), STEEMIT_1_PERCENT * 75)); op.extensions.clear(); op.extensions.insert(b); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "beneficiaries")); BOOST_TEST_MESSAGE("--- Testing maximum number of routes"); b.beneficiaries.clear(); @@ -6619,15 +6621,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.extensions.clear(); std::sort(b.beneficiaries.begin(), b.beneficiaries.end()); op.extensions.insert(b); - op.validate(); + BOOST_CHECK_NO_THROW(op.validate()); BOOST_TEST_MESSAGE("--- Testing one too many routes"); b.beneficiaries.push_back(beneficiary_route_type(account_name_type("bar"), 1)); std::sort(b.beneficiaries.begin(), b.beneficiaries.end()); op.extensions.clear(); op.extensions.insert(b); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "beneficiaries")); BOOST_TEST_MESSAGE("--- Testing duplicate accounts"); b.beneficiaries.clear(); @@ -6635,7 +6637,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type("bob", STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "beneficiaries")); BOOST_TEST_MESSAGE("--- Testing incorrect account sort order"); b.beneficiaries.clear(); @@ -6643,7 +6646,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type("alice", STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - STEEMIT_REQUIRE_THROW(op.validate(), fc::assert_exception); + GOLOS_CHECK_ERROR_PROPS(op.validate(), + CHECK_ERROR(invalid_parameter, "beneficiaries")); BOOST_TEST_MESSAGE("--- Testing correct account sort order"); b.beneficiaries.clear(); @@ -6651,7 +6655,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type("bob", STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - op.validate(); + BOOST_CHECK_NO_THROW(op.validate()); } FC_LOG_AND_RETHROW() } @@ -6683,10 +6687,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) comment.title = "test"; comment.body = "foobar"; - tx.operations.push_back(comment); - tx.set_expiration(db->head_block_time() + STEEMIT_MIN_TRANSACTION_EXPIRATION_LIMIT); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, comment)); BOOST_TEST_MESSAGE("--- Test failure on max of benefactors"); b.beneficiaries.push_back(beneficiary_route_type(account_name_type("bob"), STEEMIT_1_PERCENT)); @@ -6702,10 +6703,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.permlink = "test"; op.allow_curation_rewards = false; op.extensions.insert(b); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_specify_more_beneficiaries))); BOOST_TEST_MESSAGE("--- Test specifying a non-existent benefactor"); @@ -6713,10 +6713,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type(account_name_type("dave"), STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "account", "dave"))); BOOST_TEST_MESSAGE("--- Test setting when comment has been voted on"); @@ -6735,14 +6734,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) tx.operations.push_back(op); tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_invalid_operation, {}); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx), + CHECK_ERROR(tx_invalid_operation, 1, + CHECK_ERROR(logic_exception, logic_exception::comment_options_requires_no_rshares))); BOOST_TEST_MESSAGE("--- Test success"); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); BOOST_TEST_MESSAGE("--- Test setting when there are already beneficiaries"); @@ -6750,8 +6748,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type(account_name_type("sam"), 25 * STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - tx.sign(alice_private_key, db->get_chain_id()); - GOLOS_CHECK_THROW_PROPS(db->push_transaction(tx), tx_duplicate_transaction, {}); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::comment_already_has_beneficiaries))); } FC_LOG_AND_RETHROW() } From 942bbbf947b8761cfd17cdde6b2a9d76e0787675 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 22:10:48 +0700 Subject: [PATCH 134/250] Refactor errors: comment_options_operation (review fixes) #790 --- libraries/protocol/steem_operations.cpp | 22 +++++++++------------- tests/tests/operation_tests.cpp | 6 +++--- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index c5a3eb7496..604f582523 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -107,27 +107,23 @@ namespace golos { namespace protocol { }; void comment_payout_beneficiaries::validate() const { - fc::safe sum = 0; + fc::safe sum = 0; // avoid overflow GOLOS_CHECK_PARAM(beneficiaries, { GOLOS_CHECK_VALUE(beneficiaries.size(), "Must specify at least one beneficiary"); GOLOS_CHECK_VALUE(beneficiaries.size() < 128, "Cannot specify more than 127 beneficiaries."); // Require size serializtion fits in one byte. - try { - for (auto beneficiar: beneficiaries) { - validate_account_name(beneficiaries[0].account); - GOLOS_CHECK_VALUE(beneficiar.weight <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to one account"); - sum += beneficiar.weight; - } - - GOLOS_CHECK_VALUE(sum <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to a comment"); - } catch(const fc::overflow_exception& e) { - GOLOS_CHECK_VALUE(false, "Cannot allocate more than 100% of rewards to a comment"); // Have to check incrementally to avoid overflow + for (auto beneficiar: beneficiaries) { + validate_account_name(beneficiaries[0].account); + GOLOS_CHECK_VALUE(beneficiar.weight <= STEEMIT_100_PERCENT, + "Cannot allocate more than 100% of rewards to one account"); + sum += beneficiar.weight; } + GOLOS_CHECK_VALUE(sum <= STEEMIT_100_PERCENT, + "Cannot allocate more than 100% of rewards to a comment"); + for (size_t i = 1; i < beneficiaries.size(); i++) { GOLOS_CHECK_VALUE(beneficiaries[i - 1] < beneficiaries[i], "Benficiaries ${first} and ${second} not in sorted order (account ascending)", diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index cd61a043e7..b5a8c0890e 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -6703,7 +6703,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.permlink = "test"; op.allow_curation_rewards = false; op.extensions.insert(b); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::cannot_specify_more_beneficiaries))); @@ -6713,7 +6713,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type(account_name_type("dave"), STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "dave"))); @@ -6748,7 +6748,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) b.beneficiaries.push_back(beneficiary_route_type(account_name_type("sam"), 25 * STEEMIT_1_PERCENT)); op.extensions.clear(); op.extensions.insert(b); - GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops_throw(tx, alice_private_key, op), + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(logic_exception, logic_exception::comment_already_has_beneficiaries))); } From 42474881b1a9fc6471887b3df76b43fec36d6673 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 23 Jul 2018 19:53:53 +0700 Subject: [PATCH 135/250] Refactor errors: set_withdraw_vesting_route_operation #790 --- libraries/chain/steem_evaluator.cpp | 18 +++-- .../include/golos/protocol/exceptions.hpp | 6 ++ libraries/protocol/steem_operations.cpp | 7 +- tests/tests/operation_time_tests.cpp | 76 ++++++++----------- 4 files changed, 52 insertions(+), 55 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 57a6c63c5b..ae3f9dd0fe 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1017,10 +1017,13 @@ namespace golos { namespace chain { auto itr = wd_idx.find(boost::make_tuple(from_account.id, to_account.id)); if (itr == wd_idx.end()) { - FC_ASSERT( - o.percent != 0, "Cannot create a 0% destination."); - FC_ASSERT(from_account.withdraw_routes < - STEEMIT_MAX_WITHDRAW_ROUTES, "Account already has the maximum number of routes."); + GOLOS_CHECK_LOGIC(o.percent != 0, + logic_exception::cannot_create_zero_percent_destination, + "Cannot create a 0% destination."); + GOLOS_CHECK_LOGIC(from_account.withdraw_routes < STEEMIT_MAX_WITHDRAW_ROUTES, + logic_exception::reached_maxumum_number_of_routes, + "Account already has the maximum number of routes (${max}).", + ("max",STEEMIT_MAX_WITHDRAW_ROUTES)); _db.create([&](withdraw_vesting_route_object &wvdo) { wvdo.from_account = from_account.id; @@ -1048,7 +1051,7 @@ namespace golos { namespace chain { } itr = wd_idx.upper_bound(boost::make_tuple(from_account.id, account_id_type())); - uint16_t total_percent = 0; + fc::safe total_percent = 0; while (itr->from_account == from_account.id && itr != wd_idx.end()) { @@ -1056,8 +1059,9 @@ namespace golos { namespace chain { ++itr; } - FC_ASSERT(total_percent <= - STEEMIT_100_PERCENT, "More than 100% of vesting withdrawals allocated to destinations."); + GOLOS_CHECK_LOGIC(total_percent <= STEEMIT_100_PERCENT, + logic_exception::more_100percent_allocated_to_destinations, + "More than 100% of vesting withdrawals allocated to destinations."); } FC_CAPTURE_AND_RETHROW() } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 3e0a877c50..332fb4fbe8 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -204,6 +204,9 @@ namespace golos { // withdraw_vesting insufficient_fee_for_powerdown_registered_account, operation_would_not_change_vesting_withdraw_rate, + cannot_create_zero_percent_destination, + reached_maxumum_number_of_routes, + more_100percent_allocated_to_destinations, //account_create_with_delegation not_enough_delegation, @@ -378,6 +381,9 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // withdraw_vesting (insufficient_fee_for_powerdown_registered_account) (operation_would_not_change_vesting_withdraw_rate) + (cannot_create_zero_percent_destination) + (reached_maxumum_number_of_routes) + (more_100percent_allocated_to_destinations) //set_reset_account_operation (cannot_set_same_reset_account) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 25a3dc6b0c..ea2c829e36 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -205,10 +205,9 @@ namespace golos { namespace protocol { } void set_withdraw_vesting_route_operation::validate() const { - validate_account_name(from_account); - validate_account_name(to_account); - FC_ASSERT(0 <= percent && percent <= - STEEMIT_100_PERCENT, "Percent must be valid golos percent"); + GOLOS_CHECK_PARAM_ACCOUNT(from_account); + GOLOS_CHECK_PARAM_ACCOUNT(to_account); + GOLOS_CHECK_PARAM(percent, GOLOS_CHECK_VALUE_LEGE(percent, 0, STEEMIT_100_PERCENT)); } diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 2ac9a02455..4bc6b5fc9d 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -939,29 +939,23 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) wv.vesting_shares = withdraw_amount; signed_transaction tx; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(wv); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - tx.operations.clear(); - tx.signatures.clear(); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, wv)); BOOST_TEST_MESSAGE("Setting up bob destination"); - set_withdraw_vesting_route_operation op; - op.from_account = "alice"; - op.to_account = "bob"; - op.percent = STEEMIT_1_PERCENT * 50; - op.auto_vest = true; - tx.operations.push_back(op); + set_withdraw_vesting_route_operation op_bob; + op_bob.from_account = "alice"; + op_bob.to_account = "bob"; + op_bob.percent = STEEMIT_1_PERCENT * 50; + op_bob.auto_vest = true; BOOST_TEST_MESSAGE("Setting up sam destination"); - op.to_account = "sam"; - op.percent = STEEMIT_1_PERCENT * 30; - op.auto_vest = false; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + set_withdraw_vesting_route_operation op_sam; + op_sam.from_account = "alice"; + op_sam.to_account = "sam"; + op_sam.percent = STEEMIT_1_PERCENT * 30; + op_sam.auto_vest = false; + + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op_bob, op_sam)); BOOST_TEST_MESSAGE("Setting up first withdraw"); @@ -986,16 +980,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) (vesting_withdraw_rate.amount * STEEMIT_1_PERCENT * 20) / STEEMIT_100_PERCENT, VESTS_SYMBOL) * gpo.get_vesting_share_price(); - BOOST_REQUIRE(alice.balance == alice_total); - BOOST_REQUIRE(alice.vesting_shares == old_alice_vesting - vesting_withdraw_rate); + BOOST_CHECK_EQUAL(alice.balance, alice_total); + BOOST_CHECK_EQUAL(alice.vesting_shares, old_alice_vesting - vesting_withdraw_rate); auto bob_total = old_bob_vesting + asset( (vesting_withdraw_rate.amount * STEEMIT_1_PERCENT * 50) / STEEMIT_100_PERCENT, VESTS_SYMBOL); - BOOST_REQUIRE(bob.vesting_shares == bob_total); - BOOST_REQUIRE(bob.balance == old_bob_balance); + BOOST_CHECK_EQUAL(bob.vesting_shares, bob_total); + BOOST_CHECK_EQUAL(bob.balance, old_bob_balance); auto sam_total = old_sam_balance + @@ -1003,8 +997,8 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) (vesting_withdraw_rate.amount * STEEMIT_1_PERCENT * 30) / STEEMIT_100_PERCENT, VESTS_SYMBOL) * gpo.get_vesting_share_price(); - BOOST_REQUIRE(sam.balance == sam_total); - BOOST_REQUIRE(sam.vesting_shares == old_sam_vesting); + BOOST_CHECK_EQUAL(sam.balance, sam_total); + BOOST_CHECK_EQUAL(sam.vesting_shares, old_sam_vesting); old_alice_balance = alice.balance; old_alice_vesting = alice.vesting_shares; @@ -1016,26 +1010,20 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_TEST_MESSAGE("Test failure with greater than 100% destination assignment"); - tx.operations.clear(); - tx.signatures.clear(); - + set_withdraw_vesting_route_operation op; + op.from_account = "alice"; op.to_account = "sam"; op.percent = STEEMIT_1_PERCENT * 50 + 1; - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + op.auto_vest = false; + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::more_100percent_allocated_to_destinations))); BOOST_TEST_MESSAGE("Test from_account receiving no withdraw"); - tx.operations.clear(); - tx.signatures.clear(); - op.to_account = "sam"; op.percent = STEEMIT_1_PERCENT * 50; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); generate_blocks(db->get_account("alice").next_vesting_withdrawal, true); { @@ -1044,25 +1032,25 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) const auto& sam = db->get_account("sam"); auto& gpo = db->get_dynamic_global_properties(); - BOOST_REQUIRE(alice.vesting_shares == old_alice_vesting - vesting_withdraw_rate); - BOOST_REQUIRE(alice.balance == old_alice_balance); + BOOST_CHECK_EQUAL(alice.vesting_shares, old_alice_vesting - vesting_withdraw_rate); + BOOST_CHECK_EQUAL(alice.balance, old_alice_balance); auto bob_vesting = old_bob_vesting + asset( (vesting_withdraw_rate.amount * STEEMIT_1_PERCENT * 50) / STEEMIT_100_PERCENT, VESTS_SYMBOL); - BOOST_REQUIRE(bob.vesting_shares == bob_vesting); - BOOST_REQUIRE(bob.balance == old_bob_balance); + BOOST_CHECK_EQUAL(bob.vesting_shares, bob_vesting); + BOOST_CHECK_EQUAL(bob.balance, old_bob_balance); - BOOST_REQUIRE(sam.vesting_shares == old_sam_vesting); + BOOST_CHECK_EQUAL(sam.vesting_shares, old_sam_vesting); auto sam_total = old_sam_balance + asset( (vesting_withdraw_rate.amount * STEEMIT_1_PERCENT * 50) / STEEMIT_100_PERCENT, VESTS_SYMBOL) * gpo.get_vesting_share_price(); - BOOST_REQUIRE(sam.balance == sam_total); + BOOST_CHECK_EQUAL(sam.balance, sam_total); } } FC_LOG_AND_RETHROW() From c071a0e0508bb3de3431bccb4bb6271295dc1cec Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 24 Jul 2018 12:26:23 +0700 Subject: [PATCH 136/250] Refactor errors: pow & pow2 operations #790 --- libraries/chain/steem_evaluator.cpp | 92 ++++++++++++------- .../include/golos/protocol/exceptions.hpp | 24 +++++ libraries/protocol/steem_operations.cpp | 43 +++++---- 3 files changed, 102 insertions(+), 57 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 57a6c63c5b..bd8e963720 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1684,9 +1684,9 @@ namespace golos { namespace chain { db.has_hardfork(STEEMIT_HARDFORK_0_5__59)) { const auto &witness_by_work = db.get_index().indices().get(); auto work_itr = witness_by_work.find(o.work.work); - if (work_itr != witness_by_work.end()) { - FC_ASSERT(!"DUPLICATE WORK DISCOVERED", "${w} ${witness}", ("w", o)("witness", *work_itr)); - } + GOLOS_CHECK_LOGIC(work_itr == witness_by_work.end(), + logic_exception::duplicate_work_discovered, + "Duplicate work discovered (${work} ${witness})", ("work", o)("witness", *work_itr)); } const auto& name = o.get_worker_account(); @@ -1717,22 +1717,29 @@ namespace golos { namespace chain { const auto &worker_account = db.get_account(name); // verify it exists const auto &worker_auth = db.get_authority(name); - FC_ASSERT(worker_auth.active.num_auths() == - 1, "Miners can only have one key authority. ${a}", ("a", worker_auth.active)); - FC_ASSERT(worker_auth.active.key_auths.size() == - 1, "Miners may only have one key authority."); - FC_ASSERT(worker_auth.active.key_auths.begin()->first == - o.work.worker, "Work must be performed by key that signed the work."); - FC_ASSERT( - o.block_id == db.head_block_id(), "pow not for last block"); + GOLOS_CHECK_LOGIC(worker_auth.active.num_auths() == 1, + logic_exception::miners_can_only_have_one_key_authority, + "Miners can only have one key authority. ${a}", ("a", worker_auth.active)); + GOLOS_CHECK_LOGIC(worker_auth.active.key_auths.size() == 1, + logic_exception::miners_can_only_have_one_key_authority, + "Miners may only have one key authority."); + GOLOS_CHECK_LOGIC(worker_auth.active.key_auths.begin()->first == o.work.worker, + logic_exception::work_must_be_performed_by_signed_key, + "Work must be performed by key that signed the work."); + GOLOS_CHECK_LOGIC(o.block_id == db.head_block_id(), + logic_exception::work_not_for_last_block, + "pow not for last block"); + if (db.has_hardfork(STEEMIT_HARDFORK_0_13__256)) - FC_ASSERT(worker_account.last_account_update < - db.head_block_time(), "Worker account must not have updated their account this block."); + GOLOS_CHECK_LOGIC(worker_account.last_account_update < db.head_block_time(), + logic_exception::account_must_not_be_updated_in_this_block, + "Worker account must not have updated their account this block."); fc::sha256 target = db.get_pow_target(); - FC_ASSERT( - o.work.work < target, "Work lacks sufficient difficulty."); + GOLOS_CHECK_LOGIC(o.work.work < target, + logic_exception::insufficient_work_difficalty, + "Work lacks sufficient difficulty."); db.modify(dgp, [&](dynamic_global_property_object &p) { p.total_pow++; // make sure this doesn't break anything... @@ -1742,8 +1749,9 @@ namespace golos { namespace chain { const witness_object *cur_witness = db.find_witness(worker_account.name); if (cur_witness) { - FC_ASSERT(cur_witness->pow_worker == - 0, "This account is already scheduled for pow block production."); + GOLOS_CHECK_LOGIC(cur_witness->pow_worker == 0, + logic_exception::account_already_scheduled_for_work, + "This account is already scheduled for pow block production."); db.modify(*cur_witness, [&](witness_object &w) { w.props = o.props; w.pow_worker = dgp.total_pow; @@ -1775,7 +1783,9 @@ namespace golos { namespace chain { } void pow_evaluator::do_apply(const pow_operation &o) { - FC_ASSERT(!db().has_hardfork(STEEMIT_HARDFORK_0_13__256), "pow is deprecated. Use pow2 instead"); + if (db().has_hardfork(STEEMIT_HARDFORK_0_13__256)) { + FC_THROW_EXCEPTION(golos::unsupported_operation, "pow is deprecated. Use pow2 instead"); + } pow_apply(db(), o); } @@ -1788,26 +1798,32 @@ namespace golos { namespace chain { if (db.has_hardfork(STEEMIT_HARDFORK_0_16__551)) { const auto &work = o.work.get(); - FC_ASSERT(work.prev_block == - db.head_block_id(), "Equihash pow op not for last block"); + GOLOS_CHECK_LOGIC(work.prev_block == db.head_block_id(), + logic_exception::work_not_for_last_block, + "Equihash pow op not for last block"); auto recent_block_num = protocol::block_header::num_from_id(work.input.prev_block); - FC_ASSERT(recent_block_num > dgp.last_irreversible_block_num, + GOLOS_CHECK_LOGIC(recent_block_num > dgp.last_irreversible_block_num, + logic_exception::work_for_block_older_last_irreversible_block, "Equihash pow done for block older than last irreversible block num"); - FC_ASSERT(work.pow_summary < - target_pow, "Insufficient work difficulty. Work: ${w}, Target: ${t}", ("w", work.pow_summary)("t", target_pow)); + GOLOS_CHECK_LOGIC(work.pow_summary < target_pow, + logic_exception::insufficient_work_difficalty, + "Insufficient work difficulty. Work: ${w}, Target: ${t}", ("w", work.pow_summary)("t", target_pow)); worker_account = work.input.worker_account; } else { const auto &work = o.work.get(); - FC_ASSERT(work.input.prev_block == - db.head_block_id(), "Work not for last block"); - FC_ASSERT(work.pow_summary < - target_pow, "Insufficient work difficulty. Work: ${w}, Target: ${t}", ("w", work.pow_summary)("t", target_pow)); + GOLOS_CHECK_LOGIC(work.input.prev_block == db.head_block_id(), + logic_exception::work_not_for_last_block, + "Work not for last block"); + GOLOS_CHECK_LOGIC(work.pow_summary < target_pow, + logic_exception::insufficient_work_difficalty, + "Insufficient work difficulty. Work: ${w}, Target: ${t}", ("w", work.pow_summary)("t", target_pow)); worker_account = work.input.worker_account; } - FC_ASSERT(o.props.maximum_block_size >= - STEEMIT_MIN_BLOCK_SIZE_LIMIT * - 2, "Voted maximum block size is too small."); + GOLOS_CHECK_OP_PARAM(o, props.maximum_block_size, + GOLOS_CHECK_VALUE(o.props.maximum_block_size >= STEEMIT_MIN_BLOCK_SIZE_LIMIT * 2, + "Voted maximum block size is too small. Must be more then ${max} bytes.", + ("max", STEEMIT_MIN_BLOCK_SIZE_LIMIT * 2))); db.modify(dgp, [&](dynamic_global_property_object &p) { p.total_pow++; @@ -1817,7 +1833,8 @@ namespace golos { namespace chain { const auto &accounts_by_name = db.get_index().indices().get(); auto itr = accounts_by_name.find(worker_account); if (itr == accounts_by_name.end()) { - FC_ASSERT(o.new_owner_key.valid(), "New owner key is not valid."); + GOLOS_CHECK_OP_PARAM(o, new_owner_key, + GOLOS_CHECK_VALUE(o.new_owner_key.valid(), "Key is not valid.")); db.create([&](account_object &acc) { acc.name = worker_account; acc.memo_key = *o.new_owner_key; @@ -1841,11 +1858,16 @@ namespace golos { namespace chain { w.pow_worker = dgp.total_pow; }); } else { - FC_ASSERT(!o.new_owner_key.valid(), "Cannot specify an owner key unless creating account."); + GOLOS_CHECK_LOGIC(!o.new_owner_key.valid(), + logic_exception::cannot_specify_owner_key_unless_creating_account, + "Cannot specify an owner key unless creating account."); const witness_object *cur_witness = db.find_witness(worker_account); - FC_ASSERT(cur_witness, "Witness must be created for existing account before mining."); - FC_ASSERT(cur_witness->pow_worker == - 0, "This account is already scheduled for pow block production."); + GOLOS_CHECK_LOGIC(cur_witness, + logic_exception::witness_must_be_created_before_minning, + "Witness must be created for existing account before mining."); + GOLOS_CHECK_LOGIC(cur_witness->pow_worker == 0, + logic_exception::account_already_scheduled_for_work, + "This account is already scheduled for pow block production."); db.modify(*cur_witness, [&](witness_object &w) { w.props = o.props; w.pow_worker = dgp.total_pow; diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 3e0a877c50..d2f91c188f 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -249,6 +249,18 @@ namespace golos { // convert operation no_price_feed_yet, + + // pow operation + duplicate_work_discovered, + miners_can_only_have_one_key_authority, + work_must_be_performed_by_signed_key, + work_not_for_last_block, + work_for_block_older_last_irreversible_block, + account_must_not_be_updated_in_this_block, + insufficient_work_difficalty, + account_already_scheduled_for_work, + cannot_specify_owner_key_unless_creating_account, + witness_must_be_created_before_minning, }; }; @@ -423,6 +435,18 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // convert operation (no_price_feed_yet) + + // pow operation + (duplicate_work_discovered) + (miners_can_only_have_one_key_authority) + (work_must_be_performed_by_signed_key) + (work_not_for_last_block) + (work_for_block_older_last_irreversible_block) + (account_must_not_be_updated_in_this_block) + (insufficient_work_difficalty) + (account_already_scheduled_for_work) + (cannot_specify_owner_key_unless_creating_account) + (witness_must_be_created_before_minning) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 25a3dc6b0c..10b42462f7 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -308,10 +308,11 @@ namespace golos { namespace protocol { void pow_operation::validate() const { props.validate(); - validate_account_name(worker_account); - FC_ASSERT(work_input() == - work.input, "Determninistic input does not match recorded input"); - work.validate(); + GOLOS_CHECK_PARAM_ACCOUNT(worker_account); + GOLOS_CHECK_PARAM(work, { + GOLOS_CHECK_VALUE(work_input() == work.input, "Determninistic input does not match recorded input"); + work.validate(); + }); } struct pow2_operation_validate_visitor { @@ -387,35 +388,33 @@ namespace golos { namespace protocol { } void pow::validate() const { - FC_ASSERT(work != fc::sha256()); - FC_ASSERT( - public_key_type(fc::ecc::public_key(signature, input, false)) == - worker); + GOLOS_CHECK_VALUE(work != fc::sha256(), "Work must not equal empty hash value"); + GOLOS_CHECK_VALUE(worker == public_key_type(fc::ecc::public_key(signature, input, false)), + "Work doesn't match to worker"); auto sig_hash = fc::sha256::hash(signature); public_key_type recover = fc::ecc::public_key(signature, sig_hash, false); - FC_ASSERT(work == fc::sha256::hash(recover)); + GOLOS_CHECK_VALUE(work == fc::sha256::hash(recover), "Invalid work result"); } void pow2::validate() const { - validate_account_name(input.worker_account); + GOLOS_CHECK_PARAM_ACCOUNT(input.worker_account); pow2 tmp; tmp.create(input.prev_block, input.worker_account, input.nonce); - FC_ASSERT(pow_summary == - tmp.pow_summary, "reported work does not match calculated work"); + GOLOS_CHECK_PARAM(pow_summary, + GOLOS_CHECK_VALUE(pow_summary == tmp.pow_summary, "reported work does not match calculated work")); } void equihash_pow::validate() const { - validate_account_name(input.worker_account); + GOLOS_CHECK_PARAM_ACCOUNT(input.worker_account); auto seed = fc::sha256::hash(input); - FC_ASSERT(proof.n == - STEEMIT_EQUIHASH_N, "proof of work 'n' value is incorrect"); - FC_ASSERT(proof.k == - STEEMIT_EQUIHASH_K, "proof of work 'k' value is incorrect"); - FC_ASSERT(proof.seed == - seed, "proof of work seed does not match expected seed"); - FC_ASSERT(proof.is_valid(), "proof of work is not a solution", ("block_id", input.prev_block)("worker_account", input.worker_account)("nonce", input.nonce)); - FC_ASSERT(pow_summary == - fc::sha256::hash(proof.inputs).approx_log_32()); + GOLOS_CHECK_PARAM(proof, { + GOLOS_CHECK_VALUE(proof.n == STEEMIT_EQUIHASH_N, "proof of work 'n' value is incorrect"); + GOLOS_CHECK_VALUE(proof.k == STEEMIT_EQUIHASH_K, "proof of work 'k' value is incorrect"); + GOLOS_CHECK_VALUE(proof.seed == seed, "proof of work seed does not match expected seed"); + GOLOS_CHECK_VALUE(proof.is_valid(), "proof of work is not a solution", ("block_id", input.prev_block)("worker_account", input.worker_account)("nonce", input.nonce)); + }); + GOLOS_CHECK_PARAM(pow_summary, + GOLOS_CHECK_VALUE_EQ(pow_summary, fc::sha256::hash(proof.inputs).approx_log_32())); } void feed_publish_operation::validate() const { From e074cd9c60fc9164b7bf7a80feb9a51c2716bf18 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 24 Jul 2018 17:43:05 +0700 Subject: [PATCH 137/250] Refactor errors: account_history plugin #791 --- plugins/account_history/plugin.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index ea0ce46f94..5c1c8d1a65 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -4,13 +4,11 @@ #include #include +#include #include #define STEEM_NAMESPACE_PREFIX "golos::protocol::" -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); - namespace golos { namespace plugins { namespace account_history { struct operation_visitor_filter; @@ -113,8 +111,8 @@ if (options.count(name)) { \ uint64_t from, uint32_t limit ) { - FC_ASSERT(limit <= 10000, "Limit of ${l} is greater than maxmimum allowed", ("l", limit)); - FC_ASSERT(from >= limit, "From must be greater than limit"); + GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, 10000)); + GOLOS_CHECK_PARAM(from, GOLOS_CHECK_VALUE(from >= limit, "From must be greater then limit")); // idump((account)(from)(limit)); const auto& idx = database.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(account, from)); @@ -135,10 +133,10 @@ if (options.count(name)) { \ }; DEFINE_API(plugin, get_account_history) { - CHECK_ARG_SIZE(3) - auto account = args.args->at(0).as(); - auto from = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + GOLOS_CHECK_ARGS_COUNT(args.args, 3); + GOLOS_DECLARE_PARAM(account, args.args->at(0).as()); + GOLOS_DECLARE_PARAM(from, args.args->at(1).as()); + GOLOS_DECLARE_PARAM(limit, args.args->at(2).as()); return pimpl->database.with_weak_read_lock([&]() { return pimpl->get_account_history(account, from, limit); From a933bddcd9996b5a6d0d258f8e5039189131fbd9 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Tue, 24 Jul 2018 16:28:19 +0300 Subject: [PATCH 138/250] Refactor errors: account recovery operations #790 * request_account_recovery_operation * recover_account_operation * change_recovery_account_operation --- libraries/chain/database.cpp | 22 +- libraries/chain/steem_evaluator.cpp | 153 +++--- .../include/golos/protocol/exceptions.hpp | 18 + libraries/protocol/steem_operations.cpp | 31 +- tests/tests/operation_tests.cpp | 472 ++++++++++-------- 5 files changed, 385 insertions(+), 311 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index f66b27b2ad..99a1133eb8 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2832,36 +2832,34 @@ namespace golos { namespace chain { void database::account_recovery_processing() { // Clear expired recovery requests - const auto &rec_req_idx = get_index().indices().get(); + const auto& rec_req_idx = get_index().indices().get(); auto rec_req = rec_req_idx.begin(); - while (rec_req != rec_req_idx.end() && - rec_req->expires <= head_block_time()) { + while (rec_req != rec_req_idx.end() && rec_req->expires <= head_block_time()) { remove(*rec_req); rec_req = rec_req_idx.begin(); } // Clear invalid historical authorities - const auto &hist_idx = get_index().indices(); //by id + const auto& hist_idx = get_index().indices(); //by id auto hist = hist_idx.begin(); - while (hist != hist_idx.end() && time_point_sec( - hist->last_valid_time + - STEEMIT_OWNER_AUTH_RECOVERY_PERIOD) < head_block_time()) { + while ( + hist != hist_idx.end() && + time_point_sec(hist->last_valid_time + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD) < head_block_time() + ) { remove(*hist); hist = hist_idx.begin(); } // Apply effective recovery_account changes - const auto &change_req_idx = get_index().indices().get(); + const auto& change_req_idx = get_index().indices().get(); auto change_req = change_req_idx.begin(); - while (change_req != change_req_idx.end() && - change_req->effective_on <= head_block_time()) { - modify(get_account(change_req->account_to_recover), [&](account_object &a) { + while (change_req != change_req_idx.end() && change_req->effective_on <= head_block_time()) { + modify(get_account(change_req->account_to_recover), [&](account_object& a) { a.recovery_account = change_req->recovery_account; }); - remove(*change_req); change_req = change_req_idx.begin(); } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 9b4396e800..a91d90b95f 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2025,130 +2025,129 @@ namespace golos { namespace chain { }); } - void request_account_recovery_evaluator::do_apply(const request_account_recovery_operation &o) { - database &_db = db(); - const auto &account_to_recover = _db.get_account(o.account_to_recover); - - if (account_to_recover.recovery_account.length()) // Make sure recovery matches expected recovery account - FC_ASSERT(account_to_recover.recovery_account == - o.recovery_account, "Cannot recover an account that does not have you as there recovery partner."); - else // Empty string recovery account defaults to top witness - FC_ASSERT( - _db.get_index().indices().get().begin()->owner == - o.recovery_account, "Top witness must recover an account with no recovery partner."); + void request_account_recovery_evaluator::do_apply(const request_account_recovery_operation& o) { + const auto& account_to_recover = _db.get_account(o.account_to_recover); + if (account_to_recover.recovery_account.length()) { + // Make sure recovery matches expected recovery account + GOLOS_CHECK_LOGIC(account_to_recover.recovery_account == o.recovery_account, + logic_exception::cannot_recover_if_not_partner, + "Cannot recover an account that does not have you as there recovery partner."); + } else { + // Empty string recovery account defaults to top witness + GOLOS_CHECK_LOGIC( + _db.get_index().indices().get().begin()->owner == o.recovery_account, + logic_exception::must_be_recovered_by_top_witness, + "Top witness must recover an account with no recovery partner."); + } - const auto &recovery_request_idx = _db.get_index().indices().get(); + const auto& recovery_request_idx = + _db.get_index().indices().get(); auto request = recovery_request_idx.find(o.account_to_recover); - if (request == recovery_request_idx.end()) // New Request - { - FC_ASSERT(!o.new_owner_authority.is_impossible(), "Cannot recover using an impossible authority."); - FC_ASSERT(o.new_owner_authority.weight_threshold, "Cannot recover using an open authority."); - + if (request == recovery_request_idx.end()) { + // New Request + GOLOS_CHECK_OP_PARAM(o, new_owner_authority, { + GOLOS_CHECK_VALUE(!o.new_owner_authority.is_impossible(), + "Cannot recover using an impossible authority."); + GOLOS_CHECK_VALUE(o.new_owner_authority.weight_threshold, + "Cannot recover using an open authority."); + }); // Check accounts in the new authority exist - if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || - _db.is_producing())) { - for (auto &a : o.new_owner_authority.account_auths) { + if (_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || _db.is_producing()) { + for (auto& a : o.new_owner_authority.account_auths) { _db.get_account(a.first); } } - - _db.create([&](account_recovery_request_object &req) { + _db.create([&](account_recovery_request_object& req) { req.account_to_recover = o.account_to_recover; req.new_owner_authority = o.new_owner_authority; - req.expires = _db.head_block_time() + - STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD; + req.expires = _db.head_block_time() + STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD; }); - } else if (o.new_owner_authority.weight_threshold == - 0) // Cancel Request if authority is open - { + } else if (o.new_owner_authority.weight_threshold == 0) { + // Cancel Request if authority is open _db.remove(*request); - } else // Change Request - { - FC_ASSERT(!o.new_owner_authority.is_impossible(), "Cannot recover using an impossible authority."); - + } else { + // Change Request + GOLOS_CHECK_OP_PARAM(o, new_owner_authority, { + GOLOS_CHECK_VALUE(!o.new_owner_authority.is_impossible(), + "Cannot recover using an impossible authority."); + }); // Check accounts in the new authority exist - if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || - _db.is_producing())) { - for (auto &a : o.new_owner_authority.account_auths) { + if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || _db.is_producing())) { + for (auto& a : o.new_owner_authority.account_auths) { _db.get_account(a.first); } } - - _db.modify(*request, [&](account_recovery_request_object &req) { + _db.modify(*request, [&](account_recovery_request_object& req) { req.new_owner_authority = o.new_owner_authority; - req.expires = _db.head_block_time() + - STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD; + req.expires = _db.head_block_time() + STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD; }); } } - void recover_account_evaluator::do_apply(const recover_account_operation &o) { - database &_db = db(); - const auto &account = _db.get_account(o.account_to_recover); + void recover_account_evaluator::do_apply(const recover_account_operation& o) { + const auto& account = _db.get_account(o.account_to_recover); + const auto now = _db.head_block_time(); - if (_db.has_hardfork(STEEMIT_HARDFORK_0_12)) - FC_ASSERT( - _db.head_block_time() - account.last_account_recovery > - STEEMIT_OWNER_UPDATE_LIMIT, "Owner authority can only be updated once an hour."); + if (_db.has_hardfork(STEEMIT_HARDFORK_0_12)) { + GOLOS_CHECK_BANDWIDTH(now, account.last_account_recovery + STEEMIT_OWNER_UPDATE_LIMIT, + bandwidth_exception::change_owner_authority_bandwidth, + "Owner authority can only be updated once an hour."); + } - const auto &recovery_request_idx = _db.get_index().indices().get(); + const auto& recovery_request_idx = _db.get_index().indices().get(); auto request = recovery_request_idx.find(o.account_to_recover); - FC_ASSERT(request != - recovery_request_idx.end(), "There are no active recovery requests for this account."); - FC_ASSERT(request->new_owner_authority == - o.new_owner_authority, "New owner authority does not match recovery request."); + GOLOS_CHECK_LOGIC(request != recovery_request_idx.end(), + logic_exception::no_active_recovery_request, + "There are no active recovery requests for this account."); + GOLOS_CHECK_LOGIC(request->new_owner_authority == o.new_owner_authority, + logic_exception::authority_does_not_match_request, + "New owner authority does not match recovery request."); - const auto &recent_auth_idx = _db.get_index().indices().get(); + const auto& recent_auth_idx = _db.get_index().indices().get(); auto hist = recent_auth_idx.lower_bound(o.account_to_recover); bool found = false; - while (hist != recent_auth_idx.end() && - hist->account == o.account_to_recover && !found) { - found = hist->previous_owner_authority == - o.recent_owner_authority; + while (hist != recent_auth_idx.end() && hist->account == o.account_to_recover && !found) { + found = hist->previous_owner_authority == o.recent_owner_authority; if (found) { break; } ++hist; } - - FC_ASSERT(found, "Recent authority not found in authority history."); + GOLOS_CHECK_LOGIC(found, logic_exception::no_recent_authority_in_history, + "Recent authority not found in authority history."); _db.remove(*request); // Remove first, update_owner_authority may invalidate iterator _db.update_owner_authority(account, o.new_owner_authority); - _db.modify(account, [&](account_object &a) { - a.last_account_recovery = _db.head_block_time(); + _db.modify(account, [&](account_object& a) { + a.last_account_recovery = now; }); } - void change_recovery_account_evaluator::do_apply(const change_recovery_account_operation &o) { - database &_db = db(); + void change_recovery_account_evaluator::do_apply(const change_recovery_account_operation& o) { _db.get_account(o.new_recovery_account); // Simply validate account exists - const auto &account_to_recover = _db.get_account(o.account_to_recover); - - const auto &change_recovery_idx = _db.get_index().indices().get(); + const auto& account_to_recover = _db.get_account(o.account_to_recover); + const auto& change_recovery_idx = + _db.get_index().indices().get(); auto request = change_recovery_idx.find(o.account_to_recover); - if (request == change_recovery_idx.end()) // New request - { - _db.create([&](change_recovery_account_request_object &req) { + if (request == change_recovery_idx.end()) { + // New request + _db.create([&](change_recovery_account_request_object& req) { req.account_to_recover = o.account_to_recover; req.recovery_account = o.new_recovery_account; - req.effective_on = _db.head_block_time() + - STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; + req.effective_on = _db.head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; }); - } else if (account_to_recover.recovery_account != - o.new_recovery_account) // Change existing request - { - _db.modify(*request, [&](change_recovery_account_request_object &req) { + } else if (account_to_recover.recovery_account != o.new_recovery_account) { + // Change existing request + _db.modify(*request, [&](change_recovery_account_request_object& req) { req.recovery_account = o.new_recovery_account; - req.effective_on = _db.head_block_time() + - STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; + req.effective_on = _db.head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD; }); - } else // Request exists and changing back to current recovery account - { + } else { + // Request exists and changing back to current recovery account _db.remove(*request); } } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index f681d5b388..6460acc3ee 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -213,6 +213,15 @@ namespace golos { // prove_authority_evaluator account_is_not_challeneged, + // request_account_recovery + cannot_recover_if_not_partner, + must_be_recovered_by_top_witness, + // recover_account_operation + cannot_set_recent_recovery, + no_active_recovery_request, + authority_does_not_match_request, + no_recent_authority_in_history, + //set_reset_account_operation cannot_set_same_reset_account, @@ -389,6 +398,15 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, //prove_authority_evaluator (account_is_not_challeneged) + // request_account_recovery + (cannot_recover_if_not_partner) + (must_be_recovered_by_top_witness) + // recover_account_operation + (cannot_set_recent_recovery) + (no_active_recovery_request) + (authority_does_not_match_request) + (no_recent_authority_in_history) + //set_reset_account_operation (cannot_set_same_reset_account) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index c749f481e1..9fc87aa663 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -550,25 +550,30 @@ namespace golos { namespace protocol { } void request_account_recovery_operation::validate() const { - validate_account_name(recovery_account); - validate_account_name(account_to_recover); - new_owner_authority.validate(); + GOLOS_CHECK_PARAM_ACCOUNT(recovery_account); + GOLOS_CHECK_PARAM_ACCOUNT(account_to_recover); + GOLOS_CHECK_PARAM_VALIDATE(new_owner_authority); } void recover_account_operation::validate() const { - validate_account_name(account_to_recover); - FC_ASSERT(!(new_owner_authority == - recent_owner_authority), "Cannot set new owner authority to the recent owner authority"); - FC_ASSERT(!new_owner_authority.is_impossible(), "new owner authority cannot be impossible"); - FC_ASSERT(!recent_owner_authority.is_impossible(), "recent owner authority cannot be impossible"); - FC_ASSERT(new_owner_authority.weight_threshold, "new owner authority cannot be trivial"); - new_owner_authority.validate(); - recent_owner_authority.validate(); + GOLOS_CHECK_PARAM_ACCOUNT(account_to_recover); + GOLOS_CHECK_PARAM(new_owner_authority, { + GOLOS_CHECK_LOGIC(!(new_owner_authority == recent_owner_authority), + logic_exception::cannot_set_recent_recovery, + "Cannot set new owner authority to the recent owner authority"); + GOLOS_CHECK_VALUE(!new_owner_authority.is_impossible(), "new owner authority cannot be impossible"); + GOLOS_CHECK_VALUE(new_owner_authority.weight_threshold, "new owner authority cannot be trivial"); + new_owner_authority.validate(); + }); + GOLOS_CHECK_PARAM(recent_owner_authority, { + GOLOS_CHECK_VALUE(!recent_owner_authority.is_impossible(), "recent owner authority cannot be impossible"); + recent_owner_authority.validate(); + }); } void change_recovery_account_operation::validate() const { - validate_account_name(account_to_recover); - validate_account_name(new_recovery_account); + GOLOS_CHECK_PARAM_ACCOUNT(account_to_recover); + GOLOS_CHECK_PARAM_ACCOUNT(new_recovery_account); } void transfer_to_savings_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 062a4488eb..54f4f3a3c4 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -3823,15 +3823,144 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) FC_LOG_AND_RETHROW() } +//------------------------------------------------------------- + BOOST_AUTO_TEST_SUITE(recovery) + +#define TRIVIAL_AUTHORITY authority(0, "acc0", 1) +#define IMPOSSIBLE_AUTHORITY authority(3, "acc1", 1, "acc2", 1) +#define INVALID_AUTHORITY authority(2, "good1", 1, "2bad", 1) + + BOOST_AUTO_TEST_SUITE(request_account_recovery) + + BOOST_AUTO_TEST_CASE(request_account_recovery_validate) { try { + BOOST_TEST_MESSAGE("Testing: request_account_recovery_validate"); + request_account_recovery_operation op; + op.recovery_account = "alice"; + op.account_to_recover = "bob"; + op.new_owner_authority = authority(1, "sam", 1); + BOOST_TEST_MESSAGE("--- success on valid params"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, new_owner_authority, authority(3, "one", 1, "two", 2)); + CHECK_PARAM_VALID(op, new_owner_authority, authority()); + CHECK_PARAM_VALID(op, new_owner_authority, TRIVIAL_AUTHORITY); + CHECK_PARAM_VALID(op, new_owner_authority, IMPOSSIBLE_AUTHORITY); + + BOOST_TEST_MESSAGE("--- fail when recovery_account or account_to_recover invalid"); + CHECK_PARAM_INVALID(op, recovery_account, ""); + CHECK_PARAM_INVALID(op, account_to_recover, ""); + + BOOST_TEST_MESSAGE("--- fail when new_owner_authority invalid"); + // TODO: create separate test for authority::validate() + CHECK_PARAM_INVALID(op, new_owner_authority, authority(1, "no", 1)); + CHECK_PARAM_INVALID(op, new_owner_authority, authority(2, "good", 1, "no", 1)); + CHECK_PARAM_INVALID(op, new_owner_authority, INVALID_AUTHORITY); + + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(request_account_recovery_authorities) { try { + BOOST_TEST_MESSAGE("Testing: request_account_recovery_authorities"); + request_account_recovery_operation op; + op.recovery_account = "alice"; + op.account_to_recover = "bob"; + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set()); + } FC_LOG_AND_RETHROW() } + + // tested in account_recovery and change_recovery_account test cases + // BOOST_AUTO_TEST_CASE(request_account_recovery_apply) { try { + // } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE_END() // request_account_recovery + + + BOOST_AUTO_TEST_SUITE(recover_account) + + BOOST_AUTO_TEST_CASE(recover_account_validate) { try { + BOOST_TEST_MESSAGE("Testing: recover_account_validate"); + recover_account_operation op; + op.account_to_recover = "bob"; + op.new_owner_authority = authority(1, "alice", 1); + op.recent_owner_authority = authority(1, "sam", 1); + // TODO: key-based authorities + BOOST_TEST_MESSAGE("--- success on valid params"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, recent_owner_authority, authority()); + CHECK_PARAM_VALID(op, recent_owner_authority, TRIVIAL_AUTHORITY); + + BOOST_TEST_MESSAGE("--- fail when account_to_recover is invalid"); + CHECK_PARAM_INVALID(op, account_to_recover, ""); + + BOOST_TEST_MESSAGE("--- fail when new_owner_authority is bad"); + CHECK_PARAM_INVALID_LOGIC(op, new_owner_authority, authority(1, "sam", 1), cannot_set_recent_recovery); + CHECK_PARAM_INVALID(op, new_owner_authority, authority()); + CHECK_PARAM_INVALID(op, new_owner_authority, TRIVIAL_AUTHORITY); + CHECK_PARAM_INVALID(op, new_owner_authority, IMPOSSIBLE_AUTHORITY); + CHECK_PARAM_INVALID(op, new_owner_authority, INVALID_AUTHORITY); + + BOOST_TEST_MESSAGE("--- fail when recent_owner_authority is bad"); + CHECK_PARAM_INVALID(op, recent_owner_authority, IMPOSSIBLE_AUTHORITY); + CHECK_PARAM_INVALID(op, recent_owner_authority, INVALID_AUTHORITY); + + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(recover_account_authorities) { try { + BOOST_TEST_MESSAGE("Testing: recover_account_authorities"); + recover_account_operation op; + op.account_to_recover = "alice"; + op.new_owner_authority = authority(1, "bob", 1); + op.recent_owner_authority = authority(1, "sam", 1); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set()); + const auto bob_and_sam = vector{op.new_owner_authority, op.recent_owner_authority}; + vector req; + op.get_required_authorities(req); + BOOST_CHECK_EQUAL(bob_and_sam, req); + // TODO: maybe here can be some more complex checks (like multisig) + } FC_LOG_AND_RETHROW() } + + // tested in account_recovery and change_recovery_account test cases + // BOOST_AUTO_TEST_CASE(recover_account_apply) { try { + // } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE_END() // recover_account + + + BOOST_AUTO_TEST_SUITE(change_recovery_account) + + BOOST_AUTO_TEST_CASE(change_recovery_account_validate) { try { + BOOST_TEST_MESSAGE("Testing: change_recovery_account_validate"); + change_recovery_account_operation op; + op.account_to_recover = "alice"; + op.new_recovery_account = "bob"; + BOOST_TEST_MESSAGE("--- success on valid params"); + CHECK_OP_VALID(op); + + BOOST_TEST_MESSAGE("--- fail when account_to_recover or new_recovery_account is invalid"); + CHECK_PARAM_INVALID(op, account_to_recover, ""); + CHECK_PARAM_INVALID(op, new_recovery_account, ""); + + } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_CASE(change_recovery_account_authorities) { try { + BOOST_TEST_MESSAGE("Testing: change_recovery_account_authorities"); + change_recovery_account_operation op; + op.account_to_recover = "alice"; + op.new_recovery_account = "bob"; + CHECK_OP_AUTHS(op, account_name_set({"alice"}), account_name_set(), account_name_set()); + } FC_LOG_AND_RETHROW() } + + // tested in change_recovery_account test cases + // BOOST_AUTO_TEST_CASE(change_recovery_account_apply) { try { + // } FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE_END() // change_recovery_account + + BOOST_AUTO_TEST_CASE(account_recovery) { try { BOOST_TEST_MESSAGE("Testing: account recovery"); - ACTORS((alice)); fund("alice", 1000000); - BOOST_TEST_MESSAGE("Creating account bob with alice"); - + BOOST_TEST_MESSAGE("--- Creating account bob with alice"); account_create_operation acc_create; acc_create.fee = ASSET("10.000 GOLOS"); acc_create.creator = "alice"; @@ -3842,345 +3971,270 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) acc_create.memo_key = generate_private_key("bob_memo").get_public_key(); acc_create.json_metadata = ""; - signed_transaction tx; - tx.operations.push_back(acc_create); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - const auto &bob_auth = db->get("bob"); - BOOST_REQUIRE(bob_auth.owner == acc_create.owner); - - - BOOST_TEST_MESSAGE("Changing bob's owner authority"); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, acc_create)); + const auto& bob_auth = db->get("bob"); + BOOST_CHECK_EQUAL(bob_auth.owner, acc_create.owner); + BOOST_TEST_MESSAGE("--- Changing bob's owner authority"); account_update_operation acc_update; acc_update.account = "bob"; acc_update.owner = authority(1, generate_private_key("bad_key").get_public_key(), 1); acc_update.memo_key = acc_create.memo_key; acc_update.json_metadata = ""; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, generate_private_key("bob_owner"), acc_update)); + BOOST_CHECK_EQUAL(bob_auth.owner, *acc_update.owner); - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(acc_update); - tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(bob_auth.owner == *acc_update.owner); - - - BOOST_TEST_MESSAGE("Creating recover request for bob with alice"); - + BOOST_TEST_MESSAGE("--- Creating recover request for bob with alice"); request_account_recovery_operation request; request.recovery_account = "alice"; request.account_to_recover = "bob"; request.new_owner_authority = authority(1, generate_private_key("new_key").get_public_key(), 1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, request)); + BOOST_CHECK_EQUAL(bob_auth.owner, *acc_update.owner); - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(request); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(bob_auth.owner == *acc_update.owner); - - - BOOST_TEST_MESSAGE("Recovering bob's account with original owner auth and new secret"); - + BOOST_TEST_MESSAGE("--- Recovering bob's account with original owner auth and new secret"); generate_blocks(db->head_block_time() + STEEMIT_OWNER_UPDATE_LIMIT); - recover_account_operation recover; recover.account_to_recover = "bob"; recover.new_owner_authority = request.new_owner_authority; recover.recent_owner_authority = acc_create.owner; - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); tx.sign(generate_private_key("new_key"), db->get_chain_id()); - db->push_transaction(tx, 0); - const auto &owner1 = db->get("bob").owner; - - BOOST_REQUIRE(owner1 == recover.new_owner_authority); - + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_TEST_MESSAGE("Creating new recover request for a bogus key"); + const auto& owner1 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner1, recover.new_owner_authority); + BOOST_TEST_MESSAGE("--- Creating new recover request for a bogus key"); request.new_owner_authority = authority(1, generate_private_key("foo bar").get_public_key(), 1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, request)); - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(request); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - - BOOST_TEST_MESSAGE("Testing failure when bob does not have new authority"); - - generate_blocks(db->head_block_time() + STEEMIT_OWNER_UPDATE_LIMIT + - fc::seconds(STEEMIT_BLOCK_INTERVAL)); - + BOOST_TEST_MESSAGE("--- Testing failure when bob does not have new authority"); + generate_blocks(db->head_block_time() + STEEMIT_OWNER_UPDATE_LIMIT + fc::seconds(STEEMIT_BLOCK_INTERVAL)); recover.new_owner_authority = authority(1, generate_private_key("idontknow").get_public_key(), 1); - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); tx.sign(generate_private_key("idontknow"), db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - const auto &owner2 = db->get("bob").owner; - BOOST_REQUIRE(owner2 == - authority(1, generate_private_key("new_key").get_public_key(), 1)); - + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::authority_does_not_match_request))); - BOOST_TEST_MESSAGE("Testing failure when bob does not have old authority"); + const auto& owner2 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner2, authority(1, generate_private_key("new_key").get_public_key(), 1)); + BOOST_TEST_MESSAGE("--- Testing failure when bob does not have old authority"); recover.recent_owner_authority = authority(1, generate_private_key("idontknow").get_public_key(), 1); recover.new_owner_authority = authority(1, generate_private_key("foo bar").get_public_key(), 1); - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); tx.sign(generate_private_key("foo bar"), db->get_chain_id()); tx.sign(generate_private_key("idontknow"), db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - const auto &owner3 = db->get("bob").owner; - BOOST_REQUIRE(owner3 == - authority(1, generate_private_key("new_key").get_public_key(), 1)); - + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::no_recent_authority_in_history))); - BOOST_TEST_MESSAGE("Testing using the same old owner auth again for recovery"); + const auto& owner3 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner3, authority(1, generate_private_key("new_key").get_public_key(), 1)); + BOOST_TEST_MESSAGE("--- Testing using the same old owner auth again for recovery"); recover.recent_owner_authority = authority(1, generate_private_key("bob_owner").get_public_key(), 1); recover.new_owner_authority = authority(1, generate_private_key("foo bar").get_public_key(), 1); - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); tx.sign(generate_private_key("foo bar"), db->get_chain_id()); - db->push_transaction(tx, 0); - - const auto &owner4 = db->get("bob").owner; - BOOST_REQUIRE(owner4 == recover.new_owner_authority); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - BOOST_TEST_MESSAGE("Creating a recovery request that will expire"); + const auto& owner4 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner4, recover.new_owner_authority); + BOOST_TEST_MESSAGE("--- Creating a recovery request that will expire"); request.new_owner_authority = authority(1, generate_private_key("expire").get_public_key(), 1); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, request)); - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(request); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - const auto &request_idx = db->get_index().indices(); + const auto& request_idx = db->get_index().indices(); auto req_itr = request_idx.begin(); - - BOOST_REQUIRE(req_itr->account_to_recover == "bob"); - BOOST_REQUIRE(req_itr->new_owner_authority == - authority(1, generate_private_key("expire").get_public_key(), 1)); - BOOST_REQUIRE(req_itr->expires == db->head_block_time() + - STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD); + BOOST_CHECK_EQUAL(req_itr->account_to_recover, "bob"); + BOOST_CHECK_EQUAL(req_itr->new_owner_authority, + authority(1, generate_private_key("expire").get_public_key(), 1)); + BOOST_CHECK_EQUAL(req_itr->expires, + db->head_block_time() + STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD); auto expires = req_itr->expires; ++req_itr; - BOOST_REQUIRE(req_itr == request_idx.end()); - - generate_blocks(time_point_sec( - expires - STEEMIT_BLOCK_INTERVAL), true); - - const auto &new_request_idx = db->get_index().indices(); - BOOST_REQUIRE(new_request_idx.begin() != new_request_idx.end()); + BOOST_CHECK(req_itr == request_idx.end()); + generate_blocks(time_point_sec(expires - STEEMIT_BLOCK_INTERVAL), true); + const auto& new_request_idx = db->get_index().indices(); + BOOST_CHECK(new_request_idx.begin() != new_request_idx.end()); generate_block(); - - BOOST_REQUIRE(new_request_idx.begin() == new_request_idx.end()); + BOOST_CHECK(new_request_idx.begin() == new_request_idx.end()); recover.new_owner_authority = authority(1, generate_private_key("expire").get_public_key(), 1); recover.recent_owner_authority = authority(1, generate_private_key("bob_owner").get_public_key(), 1); - - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); - tx.set_expiration(db->head_block_time()); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(generate_private_key("expire"), db->get_chain_id()); tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - const auto &owner5 = db->get("bob").owner; - BOOST_REQUIRE(owner5 == - authority(1, generate_private_key("foo bar").get_public_key(), 1)); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::no_active_recovery_request))); - BOOST_TEST_MESSAGE("Expiring owner authority history"); + const auto& owner5 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner5, authority(1, generate_private_key("foo bar").get_public_key(), 1)); + BOOST_TEST_MESSAGE("--- Expiring owner authority history"); acc_update.owner = authority(1, generate_private_key("new_key").get_public_key(), 1); - - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(acc_update); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(generate_private_key("foo bar"), db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, generate_private_key("foo bar"), acc_update)); generate_blocks(db->head_block_time() + - (STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - - STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD)); + (STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - STEEMIT_ACCOUNT_RECOVERY_REQUEST_EXPIRATION_PERIOD)); generate_block(); - request.new_owner_authority = authority(1, generate_private_key("last key").get_public_key(), 1); - - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(request); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, request)); recover.new_owner_authority = request.new_owner_authority; recover.recent_owner_authority = authority(1, generate_private_key("bob_owner").get_public_key(), 1); - - tx.operations.clear(); - tx.signatures.clear(); - + tx.clear(); tx.operations.push_back(recover); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(generate_private_key("bob_owner"), db->get_chain_id()); tx.sign(generate_private_key("last key"), db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - const auto &owner6 = db->get("bob").owner; - BOOST_REQUIRE(owner6 == - authority(1, generate_private_key("new_key").get_public_key(), 1)); - - recover.recent_owner_authority = authority(1, generate_private_key("foo bar").get_public_key(), 1); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::no_recent_authority_in_history))); - tx.operations.clear(); - tx.signatures.clear(); + const auto& owner6 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner6, authority(1, generate_private_key("new_key").get_public_key(), 1)); + recover.recent_owner_authority = authority(1, generate_private_key("foo bar").get_public_key(), 1); + tx.clear(); tx.operations.push_back(recover); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(generate_private_key("foo bar"), db->get_chain_id()); tx.sign(generate_private_key("last key"), db->get_chain_id()); - db->push_transaction(tx, 0); - const auto &owner7 = db->get("bob").owner; - BOOST_REQUIRE(owner7 == - authority(1, generate_private_key("last key").get_public_key(), 1)); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); + + const auto& owner7 = db->get("bob").owner; + BOOST_CHECK_EQUAL(owner7, authority(1, generate_private_key("last key").get_public_key(), 1)); } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE(change_recovery_account) { + BOOST_AUTO_TEST_CASE(change_recovery_account_apply) { try { + using fc::ecc::private_key; BOOST_TEST_MESSAGE("Testing change_recovery_account_operation"); + ACTORS((alice)(sam)) - ACTORS((alice)(bob)(sam)(tyler)) - - auto change_recovery_account = [&](const std::string &account_to_recover, const std::string &new_recovery_account) { + auto change_recovery_account = [&](const string& account_to_recover, const string& new_recovery_account) { change_recovery_account_operation op; op.account_to_recover = account_to_recover; op.new_recovery_account = new_recovery_account; - signed_transaction tx; - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + - STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, alice_private_key, op); }; - auto recover_account = [&](const std::string &account_to_recover, const fc::ecc::private_key &new_owner_key, const fc::ecc::private_key &recent_owner_key) { + auto recover_account = [&]( + const string& account_to_recover, + const private_key& new_owner_key, + const private_key& recent_owner_key + ) { recover_account_operation op; op.account_to_recover = account_to_recover; op.new_owner_authority = authority(1, public_key_type(new_owner_key.get_public_key()), 1); op.recent_owner_authority = authority(1, public_key_type(recent_owner_key.get_public_key()), 1); - signed_transaction tx; tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + - STEEMIT_MAX_TIME_UNTIL_EXPIRATION); + tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); tx.sign(recent_owner_key, db->get_chain_id()); // only Alice -> throw - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_other_auth, 0)); tx.signatures.clear(); tx.sign(new_owner_key, db->get_chain_id()); // only Sam -> throw - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(db->push_transaction(tx, 0), CHECK_ERROR(tx_missing_other_auth, 0)); tx.sign(recent_owner_key, db->get_chain_id()); // Alice+Sam -> OK db->push_transaction(tx, 0); }; - auto request_account_recovery = [&](const std::string &recovery_account, const fc::ecc::private_key &recovery_account_key, const std::string &account_to_recover, const public_key_type &new_owner_key) { + auto request_account_recovery = [&]( + const string& recovery_account, + const private_key& recovery_account_key, + const string& account_to_recover, + const public_key_type& new_owner_key + ) { request_account_recovery_operation op; op.recovery_account = recovery_account; op.account_to_recover = account_to_recover; op.new_owner_authority = authority(1, new_owner_key, 1); - signed_transaction tx; - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + - STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(recovery_account_key, db->get_chain_id()); - db->push_transaction(tx, 0); + push_tx_with_ops(tx, recovery_account_key, op); }; - auto change_owner = [&](const std::string &account, const fc::ecc::private_key &old_private_key, const public_key_type &new_public_key) { + auto change_owner = [&]( + const string& account, + const private_key& old_private_key, + const public_key_type& new_public_key + ) { account_update_operation op; op.account = account; op.owner = authority(1, new_public_key, 1); - signed_transaction tx; - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + - STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(old_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, old_private_key, op)); }; - // if either/both users do not exist, we shouldn't allow it - STEEMIT_REQUIRE_THROW(change_recovery_account("alice", "nobody"), fc::exception); - STEEMIT_REQUIRE_THROW(change_recovery_account("haxer", "sam"), fc::exception); - STEEMIT_REQUIRE_THROW(change_recovery_account("haxer", "nobody"), fc::exception); - change_recovery_account("alice", "sam"); + BOOST_TEST_MESSAGE("--- if either/both users do not exist, we shouldn't allow it"); + GOLOS_CHECK_ERROR_PROPS(change_recovery_account("alice", "nobody"), + CHECK_ERROR(tx_invalid_operation, 0, CHECK_ERROR(missing_object, "account", "nobody"))); + GOLOS_CHECK_ERROR_PROPS(change_recovery_account("haxer", "sam"), + CHECK_ERROR(missing_object, "authority", "haxer")); + GOLOS_CHECK_ERROR_PROPS(change_recovery_account("haxer", "nobody"), + CHECK_ERROR(missing_object, "authority", "haxer")); + BOOST_CHECK_NO_THROW(change_recovery_account("alice", "sam")); fc::ecc::private_key alice_priv1 = fc::ecc::private_key::regenerate(fc::sha256::hash("alice_k1")); fc::ecc::private_key alice_priv2 = fc::ecc::private_key::regenerate(fc::sha256::hash("alice_k2")); public_key_type alice_pub1 = public_key_type(alice_priv1.get_public_key()); generate_blocks( - db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - - fc::seconds(STEEMIT_BLOCK_INTERVAL), true); - // cannot request account recovery until recovery account is approved - STEEMIT_REQUIRE_THROW(request_account_recovery("sam", sam_private_key, "alice", alice_pub1), fc::exception); + db->head_block_time() + STEEMIT_OWNER_AUTH_RECOVERY_PERIOD - fc::seconds(STEEMIT_BLOCK_INTERVAL), + true); + + BOOST_TEST_MESSAGE("--- cannot request account recovery until recovery account is approved"); + GOLOS_CHECK_ERROR_PROPS(request_account_recovery("sam", sam_private_key, "alice", alice_pub1), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_recover_if_not_partner))); generate_blocks(1); - // cannot finish account recovery until requested - STEEMIT_REQUIRE_THROW(recover_account("alice", alice_priv1, alice_private_key), fc::exception); + + BOOST_TEST_MESSAGE("--- cannot finish account recovery until requested"); + GOLOS_CHECK_ERROR_PROPS(recover_account("alice", alice_priv1, alice_private_key), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::no_active_recovery_request))); // do the request - request_account_recovery("sam", sam_private_key, "alice", alice_pub1); - // can't recover with the current owner key - STEEMIT_REQUIRE_THROW(recover_account("alice", alice_priv1, alice_private_key), fc::exception); - // unless we change it! - change_owner("alice", alice_private_key, public_key_type(alice_priv2.get_public_key())); - recover_account("alice", alice_priv1, alice_private_key); + BOOST_CHECK_NO_THROW(request_account_recovery("sam", sam_private_key, "alice", alice_pub1)); + + BOOST_TEST_MESSAGE("--- can't recover with the current owner key"); + GOLOS_CHECK_ERROR_PROPS(recover_account("alice", alice_priv1, alice_private_key), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::no_recent_authority_in_history))); + + BOOST_TEST_MESSAGE("--- success after we change it!"); + BOOST_CHECK_NO_THROW(change_owner("alice", alice_private_key, public_key_type(alice_priv2.get_public_key()))); + BOOST_CHECK_NO_THROW(recover_account("alice", alice_priv1, alice_private_key)); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // recovery //#define CALCULATE_NONCES From d74ee4cb676e83c20ddff08cf59cdc29186eeb65 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 25 Jul 2018 12:01:38 +0300 Subject: [PATCH 139/250] Refactor errors: escrow_transfer & escrow_approve operations #790 --- libraries/chain/steem_evaluator.cpp | 87 ++-- .../include/golos/protocol/exceptions.hpp | 36 ++ libraries/protocol/steem_operations.cpp | 53 +- tests/tests/operation_tests.cpp | 482 +++++++----------- 4 files changed, 274 insertions(+), 384 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 85402d2b4a..8ee3cf2d7e 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -322,7 +322,6 @@ namespace golos { namespace chain { } void account_update_evaluator::do_apply(const account_update_operation &o) { - database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) GOLOS_CHECK_OP_PARAM(o, account, GOLOS_CHECK_VALUE(o.account != STEEMIT_TEMP_ACCOUNT, @@ -339,7 +338,7 @@ namespace golos { namespace chain { if (o.owner) { #ifndef STEEMIT_BUILD_TESTNET if (_db.has_hardfork(STEEMIT_HARDFORK_0_11)) - GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), + GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), account_auth.last_owner_update + STEEMIT_OWNER_UPDATE_LIMIT, bandwidth_exception::change_owner_authority_bandwidth, "Owner authority can only be updated once an hour."); @@ -410,7 +409,6 @@ namespace golos { namespace chain { * Because net_rshares is 0 there is no need to update any pending payout calculations or parent posts. */ void delete_comment_evaluator::do_apply(const delete_comment_operation &o) { - database &_db = db(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) { const auto &auth = _db.get_account(o.author); GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), @@ -735,18 +733,18 @@ namespace golos { namespace chain { } FC_CAPTURE_AND_RETHROW((o)) } - void escrow_transfer_evaluator::do_apply(const escrow_transfer_operation &o) { + void escrow_transfer_evaluator::do_apply(const escrow_transfer_operation& o) { try { - database &_db = db(); - - const auto &from_account = _db.get_account(o.from); + const auto& from_account = _db.get_account(o.from); _db.get_account(o.to); _db.get_account(o.agent); - FC_ASSERT(o.ratification_deadline > - _db.head_block_time(), "The escorw ratification deadline must be after head block time."); - FC_ASSERT(o.escrow_expiration > - _db.head_block_time(), "The escrow expiration must be after head block time."); + GOLOS_CHECK_LOGIC(o.ratification_deadline > _db.head_block_time(), + logic_exception::escrow_time_in_past, + "The escrow ratification deadline must be after head block time."); + GOLOS_CHECK_LOGIC(o.escrow_expiration > _db.head_block_time(), + logic_exception::escrow_time_in_past, + "The escrow expiration must be after head block time."); asset steem_spent = o.steem_amount; asset sbd_spent = o.sbd_amount; @@ -755,16 +753,12 @@ namespace golos { namespace chain { } else { sbd_spent += o.fee; } - - FC_ASSERT(from_account.balance >= - steem_spent, "Account cannot cover STEEM costs of escrow. Required: ${r} Available: ${a}", ("r", steem_spent)("a", from_account.balance)); - FC_ASSERT(from_account.sbd_balance >= - sbd_spent, "Account cannot cover SBD costs of escrow. Required: ${r} Available: ${a}", ("r", sbd_spent)("a", from_account.sbd_balance)); - + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, steem_spent); + GOLOS_CHECK_BALANCE(from_account, MAIN_BALANCE, sbd_spent); _db.adjust_balance(from_account, -steem_spent); _db.adjust_balance(from_account, -sbd_spent); - _db.create([&](escrow_object &esc) { + _db.create([&](escrow_object& esc) { esc.escrow_id = o.escrow_id; esc.from = o.from; esc.to = o.to; @@ -779,34 +773,36 @@ namespace golos { namespace chain { FC_CAPTURE_AND_RETHROW((o)) } - void escrow_approve_evaluator::do_apply(const escrow_approve_operation &o) { + void escrow_approve_evaluator::do_apply(const escrow_approve_operation& o) { try { - database &_db = db(); - const auto &escrow = _db.get_escrow(o.from, o.escrow_id); - - FC_ASSERT(escrow.to == - o.to, "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o", o.to)("e", escrow.to)); - FC_ASSERT(escrow.agent == - o.agent, "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o", o.agent)("e", escrow.agent)); - FC_ASSERT(escrow.ratification_deadline >= - _db.head_block_time(), "The escrow ratification deadline has passed. Escrow can no longer be ratified."); + const auto& escrow = _db.get_escrow(o.from, o.escrow_id); + GOLOS_CHECK_LOGIC(escrow.to == o.to, + logic_exception::escrow_bad_to, + "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o",o.to)("e",escrow.to)); + GOLOS_CHECK_LOGIC(escrow.agent == o.agent, + logic_exception::escrow_bad_agent, + "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o",o.agent)("e",escrow.agent)); + GOLOS_CHECK_LOGIC(escrow.ratification_deadline >= _db.head_block_time(), + logic_exception::ratification_deadline_passed, + "The escrow ratification deadline has passed. Escrow can no longer be ratified."); bool reject_escrow = !o.approve; - if (o.who == o.to) { - FC_ASSERT(!escrow.to_approved, "Account 'to' (${t}) has already approved the escrow.", ("t", o.to)); - + GOLOS_CHECK_LOGIC(!escrow.to_approved, + logic_exception::account_already_approved_escrow, + "Account 'to' (${t}) has already approved the escrow.", ("t",o.to)); if (!reject_escrow) { - _db.modify(escrow, [&](escrow_object &esc) { + _db.modify(escrow, [&](escrow_object& esc) { esc.to_approved = true; }); } } if (o.who == o.agent) { - FC_ASSERT(!escrow.agent_approved, "Account 'agent' (${a}) has already approved the escrow.", ("a", o.agent)); - + GOLOS_CHECK_LOGIC(!escrow.agent_approved, + logic_exception::account_already_approved_escrow, + "Account 'agent' (${a}) has already approved the escrow.", ("a",o.agent)); if (!reject_escrow) { - _db.modify(escrow, [&](escrow_object &esc) { + _db.modify(escrow, [&](escrow_object& esc) { esc.agent_approved = true; }); } @@ -817,13 +813,11 @@ namespace golos { namespace chain { _db.adjust_balance(from_account, escrow.steem_balance); _db.adjust_balance(from_account, escrow.sbd_balance); _db.adjust_balance(from_account, escrow.pending_fee); - _db.remove(escrow); } else if (escrow.to_approved && escrow.agent_approved) { const auto &agent_account = _db.get_account(o.agent); _db.adjust_balance(agent_account, escrow.pending_fee); - - _db.modify(escrow, [&](escrow_object &esc) { + _db.modify(escrow, [&](escrow_object& esc) { esc.pending_fee.amount = 0; }); } @@ -910,8 +904,8 @@ namespace golos { namespace chain { FC_CAPTURE_AND_RETHROW((o)) } + void transfer_evaluator::do_apply(const transfer_operation &o) { - database &_db = db(); const auto &from_account = _db.get_account(o.from); const auto &to_account = _db.get_account(o.to); @@ -930,8 +924,6 @@ namespace golos { namespace chain { } void transfer_to_vesting_evaluator::do_apply(const transfer_to_vesting_operation &o) { - database &_db = db(); - const auto &from_account = _db.get_account(o.from); const auto &to_account = o.to.size() ? _db.get_account(o.to) : from_account; @@ -944,8 +936,6 @@ namespace golos { namespace chain { } void withdraw_vesting_evaluator::do_apply(const withdraw_vesting_operation &o) { - database &_db = db(); - const auto &account = _db.get_account(o.account); GOLOS_CHECK_BALANCE(account, VESTING, asset(0, VESTS_SYMBOL)); @@ -1010,7 +1000,6 @@ namespace golos { namespace chain { void set_withdraw_vesting_route_evaluator::do_apply(const set_withdraw_vesting_route_operation &o) { try { - database &_db = db(); const auto &from_account = _db.get_account(o.from_account); const auto &to_account = _db.get_account(o.to_account); const auto &wd_idx = _db.get_index().indices().get(); @@ -1067,7 +1056,6 @@ namespace golos { namespace chain { } void account_witness_proxy_evaluator::do_apply(const account_witness_proxy_operation &o) { - database &_db = db(); const auto &account = _db.get_account(o.account); GOLOS_CHECK_LOGIC(account.proxy != o.proxy, logic_exception::proxy_must_change, @@ -1125,7 +1113,6 @@ namespace golos { namespace chain { void account_witness_vote_evaluator::do_apply(const account_witness_vote_operation &o) { - database &_db = db(); const auto &voter = _db.get_account(o.account); GOLOS_CHECK_LOGIC(voter.proxy.size() == 0, logic_exception::cannot_vote_when_route_are_set, @@ -1203,8 +1190,6 @@ namespace golos { namespace chain { void vote_evaluator::do_apply(const vote_operation &o) { try { - database &_db = db(); - const auto &comment = _db.get_comment(o.author, o.permlink); const auto &voter = _db.get_account(o.voter); @@ -1889,7 +1874,6 @@ namespace golos { namespace chain { } void feed_publish_evaluator::do_apply(const feed_publish_operation &o) { - database &_db = db(); const auto &witness = _db.get_witness(o.publisher); _db.modify(witness, [&](witness_object &w) { w.sbd_exchange_rate = o.exchange_rate; @@ -1898,14 +1882,13 @@ namespace golos { namespace chain { } void convert_evaluator::do_apply(const convert_operation &o) { - database &_db = db(); const auto &owner = _db.get_account(o.owner); GOLOS_CHECK_BALANCE(owner, MAIN_BALANCE, o.amount); _db.adjust_balance(owner, -o.amount); const auto &fhistory = _db.get_feed_history(); - GOLOS_CHECK_LOGIC(!fhistory.current_median_history.is_null(), + GOLOS_CHECK_LOGIC(!fhistory.current_median_history.is_null(), logic_exception::no_price_feed_yet, "Cannot convert SBD because there is no price feed."); @@ -1960,7 +1943,7 @@ namespace golos { namespace chain { void limit_order_create2_evaluator::do_apply(const limit_order_create2_operation &o) { database &_db = db(); GOLOS_CHECK_OP_PARAM(o, expiration, { - GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), + GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), "Limit order has to expire after head block time."); }); diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index b4f2eb7fe1..3480476b5e 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -216,6 +216,24 @@ namespace golos { // prove_authority_evaluator account_is_not_challeneged, + // escrow + escrow_no_amount_set, + escrow_wrong_time_limits, + escrow_time_in_past, + escrow_bad_to, + escrow_bad_agent, + escrow_bad_receiver, + ratification_deadline_passed, + account_already_approved_escrow, + cannot_dispute_expired_escrow, + escrow_must_be_approved_first, + escrow_already_disputed, + release_amount_exceeds_escrow_balance, + only_agent_can_release_disputed, + only_from_to_can_release_non_disputed, + from_can_release_only_to_to, + to_can_release_only_to_from, + //set_reset_account_operation cannot_set_same_reset_account, @@ -407,6 +425,24 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, //prove_authority_evaluator (account_is_not_challeneged) + //escrow + (escrow_no_amount_set) + (escrow_wrong_time_limits) + (escrow_time_in_past) + (escrow_bad_to) + (escrow_bad_agent) + (escrow_bad_receiver) + (ratification_deadline_passed) + (account_already_approved_escrow) + (cannot_dispute_expired_escrow) + (escrow_must_be_approved_first) + (escrow_already_disputed) + (release_amount_exceeds_escrow_balance) + (only_agent_can_release_disputed) + (only_from_to_can_release_non_disputed) + (from_can_release_only_to_to) + (to_can_release_only_to_from) + //set_reset_account_operation (cannot_set_same_reset_account) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index bf877a7a14..e4ef23c97b 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -454,9 +454,9 @@ namespace golos { namespace protocol { "Limit order must be for the GOLOS:GBG market"); GOLOS_CHECK_PARAM(amount_to_sell, { - GOLOS_CHECK_VALUE(amount_to_sell.symbol == exchange_rate.base.symbol, + GOLOS_CHECK_VALUE(amount_to_sell.symbol == exchange_rate.base.symbol, "Sell asset must be the base of the price"); - GOLOS_CHECK_VALUE((amount_to_sell * exchange_rate).amount > 0, + GOLOS_CHECK_VALUE((amount_to_sell * exchange_rate).amount > 0, "Amount to sell cannot round to 0 when traded"); }); } @@ -484,38 +484,33 @@ namespace golos { namespace protocol { } void escrow_transfer_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - validate_account_name(agent); - FC_ASSERT(fee.amount >= 0, "fee cannot be negative"); - FC_ASSERT(sbd_amount.amount >= 0, "gbg amount cannot be negative"); - FC_ASSERT(steem_amount.amount >= - 0, "steem amount cannot be negative"); - FC_ASSERT(sbd_amount.amount > 0 || steem_amount.amount > - 0, "escrow must transfer a non-zero amount"); - FC_ASSERT(from != agent && - to != agent, "agent must be a third party"); - FC_ASSERT((fee.symbol == STEEM_SYMBOL) || - (fee.symbol == SBD_SYMBOL), "fee must be GOLOS or GBG"); - FC_ASSERT(sbd_amount.symbol == - SBD_SYMBOL, "sbd amount must contain GBG"); - FC_ASSERT(steem_amount.symbol == - STEEM_SYMBOL, "golos amount must contain GOLOS"); - FC_ASSERT(ratification_deadline < - escrow_expiration, "ratification deadline must be before escrow expiration"); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM_ACCOUNT(agent); + GOLOS_CHECK_PARAM(fee, GOLOS_CHECK_ASSET_GE0(fee, GOLOS_OR_GBG)); + GOLOS_CHECK_PARAM(sbd_amount, GOLOS_CHECK_ASSET_GE0(sbd_amount, GBG)); + GOLOS_CHECK_PARAM(steem_amount, GOLOS_CHECK_ASSET_GE0(steem_amount, GOLOS)); + GOLOS_CHECK_LOGIC(sbd_amount.amount > 0 || steem_amount.amount > 0, + logic_exception::escrow_no_amount_set, + "escrow must release a non-zero amount"); + GOLOS_CHECK_PARAM(agent, GOLOS_CHECK_VALUE(from != agent && to != agent, "agent must be a third party")); + GOLOS_CHECK_LOGIC(ratification_deadline < escrow_expiration, + logic_exception::escrow_wrong_time_limits, + "ratification deadline must be before escrow expiration"); if (json_meta.size() > 0) { - FC_ASSERT(fc::is_utf8(json_meta), "JSON Metadata not formatted in UTF8"); - FC_ASSERT(fc::json::is_valid(json_meta), "JSON Metadata not valid JSON"); + GOLOS_CHECK_PARAM(json_meta, { + GOLOS_CHECK_VALUE_UTF8(json_meta); + GOLOS_CHECK_VALUE_JSON(json_meta); + }); } } void escrow_approve_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - validate_account_name(agent); - validate_account_name(who); - FC_ASSERT(who == to || - who == agent, "to or agent must approve escrow"); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM_ACCOUNT(agent); + GOLOS_CHECK_PARAM_ACCOUNT(who); + GOLOS_CHECK_PARAM(who, GOLOS_CHECK_VALUE(who == to || who == agent, "to or agent must approve escrow")); } void escrow_dispute_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 062a4488eb..3014486877 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -49,6 +49,11 @@ fc::variant_object make_convert_request_id(const std::string& account, uint32_t return fc::variant_object(res); } +fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id) { + auto res = fc::mutable_variant_object()("account",name)("escrow",escrow_id); + return fc::variant_object(res); +} + BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) @@ -4476,6 +4481,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_SUITE_END() // prove_authority +//------------------------------------------------------------- + BOOST_AUTO_TEST_SUITE(escrow) + + BOOST_AUTO_TEST_SUITE(escrow_transfer) + BOOST_AUTO_TEST_CASE(escrow_transfer_validate) { try { BOOST_TEST_MESSAGE("Testing: escrow_transfer_validate"); @@ -4491,54 +4501,40 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.json_meta = ""; op.ratification_deadline = db->head_block_time() + 100; op.escrow_expiration = db->head_block_time() + 200; - - BOOST_TEST_MESSAGE("--- failure when sbd symbol != SBD"); - op.sbd_amount.symbol = STEEM_SYMBOL; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - BOOST_TEST_MESSAGE("--- failure when steem symbol != STEEM"); - op.sbd_amount.symbol = SBD_SYMBOL; - op.steem_amount.symbol = SBD_SYMBOL; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - BOOST_TEST_MESSAGE("--- failure when fee symbol != SBD and fee symbol != STEEM"); - op.steem_amount.symbol = STEEM_SYMBOL; - op.fee.symbol = VESTS_SYMBOL; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- success on valid parameters"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, sbd_amount, ASSET_GBG(0)); + CHECK_PARAM_VALID(op, steem_amount, ASSET_GOLOS(0)); + CHECK_PARAM_VALID(op, fee, ASSET_GOLOS(0)); + CHECK_PARAM_VALID(op, fee, ASSET_GBG(0)); + CHECK_PARAM_VALID(op, fee, ASSET_GBG(1)); + + BOOST_TEST_MESSAGE("--- failure when asset symbols invalid"); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GOLOS(1)); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GESTS(1)); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET("1.00 BAD")); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GBG(1)); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GESTS(1)); + CHECK_PARAM_INVALID(op, steem_amount, ASSET("1.00 BAD")); + CHECK_PARAM_INVALID(op, fee, ASSET_GESTS(1)); + CHECK_PARAM_INVALID(op, fee, ASSET("1.00 BAD")); BOOST_TEST_MESSAGE("--- failure when sbd == 0 and steem == 0"); - op.fee.symbol = STEEM_SYMBOL; op.sbd_amount.amount = 0; - op.steem_amount.amount = 0; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - BOOST_TEST_MESSAGE("--- failure when sbd < 0"); - op.sbd_amount.amount = -100; - op.steem_amount.amount = 1000; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + CHECK_PARAM_INVALID_LOGIC(op, steem_amount, ASSET_GOLOS(0), escrow_no_amount_set); - BOOST_TEST_MESSAGE("--- failure when steem < 0"); - op.sbd_amount.amount = 1000; - op.steem_amount.amount = -100; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - BOOST_TEST_MESSAGE("--- failure when fee < 0"); - op.steem_amount.amount = 1000; - op.fee.amount = -100; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- failure when asset amount < 0"); + op.sbd_amount.amount = 0; + CHECK_PARAM_INVALID(op, fee, ASSET_GBG(-1)); + CHECK_PARAM_INVALID(op, fee, ASSET_GOLOS(-1)); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GBG(-1)); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GOLOS(-1)); BOOST_TEST_MESSAGE("--- failure when ratification deadline == escrow expiration"); - op.fee.amount = 100; - op.ratification_deadline = op.escrow_expiration; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + CHECK_PARAM_INVALID_LOGIC(op, ratification_deadline, op.escrow_expiration, escrow_wrong_time_limits); BOOST_TEST_MESSAGE("--- failure when ratification deadline > escrow expiration"); - op.ratification_deadline = op.escrow_expiration + 100; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - BOOST_TEST_MESSAGE("--- success"); - op.ratification_deadline = op.escrow_expiration - 100; - op.validate(); + CHECK_PARAM_INVALID_LOGIC(op, ratification_deadline, op.escrow_expiration + 1, escrow_wrong_time_limits); } FC_LOG_AND_RETHROW() } @@ -4546,7 +4542,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(escrow_transfer_authorities) { try { BOOST_TEST_MESSAGE("Testing: escrow_transfer_authorities"); - escrow_transfer_operation op; op.from = "alice"; op.to = "bob"; @@ -4558,19 +4553,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.json_meta = ""; op.ratification_deadline = db->head_block_time() + 100; op.escrow_expiration = db->head_block_time() + 200; - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"alice"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -4578,9 +4561,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(escrow_transfer_apply) { try { BOOST_TEST_MESSAGE("Testing: escrow_transfer_apply"); - ACTORS((alice)(bob)(sam)) - fund("alice", 10000); escrow_transfer_operation op; @@ -4597,106 +4578,94 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_TEST_MESSAGE("--- failure when from cannot cover sbd amount"); signed_transaction tx; - tx.operations.push_back(op); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "1.000 GBG"))); BOOST_TEST_MESSAGE("--- falure when from cannot cover amount + fee"); op.sbd_amount.amount = 0; op.steem_amount.amount = 10000; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(insufficient_funds, "alice", "fund", "10.100 GOLOS"))); BOOST_TEST_MESSAGE("--- failure when ratification deadline is in the past"); op.steem_amount.amount = 1000; op.ratification_deadline = db->head_block_time() - 200; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_time_in_past))); BOOST_TEST_MESSAGE("--- failure when expiration is in the past"); op.escrow_expiration = db->head_block_time() - 100; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_time_in_past))); BOOST_TEST_MESSAGE("--- success"); op.ratification_deadline = db->head_block_time() + 100; op.escrow_expiration = db->head_block_time() + 200; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - auto alice_steem_balance = alice.balance - op.steem_amount - op.fee; auto alice_sbd_balance = alice.sbd_balance - op.sbd_amount; auto bob_steem_balance = bob.balance; auto bob_sbd_balance = bob.sbd_balance; auto sam_steem_balance = sam.balance; auto sam_sbd_balance = sam.sbd_balance; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); - db->push_transaction(tx, 0); - - const auto &escrow = db->get_escrow(op.from, op.escrow_id); - - BOOST_REQUIRE(escrow.escrow_id == op.escrow_id); - BOOST_REQUIRE(escrow.from == op.from); - BOOST_REQUIRE(escrow.to == op.to); - BOOST_REQUIRE(escrow.agent == op.agent); - BOOST_REQUIRE( - escrow.ratification_deadline == op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == op.fee); - BOOST_REQUIRE(!escrow.to_approved); - BOOST_REQUIRE(!escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); - BOOST_REQUIRE(alice.balance == alice_steem_balance); - BOOST_REQUIRE(alice.sbd_balance == alice_sbd_balance); - BOOST_REQUIRE(bob.balance == bob_steem_balance); - BOOST_REQUIRE(bob.sbd_balance == bob_sbd_balance); - BOOST_REQUIRE(sam.balance == sam_steem_balance); - BOOST_REQUIRE(sam.sbd_balance == sam_sbd_balance); + const auto& escrow = db->get_escrow(op.from, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.escrow_id, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.from, op.from); + BOOST_CHECK_EQUAL(escrow.to, op.to); + BOOST_CHECK_EQUAL(escrow.agent, op.agent); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, op.fee); + BOOST_CHECK(!escrow.to_approved); + BOOST_CHECK(!escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); + BOOST_CHECK_EQUAL(alice.balance, alice_steem_balance); + BOOST_CHECK_EQUAL(alice.sbd_balance, alice_sbd_balance); + BOOST_CHECK_EQUAL(bob.balance, bob_steem_balance); + BOOST_CHECK_EQUAL(bob.sbd_balance, bob_sbd_balance); + BOOST_CHECK_EQUAL(sam.balance, sam_steem_balance); + BOOST_CHECK_EQUAL(sam.sbd_balance, sam_sbd_balance); validate_database(); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // escrow_transfer + + + BOOST_AUTO_TEST_SUITE(escrow_approve) BOOST_AUTO_TEST_CASE(escrow_approve_validate) { try { BOOST_TEST_MESSAGE("Testing: escrow_approve_validate"); - escrow_approve_operation op; - op.from = "alice"; op.to = "bob"; op.agent = "sam"; op.who = "bob"; op.escrow_id = 0; op.approve = true; + BOOST_TEST_MESSAGE("--- success when 'who' is 'to'"); + CHECK_PARAM_VALID(op, who, op.to); - BOOST_TEST_MESSAGE("--- failure when who is not to or agent"); - op.who = "dave"; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- success when 'who' is 'agent'"); + CHECK_PARAM_VALID(op, who, op.agent); - BOOST_TEST_MESSAGE("--- success when who is to"); - op.who = op.to; - op.validate(); + BOOST_TEST_MESSAGE("--- failure when 'who' is not 'to' or 'agent'"); + CHECK_PARAM_INVALID(op, who, "dave"); - BOOST_TEST_MESSAGE("--- success when who is agent"); - op.who = op.agent; - op.validate(); + BOOST_TEST_MESSAGE("--- failure when invalid account"); + CHECK_PARAM_INVALID(op, from, ""); + CHECK_PARAM_INVALID(op, to, ""); + CHECK_PARAM_INVALID(op, agent, ""); + CHECK_PARAM_INVALID(op, who, ""); } FC_LOG_AND_RETHROW() } @@ -4704,36 +4673,16 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(escrow_approve_authorities) { try { BOOST_TEST_MESSAGE("Testing: escrow_approve_authorities"); - escrow_approve_operation op; - op.from = "alice"; op.to = "bob"; op.agent = "sam"; op.who = "bob"; op.escrow_id = 0; op.approve = true; - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("bob"); - BOOST_REQUIRE(auths == expected); - - expected.clear(); - auths.clear(); - + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); op.who = "sam"; - op.get_required_active_authorities(auths); - expected.insert("sam"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -4755,13 +4704,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) et_op.escrow_expiration = db->head_block_time() + 200; signed_transaction tx; - tx.operations.push_back(et_op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - tx.operations.clear(); - tx.signatures.clear(); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); BOOST_TEST_MESSAGE("---failure when to does not match escrow"); escrow_approve_operation op; @@ -4770,234 +4713,165 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.agent = "sam"; op.who = "dave"; op.approve = true; - - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, dave_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_bad_to))); BOOST_TEST_MESSAGE("--- failure when agent does not match escrow"); op.to = "bob"; op.agent = "dave"; - - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, dave_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_bad_agent))); BOOST_TEST_MESSAGE("--- success approving to"); op.agent = "sam"; op.who = "bob"; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); - tx.operations.clear(); - tx.signatures.clear(); - - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - auto &escrow = db->get_escrow(op.from, op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(escrow.steem_balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.100 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(!escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); - + { + auto& escrow = db->get_escrow(op.from, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(escrow.steem_balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.100 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(!escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); + } BOOST_TEST_MESSAGE("--- failure on repeat approval"); - tx.signatures.clear(); - - tx.set_expiration(db->head_block_time() + STEEMIT_BLOCK_INTERVAL); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(escrow.steem_balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.100 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(!escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); - + generate_block(); // avoid tx_duplicate_transaction + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::account_already_approved_escrow))); BOOST_TEST_MESSAGE("--- failure trying to repeal after approval"); - tx.signatures.clear(); - tx.operations.clear(); - op.approve = false; + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::account_already_approved_escrow))); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == - et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(escrow.steem_balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.100 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(!escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); - + { + auto& escrow = db->get_escrow(op.from, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(escrow.steem_balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.100 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(!escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); + } BOOST_TEST_MESSAGE("--- success refunding from because of repeal"); - tx.signatures.clear(); - tx.operations.clear(); - op.who = op.agent; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - STEEMIT_REQUIRE_THROW(db->get_escrow(op.from, op.escrow_id), fc::exception); - BOOST_REQUIRE(alice.balance == ASSET("10.000 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(op.from, op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(op.from, op.escrow_id))); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- test automatic refund when escrow is not ratified before deadline"); - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(et_op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); - generate_blocks( - et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); + generate_blocks(et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); - STEEMIT_REQUIRE_THROW(db->get_escrow(op.from, op.escrow_id), fc::exception); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("10.000 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(op.from, op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(op.from, op.escrow_id))); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- test ratification expiration when escrow is only approved by to"); - tx.operations.clear(); - tx.signatures.clear(); et_op.ratification_deadline = db->head_block_time() + 100; et_op.escrow_expiration = db->head_block_time() + 200; - tx.operations.push_back(et_op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); - tx.operations.clear(); - tx.signatures.clear(); op.who = op.to; op.approve = true; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); - generate_blocks( - et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); + generate_blocks(et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); - STEEMIT_REQUIRE_THROW(db->get_escrow(op.from, op.escrow_id), fc::exception); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("10.000 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(op.from, op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(op.from, op.escrow_id))); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- test ratification expiration when escrow is only approved by agent"); - tx.operations.clear(); - tx.signatures.clear(); et_op.ratification_deadline = db->head_block_time() + 100; et_op.escrow_expiration = db->head_block_time() + 200; - tx.operations.push_back(et_op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); - tx.operations.clear(); - tx.signatures.clear(); op.who = op.agent; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); generate_blocks(et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); - STEEMIT_REQUIRE_THROW(db->get_escrow(op.from, op.escrow_id), fc::exception); - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("10.000 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(op.from, op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(op.from, op.escrow_id))); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("10.000 GOLOS")); validate_database(); - BOOST_TEST_MESSAGE("--- success approving escrow"); - tx.operations.clear(); - tx.signatures.clear(); et_op.ratification_deadline = db->head_block_time() + 100; et_op.escrow_expiration = db->head_block_time() + 200; - tx.operations.push_back(et_op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); - tx.operations.clear(); - tx.signatures.clear(); op.who = op.to; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); - tx.operations.clear(); - tx.signatures.clear(); op.who = op.agent; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); { - const auto &escrow = db->get_escrow(op.from, op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(escrow.steem_balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); + const auto& escrow = db->get_escrow(op.from, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(escrow.steem_balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); } - BOOST_REQUIRE(db->get_account("sam").balance == et_op.fee); + BOOST_CHECK_EQUAL(db->get_account("sam").balance, et_op.fee); validate_database(); - BOOST_TEST_MESSAGE("--- ratification expiration does not remove an approved escrow"); generate_blocks(et_op.ratification_deadline + STEEMIT_BLOCK_INTERVAL, true); { - const auto &escrow = db->get_escrow(op.from, op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == ASSET("0.000 GBG")); - BOOST_REQUIRE(escrow.steem_balance == ASSET("1.000 GOLOS")); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); + const auto& escrow = db->get_escrow(op.from, op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, ASSET("0.000 GBG")); + BOOST_CHECK_EQUAL(escrow.steem_balance, ASSET("1.000 GOLOS")); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); } - BOOST_REQUIRE(db->get_account("sam").balance == et_op.fee); + BOOST_CHECK_EQUAL(db->get_account("sam").balance, et_op.fee); validate_database(); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // escrow_approve + + BOOST_AUTO_TEST_CASE(escrow_dispute_validate) { try { @@ -5820,7 +5694,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // escrow +//------------------------------------------------------------- BOOST_AUTO_TEST_SUITE(transfer_to_savings) From f3c7a8f45188c9c2a5f5b1583fee4d67f927acd8 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 25 Jul 2018 12:09:22 +0300 Subject: [PATCH 140/250] Refactor errors: escrow_dispute_operation #790 --- libraries/chain/steem_evaluator.cpp | 55 +++--- libraries/protocol/steem_operations.cpp | 10 +- tests/tests/operation_tests.cpp | 253 ++++++++++-------------- 3 files changed, 135 insertions(+), 183 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 8ee3cf2d7e..f74e967573 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -33,8 +33,8 @@ std::string wstring_to_utf8(const std::wstring &str) { ) #define GOLOS_CHECK_BANDWIDTH(NOW, NEXT, TYPE, MSG, ...) \ - GOLOS_ASSERT((NOW) > (NEXT), golos::bandwidth_exception, MSG, \ - ("bandwidth",TYPE)("now",NOW)("next",NEXT) __VA_ARGS__) + GOLOS_ASSERT((NOW) > (NEXT), golos::bandwidth_exception, MSG, \ + ("bandwidth",TYPE)("now",NOW)("next",NEXT) __VA_ARGS__) namespace golos { namespace chain { using fc::uint128_t; @@ -533,11 +533,9 @@ namespace golos { namespace chain { void comment_evaluator::do_apply(const comment_operation &o) { try { - database &_db = db(); - if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__55)) - GOLOS_CHECK_LOGIC(o.title.size() + o.body.size() + o.json_metadata.size(), + GOLOS_CHECK_LOGIC(o.title.size() + o.body.size() + o.json_metadata.size(), logic_exception::cannot_update_comment_because_nothing_changed, "Cannot update comment because nothing appears to be changing."); @@ -547,7 +545,7 @@ namespace golos { namespace chain { const auto &auth = _db.get_account(o.author); /// prove it exists if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) - GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), + GOLOS_CHECK_LOGIC(!(auth.owner_challenged || auth.active_challenged), logic_exception::account_is_currently_challenged, "Operation cannot be processed because account is currently challenged."); @@ -598,16 +596,16 @@ namespace golos { namespace chain { bandwidth_exception::post_bandwidth, "You may only post once every 5 minutes."); else - GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, golos::bandwidth_exception::comment_bandwidth, "You may only comment once every 20 seconds."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_6__113)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) - GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, bandwidth_exception::post_bandwidth, "You may only post once every 5 minutes."); else - GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, + GOLOS_CHECK_BANDWIDTH(now, auth.last_post + STEEMIT_MIN_REPLY_INTERVAL, bandwidth_exception::comment_bandwidth, "You may only comment once every 20 seconds."); } else { @@ -825,23 +823,27 @@ namespace golos { namespace chain { FC_CAPTURE_AND_RETHROW((o)) } - void escrow_dispute_evaluator::do_apply(const escrow_dispute_operation &o) { + void escrow_dispute_evaluator::do_apply(const escrow_dispute_operation& o) { try { - database &_db = db(); _db.get_account(o.from); // Verify from account exists + const auto& e = _db.get_escrow(o.from, o.escrow_id); + GOLOS_CHECK_LOGIC(_db.head_block_time() < e.escrow_expiration, + logic_exception::cannot_dispute_expired_escrow, + "Disputing the escrow must happen before expiration."); + GOLOS_CHECK_LOGIC(e.to_approved && e.agent_approved, + logic_exception::escrow_must_be_approved_first, + "The escrow must be approved by all parties before a dispute can be raised."); + GOLOS_CHECK_LOGIC(!e.disputed, + logic_exception::escrow_already_disputed, + "The escrow is already under dispute."); + GOLOS_CHECK_LOGIC(e.to == o.to, + logic_exception::escrow_bad_to, + "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o",o.to)("e",e.to)); + GOLOS_CHECK_LOGIC(e.agent == o.agent, + logic_exception::escrow_bad_agent, + "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o",o.agent)("e",e.agent)); - const auto &e = _db.get_escrow(o.from, o.escrow_id); - FC_ASSERT(_db.head_block_time() < - e.escrow_expiration, "Disputing the escrow must happen before expiration."); - FC_ASSERT(e.to_approved && - e.agent_approved, "The escrow must be approved by all parties before a dispute can be raised."); - FC_ASSERT(!e.disputed, "The escrow is already under dispute."); - FC_ASSERT(e.to == - o.to, "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o", o.to)("e", e.to)); - FC_ASSERT(e.agent == - o.agent, "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o", o.agent)("e", e.agent)); - - _db.modify(e, [&](escrow_object &esc) { + _db.modify(e, [&](escrow_object& esc) { esc.disputed = true; }); } @@ -1909,9 +1911,7 @@ namespace golos { namespace chain { } - void limit_order_create_evaluator::do_apply(const limit_order_create_operation &o) { - database &_db = db(); - + void limit_order_create_evaluator::do_apply(const limit_order_create_operation& o) { GOLOS_CHECK_OP_PARAM(o, expiration, { GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), "Limit order has to expire after head block time."); @@ -1940,8 +1940,7 @@ namespace golos { namespace chain { "Cancelling order because it was not filled."); } - void limit_order_create2_evaluator::do_apply(const limit_order_create2_operation &o) { - database &_db = db(); + void limit_order_create2_evaluator::do_apply(const limit_order_create2_operation& o) { GOLOS_CHECK_OP_PARAM(o, expiration, { GOLOS_CHECK_VALUE(o.expiration > _db.head_block_time(), "Limit order has to expire after head block time."); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index e4ef23c97b..fcaf62fede 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -514,11 +514,11 @@ namespace golos { namespace protocol { } void escrow_dispute_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - validate_account_name(agent); - validate_account_name(who); - FC_ASSERT(who == from || who == to, "who must be from or to"); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM_ACCOUNT(agent); + GOLOS_CHECK_PARAM_ACCOUNT(who); + GOLOS_CHECK_PARAM(who, GOLOS_CHECK_VALUE(who == from || who == to, "who must be from or to")); } void escrow_release_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 3014486877..256240d2b7 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -4872,6 +4872,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_SUITE_END() // escrow_approve + BOOST_AUTO_TEST_SUITE(escrow_dispute) BOOST_AUTO_TEST_CASE(escrow_dispute_validate) { try { @@ -4879,19 +4880,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) escrow_dispute_operation op; op.from = "alice"; op.to = "bob"; - op.agent = "alice"; + op.agent = "dave"; op.who = "alice"; - BOOST_TEST_MESSAGE("failure when who is not from or to"); - op.who = "sam"; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- success on valid params"); + CHECK_OP_VALID(op); + CHECK_PARAM_VALID(op, who, "bob"); - BOOST_TEST_MESSAGE("success"); - op.who = "alice"; - op.validate(); + BOOST_TEST_MESSAGE("--- failure when who is not from or to"); + CHECK_PARAM_INVALID(op, who, "dave"); + CHECK_PARAM_INVALID(op, who, "sam"); - op.who = "bob"; - op.validate(); + BOOST_TEST_MESSAGE("--- failure when account invalid"); + CHECK_PARAM_INVALID(op, from, ""); + CHECK_PARAM_INVALID(op, to, ""); + CHECK_PARAM_INVALID(op, agent, ""); + CHECK_PARAM_INVALID(op, who, ""); } FC_LOG_AND_RETHROW() } @@ -4903,26 +4907,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.from = "alice"; op.to = "bob"; op.who = "alice"; - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_active_authorities(auths); - expected.insert("alice"); - BOOST_REQUIRE(auths == expected); - - auths.clear(); - expected.clear(); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); op.who = "bob"; - op.get_required_active_authorities(auths); - expected.insert("bob"); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -4930,7 +4917,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(escrow_dispute_apply) { try { BOOST_TEST_MESSAGE("Testing: escrow_dispute_apply"); - ACTORS((alice)(bob)(sam)(dave)) fund("alice", 10000); @@ -4951,13 +4937,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ea_b_op.approve = true; signed_transaction tx; - tx.operations.push_back(et_op); - tx.operations.push_back(ea_b_op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); + sign_tx_with_ops(tx, alice_private_key, et_op, ea_b_op); tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- failure when escrow has not been approved"); escrow_dispute_operation op; @@ -4965,25 +4947,21 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.to = "bob"; op.agent = "sam"; op.who = "bob"; - - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - const auto &escrow = db->get_escrow(et_op.from, et_op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == et_op.fee); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(!escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_must_be_approved_first))); + + const auto& escrow = db->get_escrow(et_op.from, et_op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, et_op.fee); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(!escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); BOOST_TEST_MESSAGE("--- failure when to does not match escrow"); escrow_approve_operation ea_s_op; @@ -4992,81 +4970,66 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ea_s_op.agent = "sam"; ea_s_op.who = "sam"; ea_s_op.approve = true; - - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(ea_s_op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, ea_s_op)); op.to = "dave"; op.who = "alice"; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_bad_to))); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); BOOST_TEST_MESSAGE("--- failure when agent does not match escrow"); op.to = "bob"; op.who = "alice"; op.agent = "dave"; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_bad_agent))); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); BOOST_TEST_MESSAGE("--- failure when escrow is expired"); generate_blocks(2); - tx.operations.clear(); - tx.signatures.clear(); op.agent = "sam"; - tx.operations.push_back(op); - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::cannot_dispute_expired_escrow))); { - const auto &escrow = db->get_escrow(et_op.from, et_op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(!escrow.disputed); + const auto& escrow = db->get_escrow(et_op.from, et_op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(!escrow.disputed); } - BOOST_TEST_MESSAGE("--- success disputing escrow"); et_op.escrow_id = 1; et_op.ratification_deadline = db->head_block_time() + STEEMIT_BLOCK_INTERVAL; @@ -5074,62 +5037,52 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ea_b_op.escrow_id = et_op.escrow_id; ea_s_op.escrow_id = et_op.escrow_id; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back(et_op); - tx.operations.push_back(ea_b_op); - tx.operations.push_back(ea_s_op); - tx.sign(alice_private_key, db->get_chain_id()); + sign_tx_with_ops(tx, alice_private_key, et_op, ea_b_op, ea_s_op); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); - tx.operations.clear(); - tx.signatures.clear(); op.escrow_id = et_op.escrow_id; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); { - const auto &escrow = db->get_escrow(et_op.from, et_op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(escrow.disputed); + const auto& escrow = db->get_escrow(et_op.from, et_op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(escrow.disputed); } - BOOST_TEST_MESSAGE("--- failure when escrow is already under dispute"); - tx.operations.clear(); - tx.signatures.clear(); op.who = "bob"; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_already_disputed))); { - const auto &escrow = db->get_escrow(et_op.from, et_op.escrow_id); - BOOST_REQUIRE(escrow.to == "bob"); - BOOST_REQUIRE(escrow.agent == "sam"); - BOOST_REQUIRE(escrow.ratification_deadline == et_op.ratification_deadline); - BOOST_REQUIRE(escrow.escrow_expiration == et_op.escrow_expiration); - BOOST_REQUIRE(escrow.sbd_balance == et_op.sbd_amount); - BOOST_REQUIRE(escrow.steem_balance == et_op.steem_amount); - BOOST_REQUIRE(escrow.pending_fee == ASSET("0.000 GOLOS")); - BOOST_REQUIRE(escrow.to_approved); - BOOST_REQUIRE(escrow.agent_approved); - BOOST_REQUIRE(escrow.disputed); + const auto& escrow = db->get_escrow(et_op.from, et_op.escrow_id); + BOOST_CHECK_EQUAL(escrow.to, "bob"); + BOOST_CHECK_EQUAL(escrow.agent, "sam"); + BOOST_CHECK_EQUAL(escrow.ratification_deadline, et_op.ratification_deadline); + BOOST_CHECK_EQUAL(escrow.escrow_expiration, et_op.escrow_expiration); + BOOST_CHECK_EQUAL(escrow.sbd_balance, et_op.sbd_amount); + BOOST_CHECK_EQUAL(escrow.steem_balance, et_op.steem_amount); + BOOST_CHECK_EQUAL(escrow.pending_fee, ASSET("0.000 GOLOS")); + BOOST_CHECK(escrow.to_approved); + BOOST_CHECK(escrow.agent_approved); + BOOST_CHECK(escrow.disputed); } } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // escrow_dispute + BOOST_AUTO_TEST_CASE(escrow_release_validate) { try { From 4fb76b37e2d58d0c7da405eefff08b37515f5915 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 25 Jul 2018 12:14:49 +0300 Subject: [PATCH 141/250] Refactor errors: escrow_release_operation #790 --- libraries/chain/steem_evaluator.cpp | 64 ++-- libraries/protocol/steem_operations.cpp | 32 +- tests/tests/operation_tests.cpp | 461 +++++++----------------- 3 files changed, 180 insertions(+), 377 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index f74e967573..676bfaedc4 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -850,42 +850,54 @@ namespace golos { namespace chain { FC_CAPTURE_AND_RETHROW((o)) } - void escrow_release_evaluator::do_apply(const escrow_release_operation &o) { + void escrow_release_evaluator::do_apply(const escrow_release_operation& o) { try { - database &_db = db(); _db.get_account(o.from); // Verify from account exists - const auto &receiver_account = _db.get_account(o.receiver); - - const auto &e = _db.get_escrow(o.from, o.escrow_id); - FC_ASSERT(e.steem_balance >= - o.steem_amount, "Release amount exceeds escrow balance. Amount: ${a}, Balance: ${b}", ("a", o.steem_amount)("b", e.steem_balance)); - FC_ASSERT(e.sbd_balance >= - o.sbd_amount, "Release amount exceeds escrow balance. Amount: ${a}, Balance: ${b}", ("a", o.sbd_amount)("b", e.sbd_balance)); - FC_ASSERT(e.to == - o.to, "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o", o.to)("e", e.to)); - FC_ASSERT(e.agent == - o.agent, "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o", o.agent)("e", e.agent)); - FC_ASSERT(o.receiver == e.from || o.receiver == - e.to, "Funds must be released to 'from' (${f}) or 'to' (${t})", ("f", e.from)("t", e.to)); - FC_ASSERT(e.to_approved && - e.agent_approved, "Funds cannot be released prior to escrow approval."); + const auto& receiver_account = _db.get_account(o.receiver); + + const auto& e = _db.get_escrow(o.from, o.escrow_id); + GOLOS_CHECK_LOGIC(e.steem_balance >= o.steem_amount, + logic_exception::release_amount_exceeds_escrow_balance, + "Release amount exceeds escrow balance. Amount: ${a}, Balance: ${b}", + ("a",o.steem_amount)("b",e.steem_balance)); + GOLOS_CHECK_LOGIC(e.sbd_balance >= o.sbd_amount, + logic_exception::release_amount_exceeds_escrow_balance, + "Release amount exceeds escrow balance. Amount: ${a}, Balance: ${b}", + ("a",o.sbd_amount)("b",e.sbd_balance)); + GOLOS_CHECK_LOGIC(e.to == o.to, + logic_exception::escrow_bad_to, + "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o",o.to)("e",e.to)); + GOLOS_CHECK_LOGIC(e.agent == o.agent, + logic_exception::escrow_bad_agent, + "Operation 'agent' (${a}) does not match escrow 'agent' (${e}).", ("o",o.agent)("e",e.agent)); + GOLOS_CHECK_LOGIC(o.receiver == e.from || o.receiver == e.to, + logic_exception::escrow_bad_receiver, + "Funds must be released to 'from' (${f}) or 'to' (${t})", ("f",e.from)("t",e.to)); + GOLOS_CHECK_LOGIC(e.to_approved && e.agent_approved, + logic_exception::escrow_must_be_approved_first, + "Funds cannot be released prior to escrow approval."); // If there is a dispute regardless of expiration, the agent can release funds to either party if (e.disputed) { - FC_ASSERT(o.who == - e.agent, "Only 'agent' (${a}) can release funds in a disputed escrow.", ("a", e.agent)); + GOLOS_CHECK_LOGIC(o.who == e.agent, + logic_exception::only_agent_can_release_disputed, + "Only 'agent' (${a}) can release funds in a disputed escrow.", ("a",e.agent)); } else { - FC_ASSERT(o.who == e.from || o.who == - e.to, "Only 'from' (${f}) and 'to' (${t}) can release funds from a non-disputed escrow", ("f", e.from)("t", e.to)); + GOLOS_CHECK_LOGIC(o.who == e.from || o.who == e.to, + logic_exception::only_from_to_can_release_non_disputed, + "Only 'from' (${f}) and 'to' (${t}) can release funds from a non-disputed escrow", + ("f",e.from)("t",e.to)); if (e.escrow_expiration > _db.head_block_time()) { // If there is no dispute and escrow has not expired, either party can release funds to the other. if (o.who == e.from) { - FC_ASSERT(o.receiver == - e.to, "Only 'from' (${f}) can release funds to 'to' (${t}).", ("f", e.from)("t", e.to)); + GOLOS_CHECK_LOGIC(o.receiver == e.to, + logic_exception::from_can_release_only_to_to, + "Only 'from' (${f}) can release funds to 'to' (${t}).", ("f",e.from)("t",e.to)); } else if (o.who == e.to) { - FC_ASSERT(o.receiver == - e.from, "Only 'to' (${t}) can release funds to 'from' (${t}).", ("f", e.from)("t", e.to)); + GOLOS_CHECK_LOGIC(o.receiver == e.from, + logic_exception::to_can_release_only_to_from, + "Only 'to' (${t}) can release funds to 'from' (${t}).", ("f",e.from)("t",e.to)); } } } @@ -894,7 +906,7 @@ namespace golos { namespace chain { _db.adjust_balance(receiver_account, o.steem_amount); _db.adjust_balance(receiver_account, o.sbd_amount); - _db.modify(e, [&](escrow_object &esc) { + _db.modify(e, [&](escrow_object& esc) { esc.steem_balance -= o.steem_amount; esc.sbd_balance -= o.sbd_amount; }); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index fcaf62fede..96a7f74fc0 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -522,24 +522,20 @@ namespace golos { namespace protocol { } void escrow_release_operation::validate() const { - validate_account_name(from); - validate_account_name(to); - validate_account_name(agent); - validate_account_name(who); - validate_account_name(receiver); - FC_ASSERT(who == from || who == to || - who == agent, "who must be from or to or agent"); - FC_ASSERT(receiver == from || - receiver == to, "receiver must be from or to"); - FC_ASSERT(sbd_amount.amount >= 0, "gbg amount cannot be negative"); - FC_ASSERT(steem_amount.amount >= - 0, "golos amount cannot be negative"); - FC_ASSERT(sbd_amount.amount > 0 || steem_amount.amount > - 0, "escrow must release a non-zero amount"); - FC_ASSERT(sbd_amount.symbol == - SBD_SYMBOL, "gbg amount must contain GBG"); - FC_ASSERT(steem_amount.symbol == - STEEM_SYMBOL, "golos amount must contain GOLOS"); + GOLOS_CHECK_PARAM_ACCOUNT(from); + GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM_ACCOUNT(agent); + GOLOS_CHECK_PARAM_ACCOUNT(who); + GOLOS_CHECK_PARAM_ACCOUNT(receiver); + GOLOS_CHECK_PARAM(who, + GOLOS_CHECK_VALUE(who == from || who == to || who == agent, "who must be from or to or agent")); + GOLOS_CHECK_PARAM(receiver, + GOLOS_CHECK_VALUE(receiver == from || receiver == to, "receiver must be from or to")); + GOLOS_CHECK_PARAM(sbd_amount, GOLOS_CHECK_ASSET_GE0(sbd_amount, GBG)); + GOLOS_CHECK_PARAM(steem_amount, GOLOS_CHECK_ASSET_GE0(steem_amount, GOLOS)); + GOLOS_CHECK_LOGIC(sbd_amount.amount > 0 || steem_amount.amount > 0, + logic_exception::escrow_no_amount_set, + "escrow must release a non-zero amount"); } void request_account_recovery_operation::validate() const { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 256240d2b7..979f4d40c4 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -5084,47 +5084,52 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_SUITE_END() // escrow_dispute + BOOST_AUTO_TEST_SUITE(escrow_release) + BOOST_AUTO_TEST_CASE(escrow_release_validate) { try { BOOST_TEST_MESSAGE("Testing: escrow release validate"); escrow_release_operation op; op.from = "alice"; op.to = "bob"; - op.who = "alice"; op.agent = "sam"; + op.who = "alice"; op.receiver = "bob"; + op.steem_amount = ASSET_GOLOS(1); + op.sbd_amount = ASSET_GBG(0); + BOOST_TEST_MESSAGE("--- success"); + CHECK_OP_VALID(op); + BOOST_TEST_MESSAGE("--- failure when invalid account"); + CHECK_PARAM_INVALID(op, from, ""); + CHECK_PARAM_INVALID(op, to, ""); + CHECK_PARAM_INVALID(op, agent, ""); + CHECK_PARAM_INVALID(op, who, ""); + CHECK_PARAM_INVALID(op, receiver, ""); - BOOST_TEST_MESSAGE("--- failure when steem < 0"); - op.steem_amount.amount = -1; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- failure when who not from or to or agent"); + CHECK_PARAM_INVALID(op, who, "dave"); + BOOST_TEST_MESSAGE("--- failure when receiver not from or to"); + CHECK_PARAM_INVALID(op, receiver, "sam"); + CHECK_PARAM_INVALID(op, receiver, "dave"); - BOOST_TEST_MESSAGE("--- failure when sbd < 0"); - op.steem_amount.amount = 0; - op.sbd_amount.amount = -1; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); + BOOST_TEST_MESSAGE("--- failure when steem < 0"); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GOLOS(-1)); + BOOST_TEST_MESSAGE("--- failure when sbd < 0"); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GBG(-1)); BOOST_TEST_MESSAGE("--- failure when steem == 0 and sbd == 0"); - op.sbd_amount.amount = 0; - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - + CHECK_PARAM_INVALID_LOGIC(op, steem_amount, ASSET_GOLOS(0), escrow_no_amount_set); BOOST_TEST_MESSAGE("--- failure when sbd is not sbd symbol"); - op.sbd_amount = ASSET("1.000 GOLOS"); - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GOLOS(1)); + CHECK_PARAM_INVALID(op, sbd_amount, ASSET_GESTS(1)); BOOST_TEST_MESSAGE("--- failure when steem is not steem symbol"); - op.sbd_amount.symbol = SBD_SYMBOL; - op.steem_amount = ASSET("1.000 GBG"); - STEEMIT_REQUIRE_THROW(op.validate(), fc::exception); - - - BOOST_TEST_MESSAGE("--- success"); - op.steem_amount.symbol = STEEM_SYMBOL; - op.validate(); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GBG(0)); + CHECK_PARAM_INVALID(op, steem_amount, ASSET_GESTS(0)); } FC_LOG_AND_RETHROW() } @@ -5136,33 +5141,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.from = "alice"; op.to = "bob"; op.who = "alice"; - - flat_set auths; - flat_set expected; - - op.get_required_owner_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.get_required_posting_authorities(auths); - BOOST_REQUIRE(auths == expected); - - expected.insert("alice"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); - + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); op.who = "bob"; - auths.clear(); - expected.clear(); - expected.insert("bob"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); - - op.who = "sam"; - auths.clear(); - expected.clear(); - expected.insert("sam"); - op.get_required_active_authorities(auths); - BOOST_REQUIRE(auths == expected); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set({op.who}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -5170,7 +5151,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(escrow_release_apply) { try { BOOST_TEST_MESSAGE("Testing: escrow_release_apply"); - ACTORS((alice)(bob)(sam)(dave)) fund("alice", 10000); @@ -5184,13 +5164,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) et_op.escrow_expiration = db->head_block_time() + 2 * STEEMIT_BLOCK_INTERVAL; signed_transaction tx; - tx.operations.push_back(et_op); - - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, et_op)); BOOST_TEST_MESSAGE("--- failure releasing funds prior to approval"); escrow_release_operation op; @@ -5200,453 +5174,274 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.who = et_op.from; op.receiver = et_op.to; op.steem_amount = ASSET("0.100 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::escrow_must_be_approved_first))); escrow_approve_operation ea_b_op; ea_b_op.from = "alice"; ea_b_op.to = "bob"; ea_b_op.agent = "sam"; ea_b_op.who = "bob"; - escrow_approve_operation ea_s_op; ea_s_op.from = "alice"; ea_s_op.to = "bob"; ea_s_op.agent = "sam"; ea_s_op.who = "sam"; - - tx.clear(); - tx.operations.push_back(ea_b_op); - tx.operations.push_back(ea_s_op); - tx.sign(bob_private_key, db->get_chain_id()); + sign_tx_with_ops(tx, bob_private_key, ea_b_op, ea_s_op); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); BOOST_TEST_MESSAGE("--- failure when 'agent' attempts to release non-disputed escrow to 'to'"); op.who = et_op.agent; - tx.clear(); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_from_to_can_release_non_disputed))); BOOST_TEST_MESSAGE("--- failure when 'agent' attempts to release non-disputed escrow to 'from' "); op.receiver = et_op.from; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_from_to_can_release_non_disputed))); BOOST_TEST_MESSAGE("--- failure when 'agent' attempt to release non-disputed escrow to not 'to' or 'from'"); op.receiver = "dave"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when other attempts to release non-disputed escrow to 'to'"); op.receiver = et_op.to; op.who = "dave"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "who")); BOOST_TEST_MESSAGE("--- failure when other attempts to release non-disputed escrow to 'from' "); op.receiver = et_op.from; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "who")); BOOST_TEST_MESSAGE("--- failure when other attempt to release non-disputed escrow to not 'to' or 'from'"); op.receiver = "dave"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "who")); BOOST_TEST_MESSAGE("--- failure when 'to' attemtps to release non-disputed escrow to 'to'"); op.receiver = et_op.to; op.who = et_op.to; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::to_can_release_only_to_from))); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release non-dispured escrow to 'agent' "); op.receiver = et_op.agent; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release non-disputed escrow to not 'from'"); op.receiver = "dave"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- success release non-disputed escrow to 'to' from 'from'"); op.receiver = et_op.from; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_escrow(op.from, op.escrow_id).steem_balance == - ASSET("0.900 GOLOS")); - BOOST_REQUIRE( - db->get_account("alice").balance == ASSET("9.000 GOLOS")); - + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); + BOOST_CHECK_EQUAL(db->get_escrow(op.from, op.escrow_id).steem_balance, ASSET("0.900 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.000 GOLOS")); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release non-disputed escrow to 'from'"); op.receiver = et_op.from; op.who = et_op.from; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::from_can_release_only_to_to))); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release non-disputed escrow to 'agent'"); op.receiver = et_op.agent; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release non-disputed escrow to not 'from'"); op.receiver = "dave"; - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- success release non-disputed escrow to 'from' from 'to'"); op.receiver = et_op.to; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_escrow(op.from, op.escrow_id).steem_balance == ASSET("0.800 GOLOS")); - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("0.100 GOLOS")); - + BOOST_CHECK_EQUAL(db->get_escrow(op.from, op.escrow_id).steem_balance, ASSET("0.800 GOLOS")); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.100 GOLOS")); BOOST_TEST_MESSAGE("--- failure when releasing more sbd than available"); op.steem_amount = ASSET("1.000 GOLOS"); - - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::release_amount_exceeds_escrow_balance))); BOOST_TEST_MESSAGE("--- failure when releasing less steem than available"); op.steem_amount = ASSET("0.000 GOLOS"); op.sbd_amount = ASSET("1.000 GBG"); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::release_amount_exceeds_escrow_balance))); - tx.clear(); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - - + generate_block(); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release disputed escrow"); escrow_dispute_operation ed_op; ed_op.from = "alice"; ed_op.to = "bob"; ed_op.agent = "sam"; ed_op.who = "alice"; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, ed_op)); - tx.clear(); - tx.operations.push_back(ed_op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - tx.clear(); op.from = et_op.from; op.receiver = et_op.from; op.who = et_op.to; op.steem_amount = ASSET("0.100 GOLOS"); op.sbd_amount = ASSET("0.000 GBG"); - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_agent_can_release_disputed))); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release disputed escrow"); - tx.clear(); op.receiver = et_op.to; op.who = et_op.from; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_agent_can_release_disputed))); BOOST_TEST_MESSAGE("--- failure when releasing disputed escrow to an account not 'to' or 'from'"); - tx.clear(); op.who = et_op.agent; op.receiver = "dave"; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when agent does not match escrow"); - tx.clear(); op.who = "dave"; op.receiver = et_op.from; - tx.operations.push_back(op); - tx.sign(dave_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "who")); BOOST_TEST_MESSAGE("--- success releasing disputed escrow with agent to 'to'"); - tx.clear(); op.receiver = et_op.to; op.who = et_op.agent; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("0.200 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.700 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.200 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.700 GOLOS")); BOOST_TEST_MESSAGE("--- success releasing disputed escrow with agent to 'from'"); - tx.clear(); op.receiver = et_op.from; op.who = et_op.agent; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("9.100 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.600 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.100 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.600 GOLOS")); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release disputed expired escrow"); generate_blocks(2); - - tx.clear(); op.receiver = et_op.from; op.who = et_op.to; - tx.operations.push_back(op); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_agent_can_release_disputed))); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release disputed expired escrow"); - tx.clear(); op.receiver = et_op.to; op.who = et_op.from; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_agent_can_release_disputed))); BOOST_TEST_MESSAGE("--- success releasing disputed expired escrow with agent"); - tx.clear(); op.receiver = et_op.from; op.who = et_op.agent; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("9.200 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.500 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.200 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.500 GOLOS")); BOOST_TEST_MESSAGE("--- success deleting escrow when balances are both zero"); - tx.clear(); op.steem_amount = ASSET("0.500 GOLOS"); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("9.700 GOLOS")); - STEEMIT_REQUIRE_THROW(db->get_escrow(et_op.from, et_op.escrow_id), fc::exception); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, sam_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.700 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(et_op.from, et_op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(et_op.from, et_op.escrow_id))); - tx.clear(); - et_op.ratification_deadline = - db->head_block_time() + STEEMIT_BLOCK_INTERVAL; - et_op.escrow_expiration = - db->head_block_time() + 2 * STEEMIT_BLOCK_INTERVAL; - tx.operations.push_back(et_op); - tx.operations.push_back(ea_b_op); - tx.operations.push_back(ea_s_op); - tx.set_expiration( - db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.sign(alice_private_key, db->get_chain_id()); + et_op.ratification_deadline = db->head_block_time() + STEEMIT_BLOCK_INTERVAL; + et_op.escrow_expiration = db->head_block_time() + 2 * STEEMIT_BLOCK_INTERVAL; + sign_tx_with_ops(tx, alice_private_key, et_op, ea_b_op, ea_s_op); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(db->push_transaction(tx, 0)); generate_blocks(2); - BOOST_TEST_MESSAGE("--- failure when 'agent' attempts to release non-disputed expired escrow to 'to'"); - tx.clear(); op.receiver = et_op.to; op.who = et_op.agent; op.steem_amount = ASSET("0.100 GOLOS"); - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_from_to_can_release_non_disputed))); BOOST_TEST_MESSAGE("--- failure when 'agent' attempts to release non-disputed expired escrow to 'from'"); - tx.clear(); op.receiver = et_op.from; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, sam_private_key, op), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_exception::only_from_to_can_release_non_disputed))); BOOST_TEST_MESSAGE("--- failure when 'agent' attempt to release non-disputed expired escrow to not 'to' or 'from'"); - tx.clear(); op.receiver = "dave"; - tx.operations.push_back(op); - tx.sign(sam_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release non-dispured expired escrow to 'agent'"); - tx.clear(); op.who = et_op.to; op.receiver = et_op.agent; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when 'to' attempts to release non-disputed expired escrow to not 'from' or 'to'"); - tx.clear(); op.receiver = "dave"; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- success release non-disputed expired escrow to 'to' from 'to'"); - tx.clear(); op.receiver = et_op.to; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("bob").balance == ASSET("0.300 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.900 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.300 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.900 GOLOS")); BOOST_TEST_MESSAGE("--- success release non-disputed expired escrow to 'from' from 'to'"); - tx.clear(); op.receiver = et_op.from; - tx.operations.push_back(op); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE(db->get_account("alice").balance == ASSET("8.700 GOLOS")); - BOOST_REQUIRE(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == ASSET("0.800 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("8.700 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.800 GOLOS")); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release non-disputed expired escrow to 'agent'"); - tx.clear(); op.who = et_op.from; op.receiver = et_op.agent; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- failure when 'from' attempts to release non-disputed expired escrow to not 'from' or 'to'"); - tx.clear(); op.receiver = "dave"; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - STEEMIT_REQUIRE_THROW(db->push_transaction(tx, 0), fc::exception); - + GOLOS_CHECK_ERROR_PROPS(op.validate(), CHECK_ERROR(invalid_parameter, "receiver")); BOOST_TEST_MESSAGE("--- success release non-disputed expired escrow to 'to' from 'from'"); - tx.clear(); op.receiver = et_op.to; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE( - db->get_account("bob").balance == ASSET("0.400 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.700 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("bob").balance, ASSET("0.400 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.700 GOLOS")); BOOST_TEST_MESSAGE("--- success release non-disputed expired escrow to 'from' from 'from'"); - tx.clear(); op.receiver = et_op.from; - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); - - BOOST_REQUIRE( - db->get_account("alice").balance == ASSET("8.800 GOLOS")); - BOOST_REQUIRE( - db->get_escrow(et_op.from, et_op.escrow_id).steem_balance == - ASSET("0.600 GOLOS")); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("8.800 GOLOS")); + BOOST_CHECK_EQUAL(db->get_escrow(et_op.from, et_op.escrow_id).steem_balance, ASSET("0.600 GOLOS")); BOOST_TEST_MESSAGE("--- success deleting escrow when balances are zero on non-disputed escrow"); - tx.clear(); op.steem_amount = ASSET("0.600 GOLOS"); - tx.operations.push_back(op); - tx.sign(alice_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); - BOOST_REQUIRE( - db->get_account("alice").balance == ASSET("9.400 GOLOS")); - STEEMIT_REQUIRE_THROW(db->get_escrow(et_op.from, et_op.escrow_id), fc::exception); + BOOST_CHECK_EQUAL(db->get_account("alice").balance, ASSET("9.400 GOLOS")); + GOLOS_CHECK_ERROR_PROPS(db->get_escrow(et_op.from, et_op.escrow_id), + CHECK_ERROR(missing_object, "escrow", make_escrow_id(et_op.from, et_op.escrow_id))); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() // escrow_release BOOST_AUTO_TEST_SUITE_END() // escrow //------------------------------------------------------------- From a2d21ad5d1e77abdbfcc9351fb6e499e95390656 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 25 Jul 2018 12:21:21 +0300 Subject: [PATCH 142/250] Refactor errors: account recovery operations (review fixes) #790 --- libraries/chain/steem_evaluator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index a91d90b95f..a5030c1548 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -2053,7 +2053,7 @@ namespace golos { namespace chain { "Cannot recover using an open authority."); }); // Check accounts in the new authority exist - if (_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || _db.is_producing()) { + if (_db.has_hardfork(STEEMIT_HARDFORK_0_15__465)) { for (auto& a : o.new_owner_authority.account_auths) { _db.get_account(a.first); } @@ -2073,7 +2073,7 @@ namespace golos { namespace chain { "Cannot recover using an impossible authority."); }); // Check accounts in the new authority exist - if ((_db.has_hardfork(STEEMIT_HARDFORK_0_15__465) || _db.is_producing())) { + if (_db.has_hardfork(STEEMIT_HARDFORK_0_15__465)) { for (auto& a : o.new_owner_authority.account_auths) { _db.get_account(a.first); } From ce63b9a04f496c71ea98caa024feb2c424072c06 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 25 Jul 2018 16:32:07 +0700 Subject: [PATCH 143/250] Fix clearing of comment content. #860 --- plugins/social_network/social_network.cpp | 81 +++++++++++++---------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index bd0401e3ab..d82ed78988 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -43,9 +43,10 @@ struct content_depth_params { } bool miss_content() const { - return has_comment_title_depth && !comment_title_depth && - has_comment_body_depth && !comment_body_depth && - has_comment_json_metadata_depth && !comment_json_metadata_depth; + return + has_comment_title_depth && !comment_title_depth && + has_comment_body_depth && !comment_body_depth && + has_comment_json_metadata_depth && !comment_json_metadata_depth; } bool need_clear() const { @@ -53,11 +54,17 @@ struct content_depth_params { } bool should_delete_whole_content_object(const uint32_t delta) const { - return delta > comment_title_depth && delta > comment_body_depth && delta > comment_json_metadata_depth; + return + (has_comment_title_depth && delta > comment_title_depth) && + (has_comment_body_depth && delta > comment_body_depth) && + (has_comment_json_metadata_depth && delta > comment_json_metadata_depth); } bool should_delete_part_of_content_object(const uint32_t delta) const { - return delta > comment_title_depth || delta > comment_body_depth || delta > comment_json_metadata_depth; + return + (has_comment_title_depth && delta > comment_title_depth) || + (has_comment_body_depth && delta > comment_body_depth) || + (has_comment_json_metadata_depth && delta > comment_json_metadata_depth); } @@ -299,45 +306,47 @@ namespace golos { namespace plugins { namespace social_network { } FC_CAPTURE_AND_RETHROW() } - void social_network::impl::on_block(const signed_block& b) { - try { - const auto& idx = db.get_index().indices().get(); + void social_network::impl::on_block(const signed_block& b) { try { + const auto& dp = depth_parameters; - for (auto itr = idx.begin(); itr != idx.end();) { - auto& content = *itr; - ++itr; + if (!dp.need_clear()) { + return; + } - auto& comment = db.get(content.comment); + const auto& idx = db.get_index().indices().get(); - - auto delta = db.head_block_num() - content.block_number; - if (comment.mode == archived && depth_parameters.should_delete_part_of_content_object(delta)) { - if (depth_parameters.should_delete_whole_content_object(delta)) { - db.remove(content); - continue; - } + for (auto itr = idx.begin(); itr != idx.end();) { + auto& content = *itr; + ++itr; - db.modify(content, [&](comment_content_object& con) { - if (delta > depth_parameters.comment_title_depth) { - con.title.clear(); - } + auto& comment = db.get(content.comment); - if (delta > depth_parameters.comment_body_depth) { - con.body.clear(); - } + auto delta = db.head_block_num() - content.block_number; + if (comment.mode == archived && dp.should_delete_part_of_content_object(delta)) { + if (dp.should_delete_whole_content_object(delta)) { + db.remove(content); + continue; + } - if (delta > depth_parameters.comment_json_metadata_depth) { - con.json_metadata.clear(); - } - }); + db.modify(content, [&](comment_content_object& con) { + if (dp.has_comment_title_depth && delta > dp.comment_title_depth) { + con.title.clear(); + } - } - else { - break; - } + if (dp.has_comment_body_depth && delta > dp.comment_body_depth) { + con.body.clear(); + } + + if (dp.has_comment_json_metadata_depth && delta > dp.comment_json_metadata_depth) { + con.json_metadata.clear(); + } + }); + + } else { + break; } - } FC_CAPTURE_AND_RETHROW() - } + } + } FC_CAPTURE_AND_RETHROW() } void social_network::plugin_startup() { wlog("social_network plugin: plugin_startup()"); From 465624391b816a4254de05bbb1ec02277adad6da Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 25 Jul 2018 19:11:44 +0700 Subject: [PATCH 144/250] Refactor test fixture for testing plugins #791 Added the ability to pass to fixture a list of plugins that should be initialized for the test, and also pass a list of options for initializing plugins. --- .../chain/include/golos/chain/database.hpp | 2 + .../include/golos/plugins/chain/plugin.hpp | 7 + plugins/chain/plugin.cpp | 2 + plugins/operation_history/plugin.cpp | 2 - share/golosd/docker/Dockerfile-test | 12 +- tests/CMakeLists.txt | 28 +--- tests/common/database_fixture.cpp | 89 +--------- tests/common/database_fixture.hpp | 108 +++++++++--- tests/common/options_fixture.cpp | 84 ---------- tests/common/options_fixture.hpp | 143 ---------------- tests/plugin_tests/account_history.cpp | 70 ++++++++ .../account_history_blocks_test.cpp | 44 ----- tests/plugin_tests/black_options_postfix.cpp | 32 ---- tests/plugin_tests/operation_history.cpp | 154 ++++++++++++++++++ .../operation_history_blocks_test.cpp | 50 ------ .../short_list_operation_postfix_test.cpp | 45 ----- tests/plugin_tests/white_options_postfix.cpp | 35 ---- 17 files changed, 337 insertions(+), 570 deletions(-) delete mode 100644 tests/common/options_fixture.cpp delete mode 100644 tests/common/options_fixture.hpp create mode 100644 tests/plugin_tests/account_history.cpp delete mode 100644 tests/plugin_tests/account_history_blocks_test.cpp delete mode 100644 tests/plugin_tests/black_options_postfix.cpp create mode 100644 tests/plugin_tests/operation_history.cpp delete mode 100644 tests/plugin_tests/operation_history_blocks_test.cpp delete mode 100644 tests/plugin_tests/short_list_operation_postfix_test.cpp delete mode 100644 tests/plugin_tests/white_options_postfix.cpp diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 8c398fb355..925c9c3a2b 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -615,6 +615,8 @@ namespace golos { namespace chain { template friend void add_plugin_index(database &db); + friend class database_fixture; + fc::signal _plugin_index_signal; transaction_id_type _current_trx_id; diff --git a/plugins/chain/include/golos/plugins/chain/plugin.hpp b/plugins/chain/include/golos/plugins/chain/plugin.hpp index 967c66dfe4..892834d3cc 100644 --- a/plugins/chain/include/golos/plugins/chain/plugin.hpp +++ b/plugins/chain/include/golos/plugins/chain/plugin.hpp @@ -12,6 +12,10 @@ // for api #include +namespace golos { namespace chain { +struct database_fixture; +} } // namespace golos::chain + namespace golos { namespace plugins { namespace chain { @@ -93,6 +97,9 @@ namespace golos { class plugin_impl; std::unique_ptr my; + + friend class golos::chain::database_fixture; // need to set skip_startup field + bool skip_startup = false; }; } } diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 1caf0971f1..693ab060de 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -350,6 +350,8 @@ namespace chain { } void plugin::plugin_startup() { + if (skip_startup) return; + ilog("Starting chain with shared_file_size: ${n} bytes", ("n", my->shared_memory_size)); auto data_dir = appbase::app().data_dir() / "blockchain"; diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 1839c9be22..44ee9cbb5e 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -199,8 +199,6 @@ namespace golos { namespace plugins { namespace operation_history { boost::program_options::value()->composing(), "Defines depth of history for recording stats." ); - - cfg.add(cli); } void plugin::plugin_initialize(const boost::program_options::variables_map& options) { diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index fba28a7376..909c98ecf5 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -44,17 +44,9 @@ RUN \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ - make -j$(nproc) chain_test plugin_test \ - black_options_test white_options_test short_list_operation_postfix_test \ - operation_history_blocks_test \ - account_history_blocks_test && \ + make -j$(nproc) chain_test plugin_test && \ ./tests/chain_test --log_level=message --report_level=detailed && \ - ./tests/plugin_test --log_level=message --report_level=detailed && \ - ./tests/white_options_test --log_level=message --report_level=detailed && \ - ./tests/black_options_test --log_level=message --report_level=detailed && \ - ./tests/operation_history_blocks_test --log_level=message --report_level=detailed && \ - ./tests/short_list_operation_postfix_test --log_level=message --report_level=detailed && \ - ./tests/account_history_blocks_test --log_level=message --report_level=detailed + ./tests/plugin_test --log_level=message --report_level=detailed # isn't used now, but can be used later ... # diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4797c72fcc..d49c86eccd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,7 @@ file(GLOB COMMON_SOURCES common/database_fixture.cpp common/database_fixture.hpp - common/comment_reward.hpp - common/options_fixture.hpp - common/options_fixture.cpp) + common/comment_reward.hpp) find_package(Gperftools QUIET) if(GPERFTOOLS_FOUND) @@ -36,7 +34,9 @@ file(GLOB PLUGIN_TESTS "plugin_tests/main.cpp" "plugin_tests/market_history.cpp" "plugin_tests/plugin_ops.cpp" - "plugin_tests/json_rpc.cpp") + "plugin_tests/json_rpc.cpp" + "plugin_tests/operation_history.cpp" + "plugin_tests/account_history.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") @@ -63,26 +63,6 @@ macro(add_exec_test) add_test(NAME "${GET_NAME}_test_run" COMMAND "${GET_NAME}_test") endmacro(add_exec_test) -add_exec_test(NAME "white_options" FILES - "plugin_tests/main.cpp" - "plugin_tests/white_options_postfix.cpp") - -add_exec_test(NAME "black_options" FILES - "plugin_tests/main.cpp" - "plugin_tests/black_options_postfix.cpp") - -add_exec_test(NAME "operation_history_blocks" FILES - "plugin_tests/main.cpp" - "plugin_tests/operation_history_blocks_test.cpp") - -add_exec_test(NAME "short_list_operation_postfix" FILES - "plugin_tests/main.cpp" - "plugin_tests/short_list_operation_postfix_test.cpp") - -add_exec_test(NAME "account_history_blocks" FILES - "plugin_tests/main.cpp" - "plugin_tests/account_history_blocks_test.cpp") - if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") endif(MSVC) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index f6a41fa4e9..90e9049894 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -140,6 +140,10 @@ namespace golos { namespace chain { } close_database(); + db->_plugin_index_signal = fc::signal(); + appbase::app().quit(); + appbase::app().shutdown(); + appbase::reset(); } clean_database_fixture::clean_database_fixture() { @@ -231,24 +235,9 @@ namespace golos { namespace chain { } }; - add_operations_database_fixture::add_operations_database_fixture() : _plg(nullptr) { - try { - ilog("add_operations_database_fixture: begin"); - - _plg = app_initialise().get_plugin(); - initialize(); - open_database(); - } catch (const fc::exception &e) { - edump((e.to_detail_string())); - throw; - } - } - - add_operations_database_fixture::~add_operations_database_fixture() try { - ilog("add_operations_database_fixture: end"); - } FC_LOG_AND_RETHROW(); + add_operations_database_fixture::Operations add_operations_database_fixture::add_operations() try { + Operations _added_ops; - void add_operations_database_fixture::add_operations() try { ACTORS((alice)(bob)(sam)) fund("alice", 10000); vest("alice", 10000); @@ -327,34 +316,11 @@ namespace golos { namespace chain { tx.signatures.clear(); validate_database(); - } FC_LOG_AND_RETHROW(); - - add_accounts_database_fixture::add_accounts_database_fixture() : _plg(nullptr) { - try { - ilog("add_accounts_database_fixture: begin"); - - _account_names.insert("alice"); - _account_names.insert("bob"); - _account_names.insert("sam"); - _account_names.insert("dave"); - - _plg = app_initialise().get_plugin(); - initialize(); - open_database(); - } catch (const fc::exception &e) { - edump((e.to_detail_string())); - throw; - } - } - - add_accounts_database_fixture::~add_accounts_database_fixture() { - ilog("add_accounts_database_fixture: end"); - } - void add_accounts_database_fixture::add_accounts() try { - add_operations_database_fixture::add_operations(); + return _added_ops; } FC_LOG_AND_RETHROW(); + fc::ecc::private_key database_fixture::generate_private_key(string seed) { return fc::ecc::private_key::regenerate(fc::sha256::hash(seed)); } @@ -365,40 +331,6 @@ namespace golos { namespace chain { return "anon-acct-x" + std::to_string(anon_acct_count++); } - void database_fixture::initialize() { - int argc = boost::unit_test::framework::master_test_suite().argc; - char** argv = boost::unit_test::framework::master_test_suite().argv; - for (int i = 1; i < argc; i++) { - const std::string arg = argv[i]; - if (arg == "--record-assert-trip") { - fc::enable_record_assert_trip = true; - } - if (arg == "--show-test-names") { - std::cout << "running test " - << boost::unit_test::framework::current_test_case().p_name - << std::endl; - } - } - - ch_plugin = &appbase::app().register_plugin(); - oh_plugin = &appbase::app().register_plugin(); - ah_plugin = &appbase::app().register_plugin(); - sn_plugin = &appbase::app().register_plugin(); - db_plugin = &appbase::app().register_plugin(); - - appbase::app().initialize< - golos::plugins::chain::plugin, - account_history::plugin, - debug_node::plugin, - golos::plugins::social_network::social_network - >( argc, argv ); - - db_plugin->set_logging(false); - - db = &ch_plugin->db(); - BOOST_REQUIRE(db); - } - void database_fixture::startup(bool generate_hardfork) { generate_block(); if (generate_hardfork) { @@ -418,10 +350,7 @@ namespace golos { namespace chain { STEEMIT_MIN_PRODUCER_REWARD.amount); } - oh_plugin->plugin_startup(); - ah_plugin->plugin_startup(); - db_plugin->plugin_startup(); - sn_plugin->plugin_startup(); + appbase::app().startup(); validate_database(); } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 02d636aca1..f5bed19ee5 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -421,6 +421,24 @@ namespace golos { namespace chain { using namespace golos::protocol; + namespace { + template + struct PluginRegistrator; + + template + struct PluginRegistrator { + static void register_plugins() { + appbase::app().register_plugin

(); + PluginRegistrator::register_plugins(); + } + }; + + template<> + struct PluginRegistrator<> { + static void register_plugins() {} + }; + } // anonymous namespace + struct database_fixture { // the reason we use an app is to exercise the indexes of built-in plugins chain::database* db; @@ -432,7 +450,6 @@ namespace golos { namespace chain { golos::plugins::chain::plugin* ch_plugin = nullptr; golos::plugins::debug_node::plugin* db_plugin = nullptr; - golos::plugins::operation_history::plugin* oh_plugin = nullptr; golos::plugins::account_history::plugin* ah_plugin = nullptr; golos::plugins::social_network::social_network* sn_plugin = nullptr; @@ -450,7 +467,63 @@ namespace golos { namespace chain { string generate_anon_acct_name(); - void initialize(); + template + Plugin *find_plugin() { + return dynamic_cast(appbase::app().find_plugin()); + } + + typedef std::map Options; + template + void initialize(const Options& opts = {}) { + int argc = boost::unit_test::framework::master_test_suite().argc; + char** argv = boost::unit_test::framework::master_test_suite().argv; + + for (int i = 1; i < argc; i++) { + const std::string arg = argv[i]; + if (arg == "--record-assert-trip") { + fc::enable_record_assert_trip = true; + } + if (arg == "--show-test-names") { + std::cout << "running test " + << boost::unit_test::framework::current_test_case().p_name + << std::endl; + } + } + + ch_plugin = &appbase::app().register_plugin(); + db_plugin = &appbase::app().register_plugin(); + sn_plugin = &appbase::app().register_plugin(); + ah_plugin = &appbase::app().register_plugin(); + PluginRegistrator::register_plugins(); + + ch_plugin->skip_startup = true; + + std::vector args; + std::vector args_data; + args.push_back(argv[0]); + for (const auto& opt: opts) { + args_data.push_back(std::string("--")+opt.first); + args.push_back(args_data.back().c_str()); + args.push_back(opt.second.c_str()); + } + for (int i = 1; i < argc; i++) { + args.push_back(argv[i]); + } + + appbase::app().initialize< + golos::plugins::chain::plugin, + golos::plugins::account_history::plugin, + golos::plugins::debug_node::plugin, + golos::plugins::social_network::social_network, + Plugins... + >( args.size(), const_cast(args.data()) ); + + db_plugin->set_logging(false); + + db = &ch_plugin->db(); + BOOST_REQUIRE(db); + } + void startup(bool generate_hardfork = true); void open_database(); @@ -589,27 +662,20 @@ namespace golos { namespace chain { }; struct add_operations_database_fixture : public database_fixture { - typedef golos::plugins::operation_history::plugin plugin_type; - - add_operations_database_fixture(); - ~add_operations_database_fixture() override; - - void add_operations(); - - plugin_type* _plg; - std::map _added_ops; - }; - - struct add_accounts_database_fixture : public add_operations_database_fixture { - typedef golos::plugins::account_history::plugin plugin_type; - - add_accounts_database_fixture(); - ~add_accounts_database_fixture() override; + typedef golos::plugins::operation_history::plugin operation_history_plugin; + typedef std::map Operations; + + template + void initialize(const Options& opts = {}) { + database_fixture::initialize(opts); + oh_plugin = find_plugin(); + open_database(); + startup(); + } - void add_accounts(); + Operations add_operations(); - plugin_type* _plg; - fc::flat_set _account_names; + operation_history_plugin* oh_plugin = nullptr; }; namespace test { diff --git a/tests/common/options_fixture.cpp b/tests/common/options_fixture.cpp deleted file mode 100644 index 1f48c7089e..0000000000 --- a/tests/common/options_fixture.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include - -#include - -#include "options_fixture.hpp" - - -using namespace golos::test; - -namespace bpo = boost::program_options; - -typedef golos::chain::add_operations_database_fixture add_operations_database_fixture; -typedef golos::plugins::json_rpc::msg_pack msg_pack; - -using namespace golos::protocol; -using namespace golos::chain; - - -struct operation_visitor { - using result_type = std::string; - template - std::string operator()(const T&) const { - return std::string(fc::get_typename::name()); - } -} ovisit; - - -void operation_options_fixture::log_applied_options(const applied_operation &opts) const { - std::stringstream ss; - ss << "[" << opts.block << "] "; - ss << opts.trx_id.str() << " : "; /// golos::protocol::transaction_id_type - std::string op_name = opts.op.visit(ovisit); - ss << "\"" << op_name << "\""; /// golos::protocol::operation - ilog(ss.str()); -} - - -void operation_options_fixture::check_operations() { - uint32_t head_block_num = _db_init.db->head_block_num(); - ilog("Check history operations, block num is " + std::to_string(head_block_num)); - auto plg = _db_init._plg; - if (plg) { - for (uint32_t i = 0; i <= head_block_num; ++i) { - msg_pack mo; - mo.args = std::vector({fc::variant(i), fc::variant(false)}); - auto ops = plg->get_ops_in_block(mo); - for (auto o : ops) { - auto iter = _founded_ops.find(o.trx_id.str()); - if (iter == _founded_ops.end()) { - _founded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); - log_applied_options(o); - } - } - } - } else { - ilog("Operation history plugin is not inited."); - } -} - - -void account_options_fixture::check() { - uint32_t head_block_num = _db_init.db->head_block_num(); - ilog("Check history accounts, block num is " + std::to_string(head_block_num)); - auto plg = _db_init._plg; - if (plg) { - for (auto n : _db_init._account_names) { - msg_pack mp; - mp.args = std::vector({fc::variant(n), fc::variant(100), fc::variant(100)}); - auto accs = plg->get_account_history(mp); - for (auto a : accs) { - auto it = _founded_accs.find(a.second.block); - if (it == _founded_accs.end()) { - std::set set; - set.insert(n); - _founded_accs.insert(std::make_pair(a.second.block, set)); - } else { - it->second.insert(n); - } - } - } - } else { - ilog("Account history plugin is not inited."); - } -} diff --git a/tests/common/options_fixture.hpp b/tests/common/options_fixture.hpp deleted file mode 100644 index 24d825c44f..0000000000 --- a/tests/common/options_fixture.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include -#include -#include - - -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" - - -namespace bpo = boost::program_options; -namespace bfs = boost::filesystem; - -namespace golos { namespace test { - -using namespace golos::protocol; -using namespace golos::chain; - -typedef golos::plugins::operation_history::applied_operation applied_operation; - -typedef std::map chacked_operations_map; ///< pair { [itx_id], [operation name] } -typedef std::map> chacked_accounts_map; ///< pair { [block], [accaunt names] } - - -template -struct combine_postfix : key_type_option { - typedef std::vector opt_type; - std::string opt = - "account_create_operation," \ - "delete_comment_operation," \ - "vote," \ - "comment"; -}; - - -template -struct test_options : public opt_type { - bpo::options_description _cfg_opts; - bpo::options_description _cli_opts; - bpo::variables_map _vm_opts; - - void fill_default_options() { - bpo::options_description cfg_opts("Application Config Options"); - cfg_opts.add_options() - ("plugin", bpo::value>()->composing(), - "Plugin(s) to enable, may be specified multiple times") - ; - _cfg_opts.add(cfg_opts); - bpo::options_description cli_opts("Application Command Line Options"); - cli_opts.add_options() - ("help,h", "Print this help message and exit.") - ("version,v", "Print version information.") - ("data-dir,d", bpo::value()->default_value("./"), - "Directory containing configuration file config.ini") - ("config,c", bpo::value()->default_value("config.ini"), - "Configuration file name relative to data-dir") - ; - _cli_opts.add(cli_opts); - - bpo::options_description all_opts; - all_opts - .add(_cli_opts) - .add(_cfg_opts) - ; - const char *argv = "plugin"; - auto parsed_cmd_line = bpo::parse_command_line(1, &argv, all_opts); - bpo::store(parsed_cmd_line, _vm_opts); - } - - template - void fill_options() { - custom_opt_type cot; - std::stringstream ss_opts; - ss_opts << cot.key << " = " << cot.opt << "\n"; - std::istringstream iss_opts(ss_opts.str()); - _cfg_opts.add_options() - (cot.key.c_str(), bpo::value()) - ; - auto parsed_cfg = bpo::parse_config_file(iss_opts, _cfg_opts, true); - bpo::store(parsed_cfg, _vm_opts); - } - - test_options() { - fill_default_options(); - fill_options(); - } - - operator bpo::variables_map () const { - return _vm_opts; - } -}; - - -struct operation_options_fixture { - add_operations_database_fixture _db_init; - chacked_operations_map _founded_ops; - - operation_options_fixture() = default; - ~operation_options_fixture() = default; - - template - void init_plugin(const test_type& tt) { - ilog(std::string("init_plugin(") + typeid(test_type).name() + ")"); - _db_init._plg->plugin_initialize(tt); - _db_init._plg->plugin_startup(); - _db_init.startup(); - _db_init.add_operations(); - check_operations(); - } - - void log_applied_options(const applied_operation &opts) const; - - void check_operations(); -}; - - -struct account_options_fixture { - add_accounts_database_fixture _db_init; - chacked_accounts_map _founded_accs; - - account_options_fixture() = default; - ~account_options_fixture() = default; - - template - void init_plugin(const test_type& tt) { - ilog(std::string("init_plugin(") + typeid(test_type).name() + ")"); - _db_init._plg->plugin_initialize(tt); - _db_init._plg->plugin_startup(); - _db_init.startup(); - _db_init.add_accounts(); - check(); - } - - void check(); -}; -}} diff --git a/tests/plugin_tests/account_history.cpp b/tests/plugin_tests/account_history.cpp new file mode 100644 index 0000000000..7c864a4228 --- /dev/null +++ b/tests/plugin_tests/account_history.cpp @@ -0,0 +1,70 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" + + +using golos::plugins::json_rpc::msg_pack; + + +struct account_history_fixture : public golos::chain::add_operations_database_fixture { + typedef std::map> checked_accounts_map; ///< pair { [block], [accaunt names] } + typedef fc::flat_set account_names; + + checked_accounts_map check(const account_names& names) { + uint32_t head_block_num = db->head_block_num(); + ilog("Check history accounts, block num is " + std::to_string(head_block_num)); + checked_accounts_map _founded_accs; + for (auto n : names) { + msg_pack mp; + mp.args = std::vector({fc::variant(n), fc::variant(100), fc::variant(100)}); + auto accs = ah_plugin->get_account_history(mp); + for (auto a : accs) { + auto it = _founded_accs.find(a.second.block); + if (it == _founded_accs.end()) { + std::set set; + set.insert(n); + _founded_accs.insert(std::make_pair(a.second.block, set)); + } else { + it->second.insert(n); + } + } + } + return _founded_accs; + } +}; + + +BOOST_FIXTURE_TEST_SUITE(account_history_plugin, account_history_fixture) + +BOOST_AUTO_TEST_CASE(account_history_blocks) { + BOOST_TEST_MESSAGE("Testing: account_history_blocks"); + const uint32_t HISTORY_BLOCKS = 3; + initialize({{"history-blocks", std::to_string(HISTORY_BLOCKS)}}); + add_operations(); + + account_names names = {"alice", "bob", "sam", "dave"}; + auto _founded_accs = check(names); + + std::set blocks; + for (auto a : _founded_accs) { + for (auto n : a.second) { + ilog("block:" + std::to_string(a.first) + ", \"" + n + "\""); + auto iter = names.find(n); + bool is_found = (iter != names.end()); + BOOST_CHECK(is_found); + if (is_found) { + blocks.insert(a.first); + } else { + BOOST_TEST_MESSAGE("Account [" + std::to_string(a.first) + "]: \"" + n + "\" is not found"); + } + } + } + BOOST_CHECK_EQUAL(blocks.size(), HISTORY_BLOCKS); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/plugin_tests/account_history_blocks_test.cpp b/tests/plugin_tests/account_history_blocks_test.cpp deleted file mode 100644 index d844f3cd0f..0000000000 --- a/tests/plugin_tests/account_history_blocks_test.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -static uint32_t HISTORY_BLOCKS = 3; - - -struct account_options { - typedef uint32_t opt_type; - std::string key = "history-blocks"; - std::string opt = std::to_string(HISTORY_BLOCKS); -}; - - -BOOST_FIXTURE_TEST_CASE(account_history_blocks, account_options_fixture) { - auto tops = test_options(); - init_plugin(tops); - - std::set blocks; - for (auto a : _founded_accs) { - for (auto n : a.second) { - ilog("block:" + std::to_string(a.first) + ", \"" + n + "\""); - auto iter = _db_init._account_names.find(n); - bool is_found = (iter != _db_init._account_names.end()); - BOOST_CHECK(is_found); - if (is_found) { - blocks.insert(a.first); - } else { - BOOST_TEST_MESSAGE("Account [" + std::to_string(a.first) + "]: \"" + n + "\" is not found"); - } - } - } - BOOST_CHECK_EQUAL(blocks.size(), HISTORY_BLOCKS); -} diff --git a/tests/plugin_tests/black_options_postfix.cpp b/tests/plugin_tests/black_options_postfix.cpp deleted file mode 100644 index ea76ea01c2..0000000000 --- a/tests/plugin_tests/black_options_postfix.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -struct blacklist_key { - std::string key = "history-blacklist-ops"; -}; - - -BOOST_FIXTURE_TEST_CASE(black_options_postfix, operation_options_fixture) { - init_plugin(test_options>()); - - size_t _chacked_ops_count = 0; - for (const auto &co : _db_init._added_ops) { - auto iter = _founded_ops.find(co.first); - bool is_not_found = (iter == _founded_ops.end()); - BOOST_CHECK(is_not_found); - if (is_not_found) { - ++_chacked_ops_count; - } else { - BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is found"); - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, _db_init._added_ops.size()); -} diff --git a/tests/plugin_tests/operation_history.cpp b/tests/plugin_tests/operation_history.cpp new file mode 100644 index 0000000000..72dcf7a5ed --- /dev/null +++ b/tests/plugin_tests/operation_history.cpp @@ -0,0 +1,154 @@ +#include +#include + +#include +#include + +#include "database_fixture.hpp" +#include "comment_reward.hpp" + +using golos::chain::add_operations_database_fixture; +using golos::plugins::operation_history::applied_operation; +using golos::plugins::json_rpc::msg_pack; + +static const std::string OPERATIONS = "account_create_operation,delete_comment_operation,vote,comment"; + +struct operation_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + return std::string(fc::get_typename::name()); + } +}; + +void log_applied_options(const applied_operation &opts) { + std::stringstream ss; + ss << "[" << opts.block << "] "; + ss << opts.trx_id.str() << " : "; /// golos::protocol::transaction_id_type + operation_visitor ovisit; + std::string op_name = opts.op.visit(ovisit); + ss << "\"" << op_name << "\""; /// golos::protocol::operation + ilog(ss.str()); +} + +struct operation_history_fixture : public add_operations_database_fixture { + Operations check_operations() { + uint32_t head_block_num = db->head_block_num(); + ilog("Check history operations, block num is " + std::to_string(head_block_num)); + + Operations _founded_ops; + operation_visitor ovisit; + for (uint32_t i = 0; i <= head_block_num; ++i) { + msg_pack mo; + mo.args = std::vector({fc::variant(i), fc::variant(false)}); + auto ops = oh_plugin->get_ops_in_block(mo); + for (auto o : ops) { + auto iter = _founded_ops.find(o.trx_id.str()); + if (iter == _founded_ops.end()) { + _founded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); + log_applied_options(o); + } + } + } + return _founded_ops; + } +}; + +BOOST_FIXTURE_TEST_SUITE(operation_history_plugin, operation_history_fixture) + +BOOST_AUTO_TEST_CASE(operation_history_blocks) { + const uint32_t HISTORY_BLOCKS = 2; + BOOST_TEST_MESSAGE("Testing: operation_history_blocks"); + initialize({ + {"history-blocks",std::to_string(HISTORY_BLOCKS)}, + {"history-whitelist-ops",OPERATIONS} + }); + + auto _added_ops = add_operations(); + auto _founded_ops = check_operations(); + + size_t _checked_ops_count = 0; + for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { + auto iter = _added_ops.find(it->first); + bool is_found = (iter != _added_ops.end()); + BOOST_CHECK(is_found); + if (is_found) { + BOOST_CHECK_EQUAL(iter->second, it->second); + if (iter->second == it->second) { + ++_checked_ops_count; + } + } else { + BOOST_TEST_MESSAGE("Operation \"" + it->second + "\" by \"" + it->first + "\" is not found"); + } + } + BOOST_CHECK_EQUAL(_checked_ops_count, HISTORY_BLOCKS); +} + +BOOST_AUTO_TEST_CASE(black_options_postfix) { + BOOST_TEST_MESSAGE("Testing: black_options_postfix"); + initialize({{"history-blacklist-ops", OPERATIONS}}); + + auto _added_ops = add_operations(); + auto _founded_ops = check_operations(); + + size_t _chacked_ops_count = 0; + for (const auto &co : _added_ops) { + auto iter = _founded_ops.find(co.first); + bool is_not_found = (iter == _founded_ops.end()); + BOOST_CHECK(is_not_found); + if (is_not_found) { + ++_chacked_ops_count; + } else { + BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, _added_ops.size()); +} + +BOOST_AUTO_TEST_CASE(white_options_postfix) { + BOOST_TEST_MESSAGE("Testing: white_options_postfix"); + initialize({{"history-whitelist-ops", OPERATIONS}}); + + auto _added_ops = add_operations(); + auto _founded_ops = check_operations(); + + size_t _chacked_ops_count = 0; + for (const auto &co : _added_ops) { + auto iter = _founded_ops.find(co.first); + bool is_found = (iter != _founded_ops.end()); + BOOST_CHECK(is_found); + if (is_found) { + BOOST_CHECK_EQUAL(iter->second, co.second); + if (iter->second == co.second) { + ++_chacked_ops_count; + } + } else { + BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, _added_ops.size()); +} + +BOOST_AUTO_TEST_CASE(short_operation_history_blocks) { + BOOST_TEST_MESSAGE("Testing: short_operation_history_blocks"); + initialize({{"history-whitelist-ops","account_create_operation,delete_comment,comment"}}); + + auto _added_ops = add_operations(); + auto _founded_ops = check_operations(); + + size_t _chacked_ops_count = 0; + for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { + auto iter = _added_ops.find(it->first); + bool is_found = (iter != _added_ops.end()); + if (is_found) { + BOOST_TEST_MESSAGE("Found operation \"" + it->second + "\" by \"" + it->first + "\""); + BOOST_CHECK_EQUAL(iter->second, it->second); + if (iter->second == it->second) { + ++_chacked_ops_count; + } + } + } + BOOST_CHECK_EQUAL(_chacked_ops_count, 3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/plugin_tests/operation_history_blocks_test.cpp b/tests/plugin_tests/operation_history_blocks_test.cpp deleted file mode 100644 index 6c1787e256..0000000000 --- a/tests/plugin_tests/operation_history_blocks_test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -struct whitelist_key { - std::string key = "history-whitelist-ops"; -}; - - -static uint32_t HISTORY_BLOCKS = 2; - - -struct blocks_limit_key { - typedef uint32_t opt_type; - std::string key = "history-blocks"; - std::string opt = std::to_string(HISTORY_BLOCKS); -}; - - -BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { - auto tops = test_options>(); - tops.fill_options(); - init_plugin(tops); - - size_t _chacked_ops_count = 0; - for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { - auto iter = _db_init._added_ops.find(it->first); - bool is_found = (iter != _db_init._added_ops.end()); - BOOST_CHECK(is_found); - if (is_found) { - BOOST_CHECK_EQUAL(iter->second, it->second); - if (iter->second == it->second) { - ++_chacked_ops_count; - } - } else { - BOOST_TEST_MESSAGE("Operation \"" + it->second + "\" by \"" + it->first + "\" is not found"); - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, HISTORY_BLOCKS); -} diff --git a/tests/plugin_tests/short_list_operation_postfix_test.cpp b/tests/plugin_tests/short_list_operation_postfix_test.cpp deleted file mode 100644 index aedf1f478d..0000000000 --- a/tests/plugin_tests/short_list_operation_postfix_test.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -struct short_list_options_postfix { - typedef std::vector opt_type; - std::string key = "history-whitelist-ops"; - std::string opt = - "account_create_operation," \ - "delete_comment," \ - "comment"; -}; - - -static const int SHORT_LIST_LEN = 3; - - -BOOST_FIXTURE_TEST_CASE(operation_history_blocks, operation_options_fixture) { - auto tops = test_options(); - init_plugin(tops); - - size_t _chacked_ops_count = 0; - for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { - auto iter = _db_init._added_ops.find(it->first); - bool is_found = (iter != _db_init._added_ops.end()); - if (is_found) { - BOOST_TEST_MESSAGE("Found operation \"" + it->second + "\" by \"" + it->first + "\""); - BOOST_CHECK_EQUAL(iter->second, it->second); - if (iter->second == it->second) { - ++_chacked_ops_count; - } - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, SHORT_LIST_LEN); -} diff --git a/tests/plugin_tests/white_options_postfix.cpp b/tests/plugin_tests/white_options_postfix.cpp deleted file mode 100644 index 8d8b1d89e0..0000000000 --- a/tests/plugin_tests/white_options_postfix.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -#include "database_fixture.hpp" -#include "comment_reward.hpp" -#include "options_fixture.hpp" - - -using namespace golos::test; - - -struct whitelist_key { - std::string key = "history-whitelist-ops"; -}; - - -BOOST_FIXTURE_TEST_CASE(white_options_postfix, operation_options_fixture) { - init_plugin(test_options>()); - - size_t _chacked_ops_count = 0; - for (const auto &co : _db_init._added_ops) { - auto iter = _founded_ops.find(co.first); - bool is_found = (iter != _founded_ops.end()); - BOOST_CHECK(is_found); - if (is_found) { - BOOST_CHECK_EQUAL(iter->second, co.second); - if (iter->second == co.second) { - ++_chacked_ops_count; - } - } else { - BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); - } - } - BOOST_CHECK_EQUAL(_chacked_ops_count, _db_init._added_ops.size()); -} From 9d10e38166f4e6e419b7eee2d3d5c8c2f6de6a7f Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Wed, 25 Jul 2018 20:06:03 +0700 Subject: [PATCH 145/250] Refactor errors: comment_options_operation (refiew fixes) #790 --- libraries/protocol/steem_operations.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 604f582523..30090a6220 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -107,7 +107,7 @@ namespace golos { namespace protocol { }; void comment_payout_beneficiaries::validate() const { - fc::safe sum = 0; // avoid overflow + uint32_t sum = 0; // avoid overflow GOLOS_CHECK_PARAM(beneficiaries, { GOLOS_CHECK_VALUE(beneficiaries.size(), "Must specify at least one beneficiary"); @@ -119,11 +119,10 @@ namespace golos { namespace protocol { GOLOS_CHECK_VALUE(beneficiar.weight <= STEEMIT_100_PERCENT, "Cannot allocate more than 100% of rewards to one account"); sum += beneficiar.weight; + GOLOS_CHECK_VALUE(sum <= STEEMIT_100_PERCENT, + "Cannot allocate more than 100% of rewards to a comment"); } - GOLOS_CHECK_VALUE(sum <= STEEMIT_100_PERCENT, - "Cannot allocate more than 100% of rewards to a comment"); - for (size_t i = 1; i < beneficiaries.size(); i++) { GOLOS_CHECK_VALUE(beneficiaries[i - 1] < beneficiaries[i], "Benficiaries ${first} and ${second} not in sorted order (account ascending)", From 0f85f575bf8416a219361fbe89988f424b578e01 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 25 Jul 2018 22:53:10 +0700 Subject: [PATCH 146/250] Fix update comment content. #860 --- plugins/social_network/social_network.cpp | 54 ++++++++++------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index d82ed78988..173597d9f9 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -219,7 +219,8 @@ namespace golos { namespace plugins { namespace social_network { } void operator()(const golos::protocol::comment_operation& o) const { - if (depth_parameters.miss_content()) { + const auto& dp = depth_parameters; + if (dp.miss_content()) { return; } @@ -229,17 +230,17 @@ namespace golos { namespace plugins { namespace social_network { if ( comment_content != nullptr) { // Edit case db.modify(*comment_content, [&]( comment_content_object& con ) { - if (o.title.size() && (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0)) { + if (o.title.size() && (!dp.has_comment_title_depth || dp.comment_title_depth > 0)) { from_string(con.title, o.title); } if (o.json_metadata.size()) { - if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && + if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && fc::is_utf8(o.json_metadata) ) { from_string(con.json_metadata, o.json_metadata ); } } - if (o.body.size() && (!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0)) { + if (o.body.size() && (!dp.has_comment_body_depth || dp.comment_body_depth > 0)) { try { diff_match_patch dmp; auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); @@ -248,12 +249,10 @@ namespace golos { namespace plugins { namespace social_network { auto patched_body = wstring_to_utf8(result.first); if(!fc::is_utf8(patched_body)) { from_string(con.body, fc::prune_invalid_utf8(patched_body)); - } - else { + } else { from_string(con.body, patched_body); } - } - else { // replace + } else { // replace from_string(con.body, o.body); } } catch ( ... ) { @@ -261,25 +260,24 @@ namespace golos { namespace plugins { namespace social_network { } } // Set depth null if needed (this parameter is given in config) - if (depth_parameters.set_null_after_update) { + if (dp.set_null_after_update) { con.block_number = db.head_block_num(); } }); - } - else { + } else { // Creation case db.create([&](comment_content_object& con) { con.comment = comment.id; - if (!depth_parameters.has_comment_title_depth || depth_parameters.comment_title_depth > 0) { + if (!dp.has_comment_title_depth || dp.comment_title_depth > 0) { from_string(con.title, o.title); } - if ((!depth_parameters.has_comment_body_depth || depth_parameters.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { + if ((!dp.has_comment_body_depth || dp.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { from_string(con.body, o.body); } - if ((!depth_parameters.has_comment_json_metadata_depth || depth_parameters.comment_json_metadata_depth > 0) && + if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && fc::is_utf8(o.json_metadata) ) { from_string(con.json_metadata, o.json_metadata); @@ -292,19 +290,15 @@ namespace golos { namespace plugins { namespace social_network { }; - void social_network::impl::pre_operation(const operation_notification& o) { - try { - delete_visitor ovisit(*this); - o.op.visit(ovisit); - } FC_CAPTURE_AND_RETHROW() - } + void social_network::impl::pre_operation(const operation_notification& o) { try { + delete_visitor ovisit(*this); + o.op.visit(ovisit); + } FC_CAPTURE_AND_RETHROW() } - void social_network::impl::post_operation(const operation_notification& o) { - try { - operation_visitor ovisit(*this); - o.op.visit(ovisit); - } FC_CAPTURE_AND_RETHROW() - } + void social_network::impl::post_operation(const operation_notification& o) { try { + operation_visitor ovisit(*this); + o.op.visit(ovisit); + } FC_CAPTURE_AND_RETHROW() } void social_network::impl::on_block(const signed_block& b) { try { const auto& dp = depth_parameters; @@ -621,14 +615,14 @@ namespace golos { namespace plugins { namespace social_network { } const auto content = db.find(co.id); if (content != nullptr) { - con.title = std::string(content->title.begin(), content->title.end()); - con.body = std::string(content->body.begin(), content->body.end()); - con.json_metadata = std::string(content->json_metadata.begin(), content->json_metadata.end()); + con.title = to_string(content->title); + con.body = to_string(content->body); + con.json_metadata = to_string(content->json_metadata); } const auto root_content = db.find(co.root_comment); if (root_content != nullptr) { - con.root_title = std::string(root_content->title.begin(), root_content->title.end()); + con.root_title = to_string(root_content->title); } } From 1c9dcf7bfcbdb788b50af030ca765bfbbcb91bd7 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 25 Jul 2018 23:10:02 +0700 Subject: [PATCH 147/250] Fix filling comment content in get_discussions. #860 --- libraries/api/discussion_helper.cpp | 29 ------------------- .../include/golos/api/discussion_helper.hpp | 8 ----- plugins/follow/plugin.cpp | 2 ++ plugins/tags/plugin.cpp | 3 +- 4 files changed, 4 insertions(+), 38 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 2c691531a1..f78776bcfd 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -54,14 +54,6 @@ namespace golos { namespace api { struct discussion_helper::impl final { public: impl() = delete; - impl( - golos::chain::database& db, - std::function&)> fill_reputation, - std::function fill_promoted) - : database_(db), - fill_reputation_(fill_reputation), - fill_promoted_(fill_promoted) { - } impl( golos::chain::database& db, std::function&)> fill_reputation, @@ -72,12 +64,6 @@ namespace golos { namespace api { fill_promoted_(fill_promoted), fill_comment_content_(fill_comment_content) { } - impl( - golos::chain::database& db, - std::function fill_comment_content) - : database_(db), - fill_comment_content_(fill_comment_content) { - } ~impl() = default; discussion create_discussion(const std::string& author) const ; @@ -313,14 +299,6 @@ namespace golos { namespace api { return pimpl->create_discussion(o); } - discussion_helper::discussion_helper( - golos::chain::database& db, - std::function&)> fill_reputation, - std::function fill_promoted - ) { - pimpl = std::make_unique(db, fill_reputation, fill_promoted); - } - discussion_helper::discussion_helper( golos::chain::database& db, std::function&)> fill_reputation, @@ -330,13 +308,6 @@ namespace golos { namespace api { pimpl = std::make_unique(db, fill_reputation, fill_promoted, fill_comment_content); } - discussion_helper::discussion_helper( - golos::chain::database& db, - std::function fill_comment_content - ) { - pimpl = std::make_unique(db, fill_comment_content); - } - discussion_helper::~discussion_helper() = default; // diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 6d68ed2196..7c5074a3c9 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -15,20 +15,12 @@ namespace golos { namespace api { class discussion_helper { public: discussion_helper() = delete; - discussion_helper( - golos::chain::database& db, - std::function&)> fill_reputation, - std::function fill_promoted); discussion_helper( golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, std::function fill_comment_content ); - discussion_helper( - golos::chain::database& db, - std::function fill_comment_content - ); ~discussion_helper(); diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index db48f75411..6cb83bc7a1 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -290,6 +290,8 @@ namespace golos { impl() : database_(appbase::app().get_plugin().db()) { helper = std::make_unique( database_, + follow::fill_account_reputation, + nullptr, golos::plugins::social_network::fill_comment_content ); } diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 8857d619e0..7871311c52 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -37,7 +37,8 @@ namespace golos { namespace plugins { namespace tags { helper = std::make_unique( database_, follow::fill_account_reputation, - fill_promoted); + fill_promoted, + social_network::fill_comment_content); } ~impl() {} From b3eac2fc6b2bafa3433644ae4c582524dbaeb8c4 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 25 Jul 2018 23:35:27 +0700 Subject: [PATCH 148/250] Optimize get_metadata. #806 --- libraries/api/discussion_helper.cpp | 38 +-------------- .../include/golos/api/discussion_helper.hpp | 2 - .../plugins/social_network/social_network.hpp | 1 + plugins/social_network/social_network.cpp | 11 +++++ plugins/tags/discussion_query.cpp | 3 +- .../golos/plugins/tags/tag_visitor.hpp | 6 +-- .../golos/plugins/tags/tags_object.hpp | 2 - plugins/tags/plugin.cpp | 4 +- plugins/tags/tag_visitor.cpp | 47 +++++++++++++++++-- 9 files changed, 63 insertions(+), 51 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index f78776bcfd..747b5d2cb2 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -8,43 +8,7 @@ namespace golos { namespace api { - comment_metadata get_metadata(const comment_api_object& c) { - - comment_metadata meta; - - if (!c.json_metadata.empty()) { - try { - meta = fc::json::from_string(c.json_metadata).as(); - } catch (const fc::exception& e) { - // Do nothing on malformed json_metadata - } - } - - std::set lower_tags; - - std::size_t tag_limit = 5; - for (const auto& name : meta.tags) { - if (lower_tags.size() > tag_limit) { - break; - } - auto value = boost::trim_copy(name); - if (value.empty()) { - continue; - } - boost::to_lower(value); - lower_tags.insert(value); - } - - meta.tags.swap(lower_tags); - - boost::trim(meta.language); - boost::to_lower(meta.language); - - return meta; - } - - - boost::multiprecision::uint256_t to256(const fc::uint128_t& t) { + boost::multiprecision::uint256_t to256(const fc::uint128_t& t) { boost::multiprecision::uint256_t result(t.high_bits()); result <<= 65; result += t.low_bits(); diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 7c5074a3c9..2035d46559 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -10,8 +10,6 @@ namespace golos { namespace api { std::string language; }; - comment_metadata get_metadata(const comment_api_object& c); - class discussion_helper { public: discussion_helper() = delete; diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 7c97e25902..3dbe56c60e 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -68,5 +68,6 @@ namespace golos { namespace plugins { namespace social_network { // Callback which is needed for correct work of discussion_helper void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); + std::string get_json_metadata(const golos::chain::database& db, const comment_object&); } } } // golos::plugins::social_network diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 173597d9f9..4b0291533a 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -626,4 +626,15 @@ namespace golos { namespace plugins { namespace social_network { } } + std::string get_json_metadata(const golos::chain::database& db, const comment_object& c) { + if (!db.has_index()) { + return std::string(); + } + const auto content = db.find(c.id); + if (content != nullptr) { + return to_string(content->json_metadata); + } + return std::string(); + } + } } } // golos::plugins::social_network diff --git a/plugins/tags/discussion_query.cpp b/plugins/tags/discussion_query.cpp index 6bdc4452d3..76fd186e0c 100644 --- a/plugins/tags/discussion_query.cpp +++ b/plugins/tags/discussion_query.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace golos { namespace plugins { namespace tags { @@ -39,7 +40,7 @@ namespace golos { namespace plugins { namespace tags { return true; } - auto meta = tags::get_metadata(d); + auto meta = get_metadata(d.json_metadata); if ((has_language_selector() && !select_languages.count(meta.language)) || (has_language_filter() && filter_languages.count(meta.language)) ) { diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 2ed59778d4..56b2fa2cef 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -4,18 +4,18 @@ #include #include #include -#include namespace golos { namespace plugins { namespace tags { using golos::api::discussion_helper; + comment_metadata get_metadata(const std::string& json_metadata); + struct operation_visitor { - operation_visitor(database& db, const discussion_helper& helper); + operation_visitor(database& db); using result_type = void; database& db_; - const discussion_helper& helper_; void remove_stats(const tag_object& tag) const; diff --git a/plugins/tags/include/golos/plugins/tags/tags_object.hpp b/plugins/tags/include/golos/plugins/tags/tags_object.hpp index 61d233b375..14cd89d537 100644 --- a/plugins/tags/include/golos/plugins/tags/tags_object.hpp +++ b/plugins/tags/include/golos/plugins/tags/tags_object.hpp @@ -17,8 +17,6 @@ namespace golos { namespace plugins { namespace tags { using golos::api::comment_object; using golos::api::comment_api_object; - using golos::api::get_metadata; - using namespace golos::chain; using namespace boost::multi_index; using chainbase::object; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 7871311c52..e9685f1e3b 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -46,7 +46,7 @@ namespace golos { namespace plugins { namespace tags { void on_operation(const operation_notification& note) { try { /// plugins shouldn't ever throw - note.op.visit(tags::operation_visitor(database(), *helper)); + note.op.visit(tags::operation_visitor(database_)); } catch (const fc::exception& e) { edump((e.to_detail_string())); } catch (...) { @@ -291,7 +291,7 @@ namespace golos { namespace plugins { namespace tags { query.start_comment = create_discussion(*comment, query); auto& d = query.start_comment; - operation_visitor v(database_, *helper); + operation_visitor v(database_); d.hot = v.calculate_hot(d.net_rshares, d.created); d.trending = v.calculate_trending(d.net_rshares, d.created); diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index a8a0c49f4e..eea10c99b6 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -1,10 +1,49 @@ #include #include +#include namespace golos { namespace plugins { namespace tags { - operation_visitor::operation_visitor(database& db, const discussion_helper& helper) - : db_(db), helper_(helper) { + comment_metadata get_metadata(const std::string& json_metadata) { + comment_metadata meta; + + if (!json_metadata.empty()) { + try { + meta = fc::json::from_string(json_metadata).as(); + } catch (const fc::exception& e) { + // Do nothing on malformed json_metadata + } + } + + std::set lower_tags; + + std::size_t tag_limit = 5; + for (const auto& name : meta.tags) { + if (lower_tags.size() > tag_limit) { + break; + } + auto value = boost::trim_copy(name); + if (value.empty()) { + continue; + } + boost::to_lower(value); + lower_tags.insert(value); + } + + meta.tags.swap(lower_tags); + + boost::trim(meta.language); + boost::to_lower(meta.language); + + return meta; + } + + comment_metadata get_metadata(const golos::chain::database& db, const comment_object& c) { + return get_metadata(golos::plugins::social_network::get_json_metadata(db, c)); + } + + operation_visitor::operation_visitor(database& db) + : db_(db) { } void operation_visitor::remove_stats(const tag_object& tag) const { @@ -174,7 +213,7 @@ namespace golos { namespace plugins { namespace tags { auto trending = calculate_trending(comment.net_rshares, comment.created); const auto& comment_idx = db_.get_index().indices().get(); - auto meta = get_metadata(helper_.create_comment_api_object(comment)); + auto meta = get_metadata(db_, comment); auto citr = comment_idx.lower_bound(comment.id); const tag_object* language_tag = nullptr; @@ -307,7 +346,7 @@ namespace golos { namespace plugins { namespace tags { const auto& comment = db_.get_comment(op.author, op.permlink); const auto& author = db_.get_account(op.author).id; - auto meta = get_metadata(helper_.create_comment_api_object(comment)); + auto meta = get_metadata(db_, comment); const auto& stats_idx = db_.get_index().indices().get(); const auto& auth_idx = db_.get_index().indices().get(); From 445d7dbe123190a7456cdc82adf49114d088de3f Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 07:26:08 +0700 Subject: [PATCH 149/250] Refactor errros: fixed PLUGIN_API_VALIDATE_ARGS to throw valid exceptions when invalid parameter #791 --- .../include/golos/protocol/exceptions.hpp | 20 ++++ .../golos/plugins/debug_node/api_helper.hpp | 3 + .../golos/plugins/json_rpc/api_helper.hpp | 106 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 9e3c593f06..4c40a5e81c 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -55,6 +55,9 @@ #define GOLOS_CHECK_LOGIC(expr, TYPE, MSG, ...) \ GOLOS_ASSERT(expr, golos::logic_exception, MSG, ("errid", TYPE)__VA_ARGS__) + +// TODO Remove after done refactor errors in plugins #791 +// This macros is obsolete and replaced with PLUGIN_API_VALIDATE_ARGS #define GOLOS_DECLARE_PARAM(PARAM, GETTER) auto (PARAM) = [&]() {\ try {return (GETTER);} \ catch (const fc::exception &e) { \ @@ -67,6 +70,20 @@ } \ }() +#define GOLOS_CONVERT_PARAM(PARAM, VALUE, TYPE) \ + [&](){ \ + try { \ + return (VALUE).as(); \ + } catch (const fc::exception& e) { \ + FC_THROW_EXCEPTION(invalid_parameter, "Invalid value \"${value}\" for parameter \"${param}\": ${errmsg}", \ + ("param", FC_STRINGIZE(PARAM)) \ + ("value", VALUE) \ + ("errmsg", e.to_string()) \ + ("error", e)); \ + } \ + return TYPE(); /* make compiler happy */\ + }() + #define GOLOS_CHECK_PARAM(PARAM, VALIDATOR) GOLOS_CHECK_PARAM_I(PARAM, PARAM, VALIDATOR, "") #define GOLOS_CHECK_OP_PARAM(OP, PARAM, VALIDATOR) GOLOS_CHECK_PARAM_I(PARAM, OP.PARAM, VALIDATOR, "operation ") @@ -90,6 +107,9 @@ GOLOS_ASSERT( limit <= max_value, golos::limit_too_large, "Exceeded limit value. Maximum allowed ${max}", \ ("limit",limit)("max",max_value)) +#define GOLOS_CHECK_LIMIT_PARAM(limit, max_value) \ + GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, max_value)) + #define GOLOS_CHECK_ARGS_COUNT(args, required) \ GOLOS_ASSERT( (args)->size() == (required), invalid_arguments_count, \ "Expected ${required} argument(s), was ${count}", \ diff --git a/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp b/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp index b2041a7de2..358b4ab046 100644 --- a/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp +++ b/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp @@ -1,5 +1,8 @@ #pragma once +// TODO Remove after done refactor erros in plugins #791 +// This functional moved to plugins/jon_api/include/golos/plugins/json_api/api_helper.hpp + // Provides PLUGIN_API_VALIDATE_ARGS macro usable in DEFINE_API methods // to generate arguments processing boilerplate. diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp new file mode 100644 index 0000000000..b784163665 --- /dev/null +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp @@ -0,0 +1,106 @@ +#pragma once + +// Provides PLUGIN_API_VALIDATE_ARGS macro usable in DEFINE_API methods +// to generate arguments processing boilerplate. + +//Usage: +// PLUGIN_API_VALIDATE_ARGS( +// (std::string, json_filename) +// ) +//Expands to: +// std::string json_filename; +// auto n_args = args.args->size(); +// GOLOS_ASSERT(n_args == 1, golos::invalid_parameter, "Expected 1 parameter, received ${n}", ("n", n_args)("required",1)); +// json_filename = GOLOS_CONVERT_PARAM(json_filename,args.args->at(0),std::string); +// +//And this: +// PLUGIN_API_VALIDATE_ARGS( +// (std::string, json_filename) +// (uint32_t, count) +// (uint32_t, skip_flags, golos::chain::database::skip_nothing) +// ) +//Expands to: +// std::string json_filename; +// uint32_t count; +// uint32_t skip_flags = golos::chain::database::skip_nothing; +// auto n_args = args.args->size(); +// GOLOS_ASSERT(n_args >= 2 && n_args <= 3, golos::invalid_parameter, "Expected at least 2 and up to 3 parameters, received ${n}", ("n", n_args)("min",2)("max",3)); +// json_filename = GOLOS_CONVERT_PARAM(json_filename,args.args->at(0),std::string); +// count = GOLOS_CONVERT_PARAM(count,args.args->at(1),uint32_t); +// if (n_args > 2) { +// skip_flags = GOLOS_CONVERT_PARAM(skip_flags,args.args->at(2),uint32_t); +// } + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REMOVE_PARENTHESES(...) __VA_ARGS__ + +// prepare +#define PLUGIN_API_VALIDATE_ARGS(ARGS) PLUGIN_API_VALIDATE_ARGS_I(BOOST_PP_VARIADIC_SEQ_TO_SEQ(ARGS)) +#define PLUGIN_API_VALIDATE_ARGS_I(ARGS) PLUGIN_API_VALIDATE_ARGS_II(ARGS, COUNT_REQUIRED_ARGS(ARGS), BOOST_PP_SEQ_SIZE(ARGS)) + +// main +#define PLUGIN_API_VALIDATE_ARGS_II(ARGS, N_REQ, N_ARGS) \ + PLUGIN_API_DECLARE_ARG_VARS(ARGS) \ + /*FC_ASSERT(args.args.valid(), "Invalid parameters"); *//* is it possible to get invalid?*/ \ + auto n_args = args.args->size(); \ + PLUGIN_API_ARGS_NUM_ASSERT(N_REQ, N_ARGS) \ + PLUGIN_API_LOAD_AND_CHECK_ARGS(ARGS, N_REQ) + +// helper +#define COUNT_REQUIRED_ARGS(args) COUNT_REQUIRED_ARGS_I(args, BOOST_PP_SEQ_SIZE(args)) +#define COUNT_REQUIRED_ARGS_I(args, sz) BOOST_PP_SEQ_ELEM(2, BOOST_PP_WHILE(COUNT_PR, COUNT_OP, (args(end))(sz)(0))) +#define STATE_OP(op, state) op(BOOST_PP_SEQ_ELEM(0, state), BOOST_PP_SEQ_ELEM(1, state), BOOST_PP_SEQ_ELEM(2, state)) +#define COUNT_OP(d, state) STATE_OP(COUNT_OP_I, state) +#define COUNT_PR(d, state) STATE_OP(COUNT_PR_I, state) +#define COUNT_OP_I(args, sz, i) (args)(sz)(BOOST_PP_INC(i)) +#define COUNT_PR_I(args, sz, i) BOOST_PP_AND(HAVE_NEXT_ARG(sz, i), GOT_REQUIRED(args, i)) +#define HAVE_NEXT_ARG(sz, i) BOOST_PP_LESS(i, sz) +#define GOT_REQUIRED(args, i) BOOST_PP_LESS(ARG_SIZE(BOOST_PP_SEQ_ELEM(i, args)), 3) +#define ARG_SIZE(arg) BOOST_PP_VARIADIC_SIZE(REMOVE_PARENTHESES arg) + +// steps: +#define PLUGIN_API_DECLARE_ARG_VARS(ARGS) BOOST_PP_SEQ_FOR_EACH(PLUGIN_API_DECLARE_ARG_VAR, _, ARGS) +#define PLUGIN_API_DECLARE_ARG_VAR(r, data, arg) \ + ARG_TYPE(arg) ARG_NAME(arg) ARG_OPT_VALUE(arg); + +#define ARG_ELEM(arg, n) BOOST_PP_VARIADIC_ELEM(n, REMOVE_PARENTHESES arg, nop) +#define ARG_TYPE(arg) ARG_ELEM(arg, 0) +#define ARG_NAME(arg) ARG_ELEM(arg, 1) +#define ARG_VALUE(arg) ARG_ELEM(arg, 2) +#define ARG_HAVE_VALUE(arg) BOOST_PP_GREATER(ARG_SIZE(arg), 2) +#define ARG_OPT_VALUE(arg) BOOST_PP_IF(ARG_HAVE_VALUE(arg), = ARG_VALUE(arg), BOOST_PP_EMPTY()) + +#define PLUGIN_API_ARGS_NUM_ASSERT(req, all) PLUGIN_API_ARGS_NUM_ASSERT_I(BOOST_PP_LESS(req, all), req, all) +#define PLUGIN_API_ARGS_NUM_ASSERT_I(less, req, all) \ + PLUGIN_API_ARGS_NUM_ASSERT_II(AN_ASSERT_COND(less, req, all), AN_ASSERT_MSG(less, req, all), AN_ASSERT_VARS(less, req, all)) +#define PLUGIN_API_ARGS_NUM_ASSERT_II(cond, msg, vars) \ + GOLOS_ASSERT(cond, golos::invalid_arguments_count, msg, ("n", n_args) vars); + +#define AN_ASSERT_COND(less, req, all) BOOST_PP_IF(less, n_args >= req && n_args <= all, n_args == all) +#define AN_ASSERT_MSG(LESS, REQ, ALL) \ + "Expected " BOOST_PP_STRINGIZE( BOOST_PP_IF(LESS, at least REQ and up to ALL, REQ) ) \ + " parameter" PLURAL_FINAL(ALL) ", received ${n}" +#define AN_ASSERT_VARS(less, req, all) BOOST_PP_IF(less, ("min",req)("max",all), ("required",all)) +#define PLURAL_FINAL(n) BOOST_PP_IF(BOOST_PP_LESS(n, 2), "", "s") + +#define PLUGIN_API_LOAD_AND_CHECK_ARGS(ARGS, n_req) BOOST_PP_SEQ_FOR_EACH_I(LOAD_AND_CHECK_ARG, n_req, ARGS) +#define LOAD_AND_CHECK_ARG(r, n_req, i, arg) LOAD_AND_CHECK_ARG_I(arg, i, BOOST_PP_LESS(i, n_req)) +#define LOAD_AND_CHECK_ARG_I(arg, i, req) BOOST_PP_IF(req, LOAD_ARG, LOAD_OPTIONAL_ARG)(arg, i) +#define LOAD_ARG(arg, i) ARG_NAME(arg) = GOLOS_CONVERT_PARAM(ARG_NAME(arg), args.args->at(i), ARG_TYPE(arg)); +#define LOAD_OPTIONAL_ARG(arg, i) \ + if (n_args > i) { \ + LOAD_ARG(arg, i) \ + } From 58e6527ecf2b6448eb156246f90c80416e152a6f Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 13:21:09 +0700 Subject: [PATCH 150/250] Refactor errors: follow plugin #791 --- plugins/follow/follow_evaluators.cpp | 15 +- plugins/follow/follow_operations.cpp | 10 +- .../include/golos/plugins/follow/plugin.hpp | 21 ++ plugins/follow/plugin.cpp | 102 +++++---- tests/CMakeLists.txt | 3 +- tests/common/database_fixture.cpp | 22 ++ tests/common/database_fixture.hpp | 14 +- tests/common/helpers.hpp | 3 +- tests/plugin_tests/follow.cpp | 202 ++++++++++++++++++ tests/tests/operation_tests.cpp | 21 -- 10 files changed, 334 insertions(+), 79 deletions(-) create mode 100644 tests/plugin_tests/follow.cpp diff --git a/plugins/follow/follow_evaluators.cpp b/plugins/follow/follow_evaluators.cpp index ab2ca8f538..d49a429ae1 100644 --- a/plugins/follow/follow_evaluators.cpp +++ b/plugins/follow/follow_evaluators.cpp @@ -41,8 +41,9 @@ namespace golos { } if (what & (1 << ignore)) - FC_ASSERT(!(what & (1 - << blog)), "Cannot follow blog and ignore author at the same time"); + PLUGIN_CHECK_LOGIC(!(what & (1 << blog)), + logic_errors::cannot_follow_and_ignore_simultaneously, + "Cannot follow blog and ignore author at the same time"); bool was_followed = false; @@ -108,7 +109,9 @@ namespace golos { void reblog_evaluator::do_apply(const reblog_operation &o) { try { const auto &c = db().get_comment(o.author, o.permlink); - FC_ASSERT(c.parent_author.size() == 0, "Only top level posts can be reblogged"); + PLUGIN_CHECK_LOGIC(c.parent_author.size() == 0, + logic_errors::only_top_level_posts_reblogged, + "Only top level posts can be reblogged"); const auto &blog_idx = db().get_index().indices().get(); const auto &blog_comment_idx = db().get_index().indices().get(); @@ -122,7 +125,9 @@ namespace golos { auto blog_itr = blog_comment_idx.find(boost::make_tuple(c.id, o.account)); - FC_ASSERT(blog_itr == blog_comment_idx.end(), "Account has already reblogged this post"); + PLUGIN_CHECK_LOGIC(blog_itr == blog_comment_idx.end(), + logic_errors::account_already_reblogged_this_post, + "Account has already reblogged this post"); db().create([&](blog_object &b) { b.account = o.account; b.comment = c.id; @@ -195,4 +200,4 @@ namespace golos { } } -} // golos::follow \ No newline at end of file +} // golos::follow diff --git a/plugins/follow/follow_operations.cpp b/plugins/follow/follow_operations.cpp index 5eed0eb923..31e5251a66 100644 --- a/plugins/follow/follow_operations.cpp +++ b/plugins/follow/follow_operations.cpp @@ -6,15 +6,19 @@ namespace golos { namespace follow { void follow_operation::validate() const { - FC_ASSERT(follower != following, "You cannot follow yourself"); + PLUGIN_CHECK_LOGIC(follower != following, + logic_errors::cannot_follow_yourself, + "You cannot follow yourself"); } void reblog_operation::validate() const { - FC_ASSERT(account != author, "You cannot reblog your own content"); + PLUGIN_CHECK_LOGIC(account != author, + logic_errors::cannot_reblog_own_content, + "You cannot reblog your own content"); } } } } //golos::follow -DEFINE_OPERATION_TYPE(golos::plugins::follow::follow_plugin_operation) \ No newline at end of file +DEFINE_OPERATION_TYPE(golos::plugins::follow::follow_plugin_operation) diff --git a/plugins/follow/include/golos/plugins/follow/plugin.hpp b/plugins/follow/include/golos/plugins/follow/plugin.hpp index 736b536fdf..87c95df365 100644 --- a/plugins/follow/include/golos/plugins/follow/plugin.hpp +++ b/plugins/follow/include/golos/plugins/follow/plugin.hpp @@ -6,9 +6,22 @@ #include #include "follow_api_object.hpp" +#define PLUGIN_CHECK_LOGIC(expr, type, msg, ...) \ + GOLOS_CHECK_LOGIC(expr, type, msg, ("plugin", "follow") __VA_ARGS__) + namespace golos { namespace plugins { namespace follow { using json_rpc::msg_pack; + struct logic_errors { + enum error_type { + cannot_follow_yourself, + cannot_reblog_own_content, + cannot_follow_and_ignore_simultaneously, + only_top_level_posts_reblogged, + account_already_reblogged_this_post, + }; + }; + void fill_account_reputation( const golos::chain::database& db, const account_name_type& account, @@ -79,3 +92,11 @@ namespace golos { namespace plugins { namespace follow { }; } } } // golos::plugins::follow + +FC_REFLECT_ENUM(golos::plugins::follow::logic_errors::error_type, + (cannot_follow_yourself) + (cannot_reblog_own_content) + (cannot_follow_and_ignore_simultaneously) + (only_top_level_posts_reblogged) + (account_already_reblogged_this_post) +); diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index db48f75411..ae840bb4d7 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,11 +10,10 @@ #include #include #include +#include #include #include -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); namespace golos { namespace plugins { @@ -447,7 +447,7 @@ namespace golos { follow_type type, uint32_t limit) { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); std::vector result; result.reserve(limit); @@ -473,7 +473,8 @@ namespace golos { account_name_type start, follow_type type, uint32_t limit) { - FC_ASSERT(limit <= 100); + + GOLOS_CHECK_LIMIT_PARAM(limit, 100); std::vector result; const auto &idx = database().get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(account, start)); @@ -509,7 +510,7 @@ namespace golos { account_name_type account, uint32_t entry_id, uint32_t limit) { - FC_ASSERT(limit <= 500, "Cannot retrieve more than 500 feed entries at a time."); + GOLOS_CHECK_LIMIT_PARAM(limit, 500); if (entry_id == 0) { entry_id = ~0; @@ -548,7 +549,7 @@ namespace golos { account_name_type account, uint32_t entry_id, uint32_t limit) { - FC_ASSERT(limit <= 500, "Cannot retrieve more than 500 feed entries at a time."); + GOLOS_CHECK_LIMIT_PARAM(limit, 500); if (entry_id == 0) { entry_id = ~0; @@ -586,7 +587,7 @@ namespace golos { account_name_type account, uint32_t entry_id, uint32_t limit) { - FC_ASSERT(limit <= 500, "Cannot retrieve more than 500 blog entries at a time."); + GOLOS_CHECK_LIMIT_PARAM(limit, 500); if (entry_id == 0) { entry_id = ~0; @@ -620,7 +621,7 @@ namespace golos { account_name_type account, uint32_t entry_id, uint32_t limit) { - FC_ASSERT(limit <= 500, "Cannot retrieve more than 500 blog entries at a time."); + GOLOS_CHECK_LIMIT_PARAM(limit, 500); if (entry_id == 0) { entry_id = ~0; @@ -653,7 +654,8 @@ namespace golos { std::vector < account_name_type > accounts ) { - FC_ASSERT(accounts.size() <= 100, "Cannot retrieve more than 100 account reputations at a time."); + GOLOS_CHECK_PARAM(accounts, + GOLOS_CHECK_VALUE(accounts.size() <= 100, "Cannot retrieve more than 100 account reputations at a time.")); const auto &idx = database().get_index().indices().get(); @@ -710,95 +712,107 @@ namespace golos { } DEFINE_API(plugin, get_followers) { - CHECK_ARG_SIZE(4) - auto following = args.args->at(0).as(); - auto start_follower = args.args->at(1).as(); - auto type = args.args->at(2).as(); - auto limit = args.args->at(3).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, following) + (account_name_type, start_follower) + (follow_type, type) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_followers(following, start_follower, type, limit); }); } DEFINE_API(plugin, get_following) { - CHECK_ARG_SIZE(4) - auto follower = args.args->at(0).as(); - auto start_following = args.args->at(1).as(); - auto type = args.args->at(2).as(); - auto limit = args.args->at(3).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, follower) + (account_name_type, start_following) + (follow_type, type) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_following(follower, start_following, type, limit); }); } DEFINE_API(plugin, get_follow_count) { - auto tmp = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + ) return pimpl->database().with_weak_read_lock([&]() { - return pimpl->get_follow_count(tmp); + return pimpl->get_follow_count(account); }); } DEFINE_API(plugin, get_feed_entries){ - CHECK_ARG_SIZE(3) - auto account = args.args->at(0).as(); - auto entry_id = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + (uint32_t, entry_id) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_feed_entries(account, entry_id, limit); }); } DEFINE_API(plugin, get_feed) { - CHECK_ARG_SIZE(3) - auto account = args.args->at(0).as(); - auto entry_id = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + (uint32_t, entry_id) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_feed(account, entry_id, limit); }); } DEFINE_API(plugin, get_blog_entries) { - CHECK_ARG_SIZE(3) - auto account = args.args->at(0).as(); - auto entry_id = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + (uint32_t, entry_id) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_blog_entries(account, entry_id, limit); }); } DEFINE_API(plugin, get_blog) { - CHECK_ARG_SIZE(3) - auto account = args.args->at(0).as(); - auto entry_id = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + (uint32_t, entry_id) + (uint32_t, limit) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_blog(account, entry_id, limit); }); } DEFINE_API(plugin, get_account_reputations) { - CHECK_ARG_SIZE(1) - auto accounts = args.args->at(0).as< std::vector < account_name_type > >(); + PLUGIN_API_VALIDATE_ARGS( + (std::vector, accounts) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_account_reputations( accounts ); }); } DEFINE_API(plugin, get_reblogged_by) { - CHECK_ARG_SIZE(2) - auto author = args.args->at(0).as(); - auto permlink = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, author) + (std::string, permlink) + ) return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_reblogged_by(author, permlink); }); } DEFINE_API(plugin, get_blog_authors) { - auto tmp = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + ) return pimpl->database().with_weak_read_lock([&]() { - return pimpl->get_blog_authors(tmp); + return pimpl->get_blog_authors(account); }); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d49c86eccd..2c18996706 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,7 +36,8 @@ file(GLOB PLUGIN_TESTS "plugin_tests/plugin_ops.cpp" "plugin_tests/json_rpc.cpp" "plugin_tests/operation_history.cpp" - "plugin_tests/account_history.cpp") + "plugin_tests/account_history.cpp" + "plugin_tests/follow.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 90e9049894..40360c4ce5 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -133,6 +133,28 @@ namespace golos { namespace chain { using golos::plugins::json_rpc::msg_pack; + fc::variant_object make_comment_id(const std::string& author, const std::string& permlink) { + auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); + return fc::variant_object(res); + } + + fc::variant_object make_limit_order_id(const std::string& author, uint32_t orderid) { + auto res = fc::mutable_variant_object()("account",author)("order_id",orderid); + return fc::variant_object(res); + } + + fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid) { + auto res = fc::mutable_variant_object()("account",account)("request_id",requestid); + return fc::variant_object(res); + } + + fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id) { + auto res = fc::mutable_variant_object()("account",name)("escrow",escrow_id); + return fc::variant_object(res); + } + + + database_fixture::~database_fixture() { if (db_plugin) { // clear all debug updates diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index f5bed19ee5..b8ea8f070a 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -207,11 +207,10 @@ struct ErrorValidator { template<> struct ErrorValidator { - void validate(const std::string& name, const fc::variant& props, - golos::logic_exception::error_types err) { + template + void validate(const std::string& name, const fc::variant& props, errors err) { BOOST_CHECK_EQUAL(name, "logic_exception"); - BOOST_CHECK_EQUAL(props["errid"].get_string(), - fc::reflector::to_string(err)); + BOOST_CHECK_EQUAL(props["errid"].get_string(), fc::reflector::to_string(err)); } }; @@ -421,6 +420,12 @@ namespace golos { namespace chain { using namespace golos::protocol; + fc::variant_object make_comment_id(const std::string& author, const std::string& permlink); + fc::variant_object make_limit_order_id(const std::string& author, uint32_t orderid); + fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid); + fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id); + + namespace { template struct PluginRegistrator; @@ -439,6 +444,7 @@ namespace golos { namespace chain { }; } // anonymous namespace + struct database_fixture { // the reason we use an app is to exercise the indexes of built-in plugins chain::database* db; diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index fbf85f671d..46bf9cce47 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -29,7 +29,8 @@ // Check operation authorities #define CHECK_OP_AUTHS(OP, OWNER, ACTIVE, POSTING) { \ - account_name_set owner_auths, active_auths, posting_auths; \ + boost::container::flat_set \ + owner_auths, active_auths, posting_auths; \ OP.get_required_owner_authorities(owner_auths); \ BOOST_CHECK_EQUAL(owner_auths, OWNER); \ OP.get_required_active_authorities(active_auths); \ diff --git a/tests/plugin_tests/follow.cpp b/tests/plugin_tests/follow.cpp new file mode 100644 index 0000000000..9c051e14ab --- /dev/null +++ b/tests/plugin_tests/follow.cpp @@ -0,0 +1,202 @@ +#include + +#include + +#include "database_fixture.hpp" +#include "helpers.hpp" + +#include + +#include +#include + +using boost::container::flat_set; + +using golos::plugins::json_rpc::msg_pack; + +using golos::logic_exception; +using golos::missing_object; +using golos::protocol::comment_operation; +using golos::protocol::tx_invalid_operation; +using golos::protocol::public_key_type; +using golos::protocol::signed_transaction; +using golos::protocol::custom_binary_operation; +using golos::chain::account_id_type; +using golos::chain::make_comment_id; + +using namespace golos::plugins::follow; + +using account_name_set = flat_set; + + +struct follow_fixture : public golos::chain::database_fixture { + follow_fixture() : golos::chain::database_fixture() { + initialize(); + open_database(); + startup(); + } +}; + + +BOOST_FIXTURE_TEST_SUITE(follow_plugin, follow_fixture) + +BOOST_AUTO_TEST_CASE(follow_validate) { + BOOST_TEST_MESSAGE("Testing: follow_validate"); + + ACTORS((alice)(bob)); + + follow_operation op; + op.follower = "alice"; + op.following = "bob"; + op.what = {"blog"}; + CHECK_OP_VALID(op); + + CHECK_PARAM_VALIDATION_FAIL(op, following, "alice", + CHECK_ERROR(logic_exception, logic_errors::cannot_follow_yourself)); +} + +BOOST_AUTO_TEST_CASE(follow_authorities) { + BOOST_TEST_MESSAGE("Testing: follow_authorities"); + + follow_operation op; + op.follower = "alice"; + op.following = "bob"; + op.what = {"blog"}; + + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set({"alice"})); +} + +BOOST_AUTO_TEST_CASE(follow_apply) { + BOOST_TEST_MESSAGE("Testing: follow_apply"); + + ACTORS((alice)(bob)); + + generate_blocks(60 / STEEMIT_BLOCK_INTERVAL); + + custom_binary_operation cop; + cop.required_posting_auths.insert("alice"); + cop.id = "follow"; + + boost::container::vector vec; + signed_transaction tx; + + BOOST_TEST_MESSAGE("--- success execution"); + follow_operation op; + op.follower = "alice"; + op.following = "bob"; + op.what = {"blog"}; + + vec.push_back(op); + cop.data = fc::raw::pack(vec); + + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, cop)); + + BOOST_TEST_MESSAGE("--- failed when 'blog' & 'ignore' at the same time"); + op.what = {"blog", "ignore"}; + + vec.clear(); + vec.push_back(op); + cop.data = fc::raw::pack(vec); + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, cop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::cannot_follow_and_ignore_simultaneously))); +} + +BOOST_AUTO_TEST_CASE(reblog_validate) { + BOOST_TEST_MESSAGE("Testing: reblog_validate"); + + reblog_operation op; + op.account = "alice"; + op.author = "bob"; + op.permlink = "foo"; + + CHECK_OP_VALID(op); + + CHECK_PARAM_VALIDATION_FAIL(op, author, "alice", + CHECK_ERROR(logic_exception, logic_errors::cannot_reblog_own_content)); +} + +BOOST_AUTO_TEST_CASE(reblog_authorities) { + BOOST_TEST_MESSAGE("Testing: reblog_authorities"); + + reblog_operation op; + op.account = "alice"; + op.author = "bob"; + op.permlink = "foo"; + + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set({"alice"})); +} + +BOOST_AUTO_TEST_CASE(reblog_apply) { + BOOST_TEST_MESSAGE("Testing: reblog_apply"); + + ACTORS((alice)(bob)); + + generate_blocks(60 / STEEMIT_BLOCK_INTERVAL); + signed_transaction tx; + + { + comment_operation op; + op.author = "bob"; + op.permlink = "lorem"; + op.parent_author = ""; + op.parent_permlink = "ipsum"; + op.title = "Lorem Ipsum"; + op.body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + op.json_metadata = "{\"foo\":\"bar\"}"; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, op)); + + op.author = "alice"; + op.permlink = "foo"; + op.parent_author = "bob"; + op.parent_permlink = "lorem"; + op.title = "Lorem Ipsum"; + op.body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + } + + custom_binary_operation cop; + cop.required_posting_auths.insert("alice"); + cop.id = "follow"; + + boost::container::vector vec; + + BOOST_TEST_MESSAGE("--- success execution"); + reblog_operation op; + op.account = "alice"; + op.author = "bob"; + op.permlink = "lorem"; + + vec.clear(); + vec.push_back(op); + cop.data = fc::raw::pack(vec); + BOOST_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, cop)); + + BOOST_TEST_MESSAGE("--- failed when comment is missing"); + op.permlink = "david"; + + vec.clear(); + vec.push_back(op); + cop.data = fc::raw::pack(vec); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, alice_private_key, cop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "comment", make_comment_id("bob", "david")))); + + BOOST_TEST_MESSAGE("--- failed when reblog comment"); + op.account = "bob"; + op.author = "alice"; + op.permlink = "foo"; + + vec.clear(); + vec.push_back(op); + cop.data = fc::raw::pack(vec); + cop.required_posting_auths.clear(); + cop.required_posting_auths.insert("bob"); + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(tx, bob_private_key, cop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::only_top_level_posts_reblogged))); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index a6c968a082..833527de7c 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -34,27 +34,6 @@ using account_name_set = flat_set; #define BAD_UTF8_STRING "\xc3\x28" -fc::variant_object make_comment_id(const std::string& author, const std::string& permlink) { - auto res = fc::mutable_variant_object()("account",author)("permlink",permlink); - return fc::variant_object(res); -} - -fc::variant_object make_limit_order_id(const std::string& author, uint32_t orderid) { - auto res = fc::mutable_variant_object()("account",author)("order_id",orderid); - return fc::variant_object(res); -} - -fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid) { - auto res = fc::mutable_variant_object()("account",account)("request_id",requestid); - return fc::variant_object(res); -} - -fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id) { - auto res = fc::mutable_variant_object()("account",name)("escrow",escrow_id); - return fc::variant_object(res); -} - - BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_AUTO_TEST_CASE(account_create_validate) { From 2860dd0f9996bc7e8089ff4df708a76224813235 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 13:55:04 +0700 Subject: [PATCH 151/250] Refactor errors: fixed PLUGIN_API_VALIDATE_ARGS (review fixes) #791 --- .../json_rpc/include/golos/plugins/json_rpc/api_helper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp b/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp index b784163665..e9e275226b 100644 --- a/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp +++ b/plugins/json_rpc/include/golos/plugins/json_rpc/api_helper.hpp @@ -10,7 +10,7 @@ //Expands to: // std::string json_filename; // auto n_args = args.args->size(); -// GOLOS_ASSERT(n_args == 1, golos::invalid_parameter, "Expected 1 parameter, received ${n}", ("n", n_args)("required",1)); +// GOLOS_ASSERT(n_args == 1, golos::invalid_arguments_count, "Expected 1 parameter, received ${n}", ("n", n_args)("required",1)); // json_filename = GOLOS_CONVERT_PARAM(json_filename,args.args->at(0),std::string); // //And this: @@ -24,7 +24,7 @@ // uint32_t count; // uint32_t skip_flags = golos::chain::database::skip_nothing; // auto n_args = args.args->size(); -// GOLOS_ASSERT(n_args >= 2 && n_args <= 3, golos::invalid_parameter, "Expected at least 2 and up to 3 parameters, received ${n}", ("n", n_args)("min",2)("max",3)); +// GOLOS_ASSERT(n_args >= 2 && n_args <= 3, golos::invalid_arguments_count, "Expected at least 2 and up to 3 parameters, received ${n}", ("n", n_args)("min",2)("max",3)); // json_filename = GOLOS_CONVERT_PARAM(json_filename,args.args->at(0),std::string); // count = GOLOS_CONVERT_PARAM(count,args.args->at(1),uint32_t); // if (n_args > 2) { From e53f2da95c92bd477d7826b4593e7223a64dc883 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 16:13:19 +0700 Subject: [PATCH 152/250] Refactor errors: follow_plugin (add namespace to GOLOS_CHECK_LOGIC) #791 --- libraries/protocol/include/golos/protocol/exceptions.hpp | 8 +++++++- libraries/protocol/types.cpp | 7 +++++++ plugins/follow/plugin.cpp | 8 ++++++++ tests/common/database_fixture.hpp | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 4c40a5e81c..2e8a414d98 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -53,7 +53,7 @@ }; #define GOLOS_CHECK_LOGIC(expr, TYPE, MSG, ...) \ - GOLOS_ASSERT(expr, golos::logic_exception, MSG, ("errid", TYPE)__VA_ARGS__) + GOLOS_ASSERT(expr, golos::logic_exception, MSG, ("errid", TYPE)("namespace",golos::get_logic_error_namespace())__VA_ARGS__) // TODO Remove after done refactor errors in plugins #791 @@ -136,6 +136,12 @@ FC_THROW_EXCEPTION(golos::internal_error, MSG, __VA_ARGS__) namespace golos { + + + // Function to get logic_error codes namespace + template + std::string get_logic_error_namespace(); + GOLOS_DECLARE_DERIVED_EXCEPTION( golos_exception, fc::exception, 0, "golos base exception") diff --git a/libraries/protocol/types.cpp b/libraries/protocol/types.cpp index 43017f2316..2fbe075bc8 100644 --- a/libraries/protocol/types.cpp +++ b/libraries/protocol/types.cpp @@ -1,9 +1,16 @@ #include #include +#include #include namespace golos { + + template<> + std::string get_logic_error_namespace() { + return ""; + } + namespace protocol { public_key_type::public_key_type() : key_data() { diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index ae840bb4d7..2a55206ce0 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -14,6 +14,14 @@ #include #include +namespace golos { + +template<> +std::string get_logic_error_namespace() { + return golos::plugins::follow::plugin::name(); +} + +} // namespace golos namespace golos { namespace plugins { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index b8ea8f070a..bfdaed82d8 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -211,6 +211,7 @@ struct ErrorValidator { void validate(const std::string& name, const fc::variant& props, errors err) { BOOST_CHECK_EQUAL(name, "logic_exception"); BOOST_CHECK_EQUAL(props["errid"].get_string(), fc::reflector::to_string(err)); + BOOST_CHECK_EQUAL(props["namespace"].get_string(), golos::get_logic_error_namespace()); } }; From ef6ae02cae0d646cfa6b140bff2bf3f3a0994555 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 18:33:00 +0700 Subject: [PATCH 153/250] Refactor errors: follow plugin (review fixes) #791 --- tests/common/database_fixture.hpp | 1 + tests/common/helpers.hpp | 2 +- tests/plugin_tests/account_history.cpp | 6 +++--- tests/plugin_tests/follow.cpp | 4 ++-- tests/tests/operation_tests.cpp | 13 +------------ tests/tests/proposal_tests.cpp | 3 --- 6 files changed, 8 insertions(+), 21 deletions(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index bfdaed82d8..695a3836c1 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -426,6 +426,7 @@ namespace golos { namespace chain { fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid); fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id); + typedef fc::flat_set account_name_set; namespace { template diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index 46bf9cce47..63a7f77964 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -29,7 +29,7 @@ // Check operation authorities #define CHECK_OP_AUTHS(OP, OWNER, ACTIVE, POSTING) { \ - boost::container::flat_set \ + golos::chain::account_name_set \ owner_auths, active_auths, posting_auths; \ OP.get_required_owner_authorities(owner_auths); \ BOOST_CHECK_EQUAL(owner_auths, OWNER); \ diff --git a/tests/plugin_tests/account_history.cpp b/tests/plugin_tests/account_history.cpp index 7c864a4228..5739e1d5f3 100644 --- a/tests/plugin_tests/account_history.cpp +++ b/tests/plugin_tests/account_history.cpp @@ -8,14 +8,14 @@ #include "comment_reward.hpp" +using golos::chain::account_name_set; using golos::plugins::json_rpc::msg_pack; struct account_history_fixture : public golos::chain::add_operations_database_fixture { typedef std::map> checked_accounts_map; ///< pair { [block], [accaunt names] } - typedef fc::flat_set account_names; - checked_accounts_map check(const account_names& names) { + checked_accounts_map check(const account_name_set& names) { uint32_t head_block_num = db->head_block_num(); ilog("Check history accounts, block num is " + std::to_string(head_block_num)); checked_accounts_map _founded_accs; @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(account_history_blocks) { initialize({{"history-blocks", std::to_string(HISTORY_BLOCKS)}}); add_operations(); - account_names names = {"alice", "bob", "sam", "dave"}; + account_name_set names = {"alice", "bob", "sam", "dave"}; auto _founded_accs = check(names); std::set blocks; diff --git a/tests/plugin_tests/follow.cpp b/tests/plugin_tests/follow.cpp index 9c051e14ab..3d6683da5e 100644 --- a/tests/plugin_tests/follow.cpp +++ b/tests/plugin_tests/follow.cpp @@ -24,9 +24,9 @@ using golos::protocol::custom_binary_operation; using golos::chain::account_id_type; using golos::chain::make_comment_id; -using namespace golos::plugins::follow; +using golos::chain::account_name_set; -using account_name_set = flat_set; +using namespace golos::plugins::follow; struct follow_fixture : public golos::chain::database_fixture { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 833527de7c..75bcb876ad 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -29,7 +29,6 @@ using namespace golos::protocol; using golos::plugins::social_network::comment_content_object; using std::string; -using account_name_set = flat_set; #define BAD_UTF8_STRING "\xc3\x28" @@ -766,17 +765,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) op.permlink = "test"; op.weight = 1000; - using account_name_set = flat_set; - account_name_set auths; - - op.get_required_owner_authorities(auths); - BOOST_CHECK_EQUAL(auths, account_name_set()); - - op.get_required_active_authorities(auths); - BOOST_CHECK_EQUAL(auths, account_name_set()); - - op.get_required_posting_authorities(auths); - BOOST_CHECK_EQUAL(auths, account_name_set({"bob"})); + CHECK_OP_AUTHS(op, account_name_set(), account_name_set(), account_name_set({"bob"})); validate_database(); } diff --git a/tests/tests/proposal_tests.cpp b/tests/tests/proposal_tests.cpp index 6390c75fcb..ef7f65c773 100644 --- a/tests/tests/proposal_tests.cpp +++ b/tests/tests/proposal_tests.cpp @@ -91,7 +91,6 @@ BOOST_AUTO_TEST_CASE(proposal_create_authorities) { try { proposal_create_operation op; op.author = "bob"; op.title = "test"; - using account_name_set = flat_set; CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); } FC_LOG_AND_RETHROW() } @@ -131,7 +130,6 @@ BOOST_AUTO_TEST_CASE(proposal_update_validate) { try { BOOST_AUTO_TEST_CASE(proposal_update_authorities) { try { BOOST_TEST_MESSAGE("Testing: proposal_update_authorities"); - using account_name_set = flat_set; account_name_set nobody; account_name_set bob_acc = account_name_set({"bob"}); account_name_set cid_acc = account_name_set({"cid"}); @@ -203,7 +201,6 @@ BOOST_AUTO_TEST_CASE(proposal_delete_authorities) { try { op.requester = "bob"; op.author = "alice"; op.title = "test"; - using account_name_set = flat_set; CHECK_OP_AUTHS(op, account_name_set(), account_name_set({"bob"}), account_name_set()); } FC_LOG_AND_RETHROW() } From 879893a3900e6d5bdce04c7293d3ba122ef92817 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 19:02:28 +0700 Subject: [PATCH 154/250] Refactor errors: block_info plugin #791 --- plugins/block_info/plugin.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plugins/block_info/plugin.cpp b/plugins/block_info/plugin.cpp index 52bc5b2ea6..5d2e898652 100644 --- a/plugins/block_info/plugin.cpp +++ b/plugins/block_info/plugin.cpp @@ -3,8 +3,11 @@ #include #include +#include +#include #include #include +#include namespace golos { namespace plugins { @@ -43,8 +46,8 @@ struct plugin::plugin_impl { std::vector plugin::plugin_impl::get_block_info(uint32_t start_block_num, uint32_t count) { std::vector result; - FC_ASSERT(start_block_num > 0); - FC_ASSERT(count <= 10000); + GOLOS_CHECK_PARAM(start_block_num, GOLOS_CHECK_VALUE_GT(start_block_num, 0)); + GOLOS_CHECK_LIMIT_PARAM(count, 10000); uint32_t n = std::min(uint32_t(block_info_.size()), start_block_num + count); @@ -61,8 +64,8 @@ std::vector plugin::plugin_impl::get_blocks_with_info( std::vector result; const auto & db = database(); - FC_ASSERT(start_block_num > 0); - FC_ASSERT(count <= 10000); + GOLOS_CHECK_PARAM(start_block_num, GOLOS_CHECK_VALUE_GT(start_block_num, 0)); + GOLOS_CHECK_LIMIT_PARAM(count, 10000); uint32_t n = std::min( uint32_t( block_info_.size() ), start_block_num + count ); uint64_t total_size = 0; @@ -104,8 +107,10 @@ void plugin::plugin_impl::on_applied_block(const protocol::signed_block &b) { } DEFINE_API ( plugin, get_block_info ) { - auto start_block_num = args.args->at(0).as(); - auto count = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, start_block_num) + (uint32_t, count) + ); auto &db = my->database(); return db.with_weak_read_lock([&]() { return my->get_block_info(start_block_num, count); @@ -113,8 +118,10 @@ DEFINE_API ( plugin, get_block_info ) { } DEFINE_API ( plugin, get_blocks_with_info ) { - auto start_block_num = args.args->at(0).as(); - auto count = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, start_block_num) + (uint32_t, count) + ); auto &db = my->database(); return db.with_weak_read_lock([&]() { return my->get_blocks_with_info(start_block_num, count); From 17a5a13c92d90f99b2e1048f321f14df0ad9de78 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 19:12:53 +0700 Subject: [PATCH 155/250] Refactor errors: follow plugin (review fixes) #791 --- tests/common/database_fixture.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 695a3836c1..250e5a2921 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -426,7 +426,7 @@ namespace golos { namespace chain { fc::variant_object make_convert_request_id(const std::string& account, uint32_t requestid); fc::variant_object make_escrow_id(const string& name, uint32_t escrow_id); - typedef fc::flat_set account_name_set; + using account_name_set = fc::flat_set; namespace { template From 13c9cd078eb1ca9ced375f14144f57398efaaf9a Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 19:56:01 +0700 Subject: [PATCH 156/250] Refactor errors: database_api plugin #791 --- plugins/database_api/api.cpp | 184 +++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 83 deletions(-) diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index 9b4fbb7f74..d84151ec65 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include #include @@ -11,12 +13,6 @@ #include -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); -#define CHECK_ARGS_COUNT(min, max) \ - FC_ASSERT(n_args >= min && n_args <= max, "Expected #min-#max arguments, got ${n}", ("n", n_args)); - - namespace golos { namespace plugins { namespace database_api { @@ -181,9 +177,11 @@ plugin::api_impl::~api_impl() { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, get_block_header) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, block_num) + ); return my->database().with_weak_read_lock([&]() { - return my->get_block_header(args.args->at(0).as()); + return my->get_block_header(block_num); }); } @@ -196,9 +194,11 @@ optional plugin::api_impl::get_block_header(uint32_t block_num) co } DEFINE_API(plugin, get_block) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, block_num) + ); return my->database().with_weak_read_lock([&]() { - return my->get_block(args.args->at(0).as()); + return my->get_block(block_num); }); } @@ -213,14 +213,9 @@ optional plugin::api_impl::get_block(uint32_t block_num) const { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, set_block_applied_callback) { - CHECK_ARG_SIZE(1); - block_applied_callback_result_type type = block; - auto arg = args.args->at(0); - try { - type = arg.as(); - } catch (...) { - ilog("Bad argument (${a}) passed to set_block_applied_callback, using default", ("a",arg)); - } + PLUGIN_API_VALIDATE_ARGS( + (block_applied_callback_result_type, type) + ); // Delegate connection handlers to callback msg_pack_transfer transfer(args); @@ -254,7 +249,6 @@ DEFINE_API(plugin, set_block_applied_callback) { } DEFINE_API(plugin, set_pending_transaction_callback) { - // CHECK_ARG_SIZE(1); // not used // Delegate connection handlers to callback msg_pack_transfer transfer(args); my->database().with_weak_read_lock([&]{ @@ -311,6 +305,7 @@ void plugin::api_impl::op_applied_callback(const operation_notification& o) { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, get_config) { + PLUGIN_API_VALIDATE_ARGS(); return my->database().with_weak_read_lock([&]() { return my->get_config(); }); @@ -321,12 +316,14 @@ fc::variant_object plugin::api_impl::get_config() const { } DEFINE_API(plugin, get_dynamic_global_properties) { + PLUGIN_API_VALIDATE_ARGS(); return my->database().with_weak_read_lock([&]() { return my->get_dynamic_global_properties(); }); } DEFINE_API(plugin, get_chain_properties) { + PLUGIN_API_VALIDATE_ARGS(); return my->database().with_weak_read_lock([&]() { return chain_api_properties(my->database().get_witness_schedule_object().median_props, my->database()); }); @@ -337,12 +334,14 @@ dynamic_global_property_api_object plugin::api_impl::get_dynamic_global_properti } DEFINE_API(plugin, get_hardfork_version) { + PLUGIN_API_VALIDATE_ARGS(); return my->database().with_weak_read_lock([&]() { return my->database().get(hardfork_property_object::id_type()).current_hardfork_version; }); } DEFINE_API(plugin, get_next_scheduled_hardfork) { + PLUGIN_API_VALIDATE_ARGS(); return my->database().with_weak_read_lock([&]() { scheduled_hardfork shf; const auto &hpo = my->database().get(hardfork_property_object::id_type()); @@ -359,9 +358,11 @@ DEFINE_API(plugin, get_next_scheduled_hardfork) { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, get_accounts) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (vector, account_names) + ); return my->database().with_weak_read_lock([&]() { - return my->get_accounts(args.args->at(0).as >()); + return my->get_accounts(account_names); }); } @@ -387,9 +388,11 @@ std::vector plugin::api_impl::get_accounts(std::vector, account_names) + ); return my->database().with_weak_read_lock([&]() { - return my->lookup_account_names(args.args->at(0).as >()); + return my->lookup_account_names(account_names); }); } @@ -413,9 +416,10 @@ std::vector> plugin::api_impl::lookup_account_names } DEFINE_API(plugin, lookup_accounts) { - CHECK_ARG_SIZE(2) - account_name_type lower_bound_name = args.args->at(0).as(); - uint32_t limit = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, lower_bound_name) + (uint32_t, limit) + ); return my->database().with_weak_read_lock([&]() { return my->lookup_accounts(lower_bound_name, limit); }); @@ -425,7 +429,7 @@ std::set plugin::api_impl::lookup_accounts( const std::string &lower_bound_name, uint32_t limit ) const { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &accounts_by_name = database().get_index().indices().get(); std::set result; @@ -448,8 +452,9 @@ uint64_t plugin::api_impl::get_account_count() const { } DEFINE_API(plugin, get_owner_history) { - CHECK_ARG_SIZE(1) - auto account = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + ); return my->database().with_weak_read_lock([&]() { std::vector results; const auto &hist_idx = my->database().get_index().indices().get< @@ -466,8 +471,9 @@ DEFINE_API(plugin, get_owner_history) { } DEFINE_API(plugin, get_recovery_request) { - CHECK_ARG_SIZE(1) - auto account = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + ); return my->database().with_weak_read_lock([&]() { optional result; @@ -484,9 +490,10 @@ DEFINE_API(plugin, get_recovery_request) { } DEFINE_API(plugin, get_escrow) { - CHECK_ARG_SIZE(2) - auto from = args.args->at(0).as(); - auto escrow_id = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, from) + (uint32_t, escrow_id) + ); return my->database().with_weak_read_lock([&]() { optional result; @@ -547,19 +554,20 @@ std::vector plugin::api_impl::get_withdraw_routes( DEFINE_API(plugin, get_withdraw_routes) { - FC_ASSERT(args.args->size() == 1 || args.args->size() == 2, "Expected 1-2 arguments, was ${n}", - ("n", args.args->size())); - auto account = args.args->at(0).as(); - auto type = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + (withdraw_route_type, type, incoming) + ); return my->database().with_weak_read_lock([&]() { return my->get_withdraw_routes(account, type); }); } DEFINE_API(plugin, get_account_bandwidth) { - CHECK_ARG_SIZE(2) - auto account = args.args->at(0).as(); - auto type = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + (bandwidth_type, type) + ); optional result; auto band = my->database().find( boost::make_tuple(account, type)); @@ -578,8 +586,9 @@ DEFINE_API(plugin, get_account_bandwidth) { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, get_transaction_hex) { - CHECK_ARG_SIZE(1) - auto trx = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + ); return my->database().with_weak_read_lock([&]() { return my->get_transaction_hex(trx); }); @@ -590,9 +599,10 @@ std::string plugin::api_impl::get_transaction_hex(const signed_transaction &trx) } DEFINE_API(plugin, get_required_signatures) { - CHECK_ARG_SIZE(2) - auto trx = args.args->at(0).as(); - auto available_keys = args.args->at(1).as>(); + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + (flat_set, available_keys) + ); return my->database().with_weak_read_lock([&]() { return my->get_required_signatures(trx, available_keys); }); @@ -621,9 +631,11 @@ std::set plugin::api_impl::get_required_signatures( } DEFINE_API(plugin, get_potential_signatures) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + ); return my->database().with_weak_read_lock([&]() { - return my->get_potential_signatures(args.args->at(0).as()); + return my->get_potential_signatures(trx); }); } @@ -660,9 +672,11 @@ std::set plugin::api_impl::get_potential_signatures(const signe } DEFINE_API(plugin, verify_authority) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + ); return my->database().with_weak_read_lock([&]() { - return my->verify_authority(args.args->at(0).as()); + return my->verify_authority(trx); }); } @@ -678,10 +692,12 @@ bool plugin::api_impl::verify_authority(const signed_transaction &trx) const { } DEFINE_API(plugin, verify_account_authority) { - CHECK_ARG_SIZE(2) + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, name) + (flat_set, keys) + ); return my->database().with_weak_read_lock([&]() { - return my->verify_account_authority(args.args->at(0).as(), - args.args->at(1).as >()); + return my->verify_account_authority(name, keys); }); } @@ -689,22 +705,22 @@ bool plugin::api_impl::verify_account_authority( const std::string &name, const flat_set &keys ) const { - FC_ASSERT(name.size() > 0); - auto account = database().find(name); - FC_ASSERT(account, "no such account"); + GOLOS_CHECK_PARAM(name, GOLOS_CHECK_VALUE(name.size() > 0, "Account must be not empty")); + auto account = database().get_account(name); /// reuse trx.verify_authority by creating a dummy transfer signed_transaction trx; transfer_operation op; - op.from = account->name; + op.from = account.name; trx.operations.emplace_back(op); return verify_authority(trx); } DEFINE_API(plugin, get_conversion_requests) { - CHECK_ARG_SIZE(1) - auto account = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + ); return my->database().with_weak_read_lock([&]() { const auto &idx = my->database().get_index().indices().get(); std::vector result; @@ -719,8 +735,9 @@ DEFINE_API(plugin, get_conversion_requests) { DEFINE_API(plugin, get_savings_withdraw_from) { - CHECK_ARG_SIZE(1) - auto account = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + ); return my->database().with_weak_read_lock([&]() { std::vector result; @@ -735,8 +752,9 @@ DEFINE_API(plugin, get_savings_withdraw_from) { } DEFINE_API(plugin, get_savings_withdraw_to) { - CHECK_ARG_SIZE(1) - auto account = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + ); return my->database().with_weak_read_lock([&]() { std::vector result; @@ -752,14 +770,14 @@ DEFINE_API(plugin, get_savings_withdraw_to) { //vector get_vesting_delegations(string account, string from, uint32_t limit, delegations_type type = delegated) const; DEFINE_API(plugin, get_vesting_delegations) { - size_t n_args = args.args->size(); - CHECK_ARGS_COUNT(2, 4); - auto account = args.args->at(0).as(); - auto from = args.args->at(1).as(); - auto limit = n_args >= 3 ? args.args->at(2).as() : 100; - auto type = n_args >= 4 ? args.args->at(3).as() : delegated; + PLUGIN_API_VALIDATE_ARGS( + (string, account) + (string, from) + (uint32_t, limit, 100) + (delegations_type, type, delegated) + ); bool sent = type == delegated; - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); vector result; result.reserve(limit); @@ -781,12 +799,12 @@ DEFINE_API(plugin, get_vesting_delegations) { //vector get_expiring_vesting_delegations(string account, time_point_sec from, uint32_t limit = 100) const; DEFINE_API(plugin, get_expiring_vesting_delegations) { - size_t n_args = args.args->size(); - CHECK_ARGS_COUNT(2, 3); - auto account = args.args->at(0).as(); - auto from = args.args->at(1).as(); - uint32_t limit = n_args >= 3 ? args.args->at(2).as() : 100; - FC_ASSERT(limit <= 1000); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + (time_point_sec, from) + (uint32_t, limit, 100) + ); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); return my->database().with_weak_read_lock([&]() { vector result; @@ -802,8 +820,7 @@ DEFINE_API(plugin, get_expiring_vesting_delegations) { } DEFINE_API(plugin, get_database_info) { - CHECK_ARG_SIZE(0); - + PLUGIN_API_VALIDATE_ARGS(); // read lock doesn't seem needed... database_info info; @@ -864,11 +881,12 @@ std::vector plugin::api_impl::get_proposed_transactions( } DEFINE_API(plugin, get_proposed_transactions) { - CHECK_ARG_SIZE(3); - auto account = args.args->at(0).as(); - auto from = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - FC_ASSERT(limit <= 100); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + (uint32_t, from) + (uint32_t, limit) + ); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); return my->database().with_weak_read_lock([&]() { return my->get_proposed_transactions(account, from, limit); From f6533bde1aedfee86c129f74c7e551dacb39c960 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 19:59:33 +0700 Subject: [PATCH 157/250] Refactor errors: debug_node plugin #791 --- .../golos/plugins/debug_node/api_helper.hpp | 110 ------------------ plugins/debug_node/plugin.cpp | 3 +- 2 files changed, 2 insertions(+), 111 deletions(-) delete mode 100644 plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp diff --git a/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp b/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp deleted file mode 100644 index 358b4ab046..0000000000 --- a/plugins/debug_node/include/golos/plugins/debug_node/api_helper.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -// TODO Remove after done refactor erros in plugins #791 -// This functional moved to plugins/jon_api/include/golos/plugins/json_api/api_helper.hpp - -// Provides PLUGIN_API_VALIDATE_ARGS macro usable in DEFINE_API methods -// to generate arguments processing boilerplate. - -//Usage: -// PLUGIN_API_VALIDATE_ARGS( -// (std::string, json_filename) -// ) -//Expands to: -// std::string json_filename; -// FC_ASSERT(args.args.valid(), "Invalid parameters"); -// auto n_args = args.args->size(); -// FC_ASSERT(n_args == 1, "Expected 1 parameter, received ${n}", ("n", n_args)); -// json_filename = args.args->at(0).as(); -// -//And this: -// PLUGIN_API_VALIDATE_ARGS( -// (std::string, json_filename) -// (uint32_t, count) -// (uint32_t, skip_flags, golos::chain::database::skip_nothing) -// ) -//Expands to: -// std::string json_filename; -// uint32_t count; -// uint32_t skip_flags = golos::chain::database::skip_nothing; -// FC_ASSERT(args.args.valid(), "Invalid parameters"); -// auto n_args = args.args->size(); -// FC_ASSERT(n_args >= 2 && n_args <= 3, "Expected at least 2 and up to 3 parameters, received ${n}", ("n", n_args)); -// json_filename = args.args->at(0).as(); -// count = args.args->at(1).as(); -// if (n_args > 2) { -// skip_flags = args.args->at(2).as(); -// } - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REMOVE_PARENTHESES(...) __VA_ARGS__ - -// prepare -#define PLUGIN_API_VALIDATE_ARGS(ARGS) PLUGIN_API_VALIDATE_ARGS_I(BOOST_PP_VARIADIC_SEQ_TO_SEQ(ARGS)) -#define PLUGIN_API_VALIDATE_ARGS_I(ARGS) PLUGIN_API_VALIDATE_ARGS_II(ARGS, COUNT_REQUIRED_ARGS(ARGS), BOOST_PP_SEQ_SIZE(ARGS)) - -// main -#define PLUGIN_API_VALIDATE_ARGS_II(ARGS, N_REQ, N_ARGS) \ - PLUGIN_API_DECLARE_ARG_VARS(ARGS) \ - FC_ASSERT(args.args.valid(), "Invalid parameters"); /* is it possible to get invalid?*/ \ - auto n_args = args.args->size(); \ - PLUGIN_API_ARGS_NUM_ASSERT(N_REQ, N_ARGS) \ - PLUGIN_API_LOAD_AND_CHECK_ARGS(ARGS, N_REQ) - -// helper -#define COUNT_REQUIRED_ARGS(args) COUNT_REQUIRED_ARGS_I(args, BOOST_PP_SEQ_SIZE(args)) -#define COUNT_REQUIRED_ARGS_I(args, sz) BOOST_PP_SEQ_ELEM(2, BOOST_PP_WHILE(COUNT_PR, COUNT_OP, (args(end))(sz)(0))) -#define STATE_OP(op, state) op(BOOST_PP_SEQ_ELEM(0, state), BOOST_PP_SEQ_ELEM(1, state), BOOST_PP_SEQ_ELEM(2, state)) -#define COUNT_OP(d, state) STATE_OP(COUNT_OP_I, state) -#define COUNT_PR(d, state) STATE_OP(COUNT_PR_I, state) -#define COUNT_OP_I(args, sz, i) (args)(sz)(BOOST_PP_INC(i)) -#define COUNT_PR_I(args, sz, i) BOOST_PP_AND(HAVE_NEXT_ARG(sz, i), GOT_REQUIRED(args, i)) -#define HAVE_NEXT_ARG(sz, i) BOOST_PP_LESS(i, sz) -#define GOT_REQUIRED(args, i) BOOST_PP_LESS(ARG_SIZE(BOOST_PP_SEQ_ELEM(i, args)), 3) -#define ARG_SIZE(arg) BOOST_PP_VARIADIC_SIZE(REMOVE_PARENTHESES arg) - -// steps: -#define PLUGIN_API_DECLARE_ARG_VARS(ARGS) BOOST_PP_SEQ_FOR_EACH(PLUGIN_API_DECLARE_ARG_VAR, _, ARGS) -#define PLUGIN_API_DECLARE_ARG_VAR(r, data, arg) \ - ARG_TYPE(arg) ARG_NAME(arg) ARG_OPT_VALUE(arg); - -#define ARG_ELEM(arg, n) BOOST_PP_VARIADIC_ELEM(n, REMOVE_PARENTHESES arg, nop) -#define ARG_TYPE(arg) ARG_ELEM(arg, 0) -#define ARG_NAME(arg) ARG_ELEM(arg, 1) -#define ARG_VALUE(arg) ARG_ELEM(arg, 2) -#define ARG_HAVE_VALUE(arg) BOOST_PP_GREATER(ARG_SIZE(arg), 2) -#define ARG_OPT_VALUE(arg) BOOST_PP_IF(ARG_HAVE_VALUE(arg), = ARG_VALUE(arg), BOOST_PP_EMPTY()) - -#define PLUGIN_API_ARGS_NUM_ASSERT(req, all) PLUGIN_API_ARGS_NUM_ASSERT_I(BOOST_PP_LESS(req, all), req, all) -#define PLUGIN_API_ARGS_NUM_ASSERT_I(less, req, all) \ - PLUGIN_API_ARGS_NUM_ASSERT_II(AN_ASSERT_COND(less, req, all), AN_ASSERT_MSG(less, req, all)) -#define PLUGIN_API_ARGS_NUM_ASSERT_II(cond, msg) \ - FC_ASSERT(cond, msg, ("n", n_args)); - -#define AN_ASSERT_COND(less, req, all) BOOST_PP_IF(less, n_args >= req && n_args <= all, n_args == all) -#define AN_ASSERT_MSG(LESS, REQ, ALL) \ - "Expected " BOOST_PP_STRINGIZE( BOOST_PP_IF(LESS, at least REQ and up to ALL, REQ) ) \ - " parameter" PLURAL_FINAL(ALL) ", received ${n}" -#define PLURAL_FINAL(n) BOOST_PP_IF(BOOST_PP_LESS(n, 2), "", "s") - -#define PLUGIN_API_LOAD_AND_CHECK_ARGS(ARGS, n_req) BOOST_PP_SEQ_FOR_EACH_I(LOAD_AND_CHECK_ARG, n_req, ARGS) -#define LOAD_AND_CHECK_ARG(r, n_req, i, arg) LOAD_AND_CHECK_ARG_I(arg, i, BOOST_PP_LESS(i, n_req)) -#define LOAD_AND_CHECK_ARG_I(arg, i, req) BOOST_PP_IF(req, LOAD_ARG, LOAD_OPTIONAL_ARG)(arg, i) -#define LOAD_ARG(arg, i) ARG_NAME(arg) = args.args->at(i).as(); -#define LOAD_OPTIONAL_ARG(arg, i) \ - if (n_args > i) { \ - LOAD_ARG(arg, i) \ - } diff --git a/plugins/debug_node/plugin.cpp b/plugins/debug_node/plugin.cpp index c78312a333..8b7d455078 100644 --- a/plugins/debug_node/plugin.cpp +++ b/plugins/debug_node/plugin.cpp @@ -1,5 +1,6 @@ #include +#include #include #include @@ -478,7 +479,7 @@ bool plugin::plugin_impl::debug_has_hardfork( uint32_t hardfork_id ) { // -#include +#include #define DEFINE_PLUGIN_API(name) DEFINE_API(plugin, name) From c3049a047f8517c5131263e3a7e63c8e91356818 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 20:07:09 +0700 Subject: [PATCH 158/250] Refactor errors: market_history plugin #791 --- .../market_history/market_history_plugin.cpp | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/plugins/market_history/market_history_plugin.cpp b/plugins/market_history/market_history_plugin.cpp index 7ec0401d17..dc855ade69 100644 --- a/plugins/market_history/market_history_plugin.cpp +++ b/plugins/market_history/market_history_plugin.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -255,7 +256,7 @@ namespace golos { } order_book_extended market_history_plugin::market_history_plugin_impl::get_order_book_extended(uint32_t limit) const { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); order_book_extended result; auto max_sell = price::max(SBD_SYMBOL, STEEM_SYMBOL); @@ -298,7 +299,7 @@ namespace golos { vector market_history_plugin::market_history_plugin_impl::get_trade_history( time_point_sec start, time_point_sec end, uint32_t limit) const { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &bucket_idx = database().get_index().indices().get(); auto itr = bucket_idx.lower_bound(start); @@ -318,7 +319,7 @@ namespace golos { } vector market_history_plugin::market_history_plugin_impl::get_recent_trades(uint32_t limit) const { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &order_idx = database().get_index().indices().get(); auto itr = order_idx.rbegin(); @@ -447,6 +448,7 @@ namespace golos { // Api Defines DEFINE_API(market_history_plugin, get_ticker) { + PLUGIN_API_VALIDATE_ARGS(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_ticker(); @@ -454,6 +456,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_volume) { + PLUGIN_API_VALIDATE_ARGS(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_volume(); @@ -461,8 +464,9 @@ namespace golos { } DEFINE_API(market_history_plugin, get_order_book) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1); - GOLOS_DECLARE_PARAM(limit, args.args->at(0).as()); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, limit) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_order_book(limit); @@ -470,8 +474,9 @@ namespace golos { } DEFINE_API(market_history_plugin, get_order_book_extended) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1); - auto limit = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, limit) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_order_book_extended(limit); @@ -480,10 +485,11 @@ namespace golos { DEFINE_API(market_history_plugin, get_trade_history) { - GOLOS_CHECK_ARGS_COUNT(args.args, 3); - auto start = args.args->at(0).as(); - auto end = args.args->at(1).as(); - auto limit = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (time_point_sec, start) + (time_point_sec, end) + (uint32_t, limit) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_trade_history(start, end, limit); @@ -491,8 +497,9 @@ namespace golos { } DEFINE_API(market_history_plugin, get_recent_trades) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1); - auto limit = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, limit) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_recent_trades(limit); @@ -500,10 +507,11 @@ namespace golos { } DEFINE_API(market_history_plugin, get_market_history) { - GOLOS_CHECK_ARGS_COUNT(args.args, 3); - auto bucket_seconds = args.args->at(0).as(); - auto start = args.args->at(1).as(); - auto end = args.args->at(2).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, bucket_seconds) + (time_point_sec, start) + (time_point_sec, end) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_market_history(bucket_seconds, start, end); @@ -511,6 +519,7 @@ namespace golos { } DEFINE_API(market_history_plugin, get_market_history_buckets) { + PLUGIN_API_VALIDATE_ARGS(); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_market_history_buckets(); @@ -518,9 +527,9 @@ namespace golos { } DEFINE_API(market_history_plugin, get_open_orders) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1); - GOLOS_DECLARE_PARAM(account, args.args->at(0).as()); - //auto tmp = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account) + ); auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_open_orders(account); From 2f6fe464fe477f88e523516d7f6ff6c4e9569ac7 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Mon, 23 Jul 2018 16:02:40 +0700 Subject: [PATCH 159/250] Add base implementation of contact list for private messages. #805 --- .../include/golos/wallet/remote_node_api.hpp | 4 +- .../wallet/include/golos/wallet/wallet.hpp | 10 +- libraries/wallet/wallet.cpp | 2 +- .../private_message_evaluators.hpp | 15 + .../private_message_objects.hpp | 205 ++++++++-- .../private_message_plugin.hpp | 29 +- .../private_message_objects.cpp | 91 ++++- .../private_message_plugin.cpp | 375 +++++++++++++++--- 8 files changed, 625 insertions(+), 106 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index d9d767ec77..8979c85150 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -175,8 +175,8 @@ struct remote_market_history { * Class is used by wallet to send formatted API calls to market_history plugin on remote node. */ struct remote_private_message { - vector get_inbox(const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) const; - vector get_outbox(const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) const; + vector get_inbox(const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset) const; + vector get_outbox(const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; }; /** diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index bc2ef4c747..acce2f887b 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -49,11 +49,11 @@ namespace golos { namespace wallet { std::string body; }; - struct extended_message_object: public message_api_obj { + struct extended_message_object: public message_api_object { extended_message_object() = default; - extended_message_object(const message_api_obj& o) - : message_api_obj(o) { + extended_message_object(const message_api_object& o) + : message_api_object(o) { } message_body message; @@ -1140,7 +1140,7 @@ namespace golos { namespace wallet { annotated_signed_transaction send_private_message( const std::string& from, const std::string& to, const message_body& message, bool broadcast); - message_body try_decrypt_message( const message_api_obj& mo ); + message_body try_decrypt_message(const message_api_object& mo); }; struct plain_keys { @@ -1280,5 +1280,5 @@ FC_REFLECT( FC_REFLECT_DERIVED( (golos::wallet::extended_message_object), - ((golos::plugins::private_message::message_api_obj)), + ((golos::plugins::private_message::message_api_object)), (message)); \ No newline at end of file diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index fe19ebf0c9..764f67d457 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2588,7 +2588,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction(trx, broadcast); } - message_body wallet_api::try_decrypt_message(const message_api_obj& mo) { + message_body wallet_api::try_decrypt_message(const message_api_object& mo) { message_body result; fc::sha512 shared_secret; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index 51608f13ff..de7b4d90e2 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -23,4 +23,19 @@ namespace golos { namespace plugins { namespace private_message { private_message_plugin* plugin_; }; + class private_list_evaluator: + public golos::chain::evaluator_impl + { + public: + using operation_type = private_list_operation; + + private_list_evaluator(database& db, private_message_plugin* plugin) + : golos::chain::evaluator_impl(db), + plugin_(plugin) + {} + + void do_apply(const private_list_operation& o); + + private_message_plugin* plugin_; + }; } } } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 6ccc4f6091..4a1637e895 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -15,17 +15,19 @@ namespace golos { namespace plugins { namespace private_message { using namespace golos::protocol; using namespace chainbase; using namespace golos::chain; + using namespace boost::multi_index; #ifndef PRIVATE_MESSAGE_SPACE_ID #define PRIVATE_MESSAGE_SPACE_ID 6 #endif enum private_message_object_type { - message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8), + list_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 1, + list_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, }; - class message_object: - public object { + class message_object: public object { public: template message_object(Constructor&& c, allocator a) @@ -42,42 +44,30 @@ namespace golos { namespace plugins { namespace private_message { uint64_t sent_time = 0; /// used as seed to secret generation time_point_sec receive_time; /// time received by blockchain uint32_t checksum = 0; + time_point_sec read_time; buffer_type encrypted_message; }; using message_id_type = message_object::id_type; - struct message_api_obj { - message_api_obj(const message_object& o) - : id(o.id), - from(o.from), - to(o.to), - from_memo_key(o.from_memo_key), - to_memo_key(o.to_memo_key), - sent_time(o.sent_time), - receive_time(o.receive_time), - checksum(o.checksum), - encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { - } - - message_api_obj() = default; + struct message_api_object { + message_api_object(const message_object& o); + message_api_object(); - message_id_type id; account_name_type from; account_name_type to; public_key_type from_memo_key; public_key_type to_memo_key; - uint64_t sent_time; + uint64_t sent_time = 0; time_point_sec receive_time; - uint32_t checksum; + uint32_t checksum = 0; + time_point_sec read_time; std::vector encrypted_message; }; struct by_to_date; struct by_from_date; - using namespace boost::multi_index; - using message_index = multi_index_container< message_object, indexed_by< @@ -92,7 +82,7 @@ namespace golos { namespace plugins { namespace private_message { member, member>, composite_key_compare< - std::less, + string_less, std::greater, std::less>>, ordered_unique< @@ -103,7 +93,7 @@ namespace golos { namespace plugins { namespace private_message { member, member>, composite_key_compare< - std::less, + string_less, std::greater, std::less>>>, allocator>; @@ -118,19 +108,180 @@ namespace golos { namespace plugins { namespace private_message { std::vector encrypted_message; void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + + enum private_list_type: uint8_t { + undefined = 1, + pinned = 2, + ignored = 3, + }; + + constexpr auto private_list_type_size = ignored + 1; + + class list_object: public object { + public: + template + list_object(Constructor&& c, allocator a) { + c(*this); + } + + id_type id; + + account_name_type owner; + account_name_type contact; + private_list_type type; + uint32_t total_send_messages = 0; + uint32_t unread_send_messages = 0; + uint32_t total_recv_messages = 0; + uint32_t unread_recv_messages = 0; + }; + + using list_id_type = list_object::id_type; + + struct list_api_object { + list_api_object(const list_object& o); + list_api_object(); + + account_name_type owner; + account_name_type contact; + private_list_type owner_type = undefined; + private_list_type contact_type = undefined; + uint32_t total_send_messages = 0; + uint32_t unread_send_messages = 0; + uint32_t total_recv_messages = 0; + uint32_t unread_recv_messages = 0; + }; + + struct by_owner; + struct by_contact; + + using list_index = multi_index_container< + list_object, + indexed_by< + ordered_unique< + tag, + member>, + ordered_unique< + tag, + composite_key< + list_object, + member, + member, + member>, + composite_key_compare< + string_less, + std::greater, + string_less>>, + ordered_unique< + tag, + composite_key< + list_object, + member, + member>, + composite_key_compare< + string_less, + string_less>>>, + allocator>; + + struct list_size_info { + uint32_t total_contacts = 0; + uint32_t total_send_messages = 0; + uint32_t unread_send_messages = 0; + uint32_t total_recv_messages = 0; + uint32_t unread_recv_messages = 0; + }; - void get_required_posting_authorities(flat_set& a) const { - a.insert(from); + struct list_size_object: public object { + template + list_size_object(Constructor&& c, allocator a) { + c(*this); } + + id_type id; + + account_name_type owner; + private_list_type type; + list_size_info info; + }; + + using list_size_id_type = list_size_object::id_type; + + struct list_size_api_object { + account_name_type owner; + fc::flat_map info; }; - using private_message_plugin_operation = fc::static_variant; + using list_size_index = multi_index_container< + list_size_object, + indexed_by< + ordered_unique< + tag, + member>, + ordered_unique< + tag, + composite_key< + list_size_object, + member, + member>, + composite_key_compare< + string_less, + std::less>>>, + allocator>; + + struct private_list_operation: public base_operation { + account_name_type owner; + account_name_type contact; + private_list_type type; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + + using private_message_plugin_operation = fc::static_variant< + private_message_operation, + private_list_operation>; } } } // golos::plugins::private_message +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::private_message::message_object, golos::plugins::private_message::message_index) + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::private_message::list_object, golos::plugins::private_message::list_index) + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::private_message::list_size_object, golos::plugins::private_message::list_size_index) + +FC_REFLECT( + (golos::plugins::private_message::message_api_object), + (from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(read_time)(checksum)(encrypted_message)) + +FC_REFLECT_ENUM( + golos::plugins::private_message::private_list_type, + (undefined)(pinned)(ignored)) + +FC_REFLECT( + (golos::plugins::private_message::list_size_info), + (total_contacts)(total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + +FC_REFLECT( + (golos::plugins::private_message::list_api_object), + (owner)(contact)(owner_type)(contact_type) + (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + +FC_REFLECT( + (golos::plugins::private_message::list_size_api_object), + (owner)(info)) + FC_REFLECT( (golos::plugins::private_message::private_message_operation), (from)(to)(from_memo_key)(to_memo_key)(sent_time)(checksum)(encrypted_message)) +FC_REFLECT( + (golos::plugins::private_message::private_list_operation), + (owner)(contact)(type)) + FC_REFLECT_TYPENAME((golos::plugins::private_message::private_message_plugin_operation)) + DECLARE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation) \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index 3e733c96b6..56ee3503c6 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -16,8 +16,11 @@ namespace golos { namespace plugins { namespace private_message { using namespace golos::chain; - DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) - DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_list_size, json_rpc::msg_pack, list_size_api_object) + DEFINE_API_ARGS(get_list_info, json_rpc::msg_pack, list_api_object) + DEFINE_API_ARGS(get_list, json_rpc::msg_pack, std::vector) /** * This plugin scans the blockchain for custom operations containing a valid message and authorized @@ -33,20 +36,20 @@ namespace golos { namespace plugins { namespace private_message { ~private_message_plugin(); void set_program_options( - boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) override; + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) override; - void plugin_initialize(const boost::program_options::variables_map &options) override; + void plugin_initialize(const boost::program_options::variables_map& options) override; void plugin_startup() override; void plugin_shutdown() override; - flat_map tracked_accounts() const; /// map start_range to end_range + bool is_tracked_account(account_name_type) const; - static const std::string &name(); + static const std::string& name(); - DECLARE_API((get_inbox)(get_outbox)) + DECLARE_API((get_inbox)(get_outbox)(get_list_size)(get_list_info)(get_list)) private: class private_message_plugin_impl; @@ -56,13 +59,3 @@ namespace golos { namespace plugins { namespace private_message { }; } } } //golos::plugins::private_message - -FC_REFLECT( - (golos::plugins::private_message::message_object), - (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); -CHAINBASE_SET_INDEX_TYPE( - golos::plugins::private_message::message_object, golos::plugins::private_message::message_index); - -FC_REFLECT( - (golos::plugins::private_message::message_api_obj), - (id)(from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(checksum)(encrypted_message)); diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_objects.cpp index 5341e04cd0..2098d10e60 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_objects.cpp @@ -1,11 +1,100 @@ #include #include +#include +#include namespace golos { namespace plugins { namespace private_message { + static inline void validate_account_name(const string &name) { + GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); + } + + message_api_object::message_api_object(const message_object& o) + : from(o.from), + to(o.to), + from_memo_key(o.from_memo_key), + to_memo_key(o.to_memo_key), + sent_time(o.sent_time), + receive_time(o.receive_time), + checksum(o.checksum), + read_time(o.read_time), + encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { + } + + message_api_object::message_api_object() = default; + + list_api_object::list_api_object(const list_object& o) + : owner(o.owner), + contact(o.contact), + owner_type(o.type), + total_send_messages(o.total_send_messages), + unread_send_messages(o.unread_send_messages), + total_recv_messages(o.total_recv_messages), + unread_recv_messages(o.unread_recv_messages) { + } + + list_api_object::list_api_object() = default; + void private_message_operation::validate() const { - FC_ASSERT(from != to, "You cannot write to yourself"); + GOLOS_CHECK_PARAM_ACCOUNT(to); + + GOLOS_CHECK_PARAM(from, { + validate_account_name(from); + GOLOS_CHECK_VALUE(from != to, "You cannot write to yourself"); + }); + + GOLOS_CHECK_PARAM(to_memo_key, { + GOLOS_CHECK_VALUE(to_memo_key != public_key_type(), "To_key can't be empty"); + }); + + GOLOS_CHECK_PARAM(from_memo_key, { + GOLOS_CHECK_VALUE(from_memo_key != public_key_type(), "From_key can't be empty"); + GOLOS_CHECK_VALUE(from_memo_key != to_memo_key, "From_key can't be equal to to_key"); + }); + + GOLOS_CHECK_PARAM(sent_time, { + GOLOS_CHECK_VALUE(sent_time != 0, "Send time can't be zero"); + }); + + GOLOS_CHECK_PARAM(encrypted_message, { + GOLOS_CHECK_VALUE(encrypted_message.size() >= 16, "Encrypted message is too small"); + }); } + + void private_message_operation::get_required_posting_authorities(flat_set& a) const { + a.insert(from); + } + + bool is_valid_list_type(private_list_type type) { + switch(type) { + case undefined: + case pinned: + case ignored: + return true; + + default: + break; + } + return false; + } + + void private_list_operation::validate() const { + GOLOS_CHECK_PARAM_ACCOUNT(contact); + + GOLOS_CHECK_PARAM(owner, { + validate_account_name(owner); + GOLOS_CHECK_VALUE(owner != contact, "You cannot add contact to yourself"); + }); + + GOLOS_CHECK_PARAM(type, { + GOLOS_CHECK_VALUE(is_valid_list_type(type), "Unknown list type"); + }); + } + + void private_list_operation::get_required_posting_authorities(flat_set& a) const { + a.insert(owner); + } + } } } // golos::plugins::private_message DEFINE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 3db455903b..5c36629b63 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -29,36 +29,43 @@ namespace golos { namespace plugins { namespace private_message { public: private_message_plugin_impl(private_message_plugin& plugin) : db_(appbase::app().get_plugin().db()) { + custom_operation_interpreter_ = std::make_shared >(db_); custom_operation_interpreter_->register_evaluator(&plugin); + custom_operation_interpreter_->register_evaluator(&plugin); db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); - return; } - std::vector get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset) const; + std::vector get_inbox( + const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset) const; + + std::vector get_outbox( + const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; - std::vector get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset) const; + list_api_object get_list_info(const std::string& owner, const std::string& contact) const; + list_size_api_object get_list_size(const std::string& owner) const; + + std::vector get_list( + const std::string& owner, const private_list_type type, uint16_t limit, uint32_t offset) const; ~private_message_plugin_impl() = default; + bool is_tracked_account(account_name_type) const; + std::shared_ptr> custom_operation_interpreter_; flat_map tracked_accounts_; - golos::chain::database &db_; + golos::chain::database& db_; }; - std::vector private_message_plugin::private_message_plugin_impl::get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint64_t offset + std::vector private_message_plugin::private_message_plugin_impl::get_inbox( + const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset ) const { - FC_ASSERT(limit <= 100); - - std::vector result; + std::vector result; const auto &idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(to, newest)); @@ -74,12 +81,11 @@ namespace golos { namespace plugins { namespace private_message { return result; } - std::vector private_message_plugin::private_message_plugin_impl::get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint64_t offset + std::vector private_message_plugin::private_message_plugin_impl::get_outbox( + const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset ) const { - FC_ASSERT(limit <= 100); - std::vector result; + std::vector result; const auto &idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(from, newest)); @@ -95,38 +101,243 @@ namespace golos { namespace plugins { namespace private_message { return result; } - void private_message_evaluator::do_apply(const private_message_operation &pm) { - database &d = db(); - - const flat_map &tracked_accounts = plugin_->tracked_accounts(); - - auto to_itr = tracked_accounts.lower_bound(pm.to); - auto from_itr = tracked_accounts.lower_bound(pm.from); - - FC_ASSERT(pm.from != pm.to); - FC_ASSERT(pm.from_memo_key != pm.to_memo_key); - FC_ASSERT(pm.sent_time != 0); - FC_ASSERT(pm.encrypted_message.size() >= 16); - - if (!tracked_accounts.size() || - (to_itr != tracked_accounts.end() && pm.to >= to_itr->first && - pm.to <= to_itr->second) || - (from_itr != tracked_accounts.end() && - pm.from >= from_itr->first && pm.from <= from_itr->second) - ) { - d.create([&](message_object &pmo) { - pmo.from = pm.from; - pmo.to = pm.to; - pmo.from_memo_key = pm.from_memo_key; - pmo.to_memo_key = pm.to_memo_key; - pmo.checksum = pm.checksum; - pmo.sent_time = pm.sent_time; - pmo.receive_time = d.head_block_time(); - pmo.encrypted_message.resize(pm.encrypted_message.size()); - std::copy( - pm.encrypted_message.begin(), pm.encrypted_message.end(), - pmo.encrypted_message.begin()); + list_api_object private_message_plugin::private_message_plugin_impl::get_list_info( + const std::string& owner, const std::string& contact + ) const { + const auto& idx = db_.get_index().indices().get(); + auto itr = idx.find(std::make_tuple(owner, contact)); + + if (itr != idx.end()) { + list_api_object result(*itr); + auto ritr = idx.find(std::make_tuple(contact, owner)); + if (idx.end() != ritr) { + result.contact_type = ritr->type; + } + return result; + } + return list_api_object(); + } + + list_size_api_object private_message_plugin::private_message_plugin_impl::get_list_size( + const std::string& owner + ) const { + list_size_api_object result; + + const auto& idx = db_.get_index().indices().get(); + + result.owner = owner; + for (uint8_t i = undefined; i < private_list_type_size; ++i) { + auto t = static_cast(i); + auto itr = idx.find(std::make_tuple(owner, t)); + if (idx.end() != itr) { + result.info[t] = itr->info; + } else { + result.info[t] = list_size_info(); + } + } + + return result; + } + + std::vector private_message_plugin::private_message_plugin_impl::get_list( + const std::string& owner, const private_list_type type, uint16_t limit, uint32_t offset + ) const { + std::vector result; + + result.reserve(limit); + + const auto& idx = db_.get_index().indices().get(); + const auto& ridx = db_.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(owner, type)); + auto etr = idx.upper_bound(std::make_tuple(owner, type)); + + for (; itr != etr && offset; ++itr, --offset); + + for (; itr != etr; ++itr) { + result.emplace_back(*itr); + + auto ritr = ridx.find(std::make_tuple(itr->contact, itr->owner)); + if (ritr != ridx.end()) { + result.back().contact_type = ritr->type; + } + } + return result; + } + + void private_message_evaluator::do_apply(const private_message_operation& pm) { + database& d = db(); + + if (!plugin_->is_tracked_account(pm.from) && !plugin_->is_tracked_account(pm.to)) { + return; + } + + GOLOS_CHECK_OP_PARAM(pm, to, { + GOLOS_CHECK_VALUE(d.find_account(pm.to) != nullptr, "Account doesn't exist"); + }); + + d.create([&](message_object& pmo) { + pmo.from = pm.from; + pmo.to = pm.to; + pmo.from_memo_key = pm.from_memo_key; + pmo.to_memo_key = pm.to_memo_key; + pmo.checksum = pm.checksum; + pmo.sent_time = pm.sent_time; + pmo.read_time = time_point_sec::min(); + pmo.receive_time = d.head_block_time(); + pmo.encrypted_message.resize(pm.encrypted_message.size()); + std::copy( + pm.encrypted_message.begin(), pm.encrypted_message.end(), + pmo.encrypted_message.begin()); + }); + + // Ok, now update contact lists and counters in them + + auto& idx = d.get_index().indices().get(); + auto& sidx = d.get_index().indices().get(); + + // Increment counters depends on side of communication + auto modify_counters = [&](auto& o, const bool is_send) { + if (is_send) { + o.total_send_messages++; + o.unread_send_messages++; + } else { + o.total_recv_messages++; + o.unread_recv_messages++; + } + }; + + // Update global counters by type of contact + + auto modify_size = [&](auto& owner, auto type, const bool is_new_contact, const bool is_send) { + auto func = [&](list_size_object& plso) { + modify_counters(plso.info, is_send); + if (is_new_contact) { + plso.info.total_contacts++; + } + }; + + auto itr = sidx.find(std::make_tuple(owner, type)); + if (sidx.end() == itr) { + d.create([&](list_size_object& plso){ + plso.owner = owner; + plso.type = type; + func(plso); + }); + } else { + d.modify(*itr, func); + } + }; + + // Add contact list if it doesn't exist or update it if it exits + + auto modify_contact = [&](auto& owner, auto& contact, auto type, const bool is_send) { + bool is_new_contact; + auto itr = idx.find(std::make_tuple(owner, contact)); + if (idx.end() != itr) { + d.modify(*itr, [&](list_object& plo) { + modify_counters(plo, is_send); + }); + is_new_contact = false; + type = itr->type; + } else { + d.create([&](list_object& plo) { + plo.owner = owner; + plo.contact = contact; + plo.type = type; + modify_counters(plo, is_send); + }); + is_new_contact = true; + } + modify_size(owner, type, is_new_contact, is_send); + }; + + modify_contact(pm.from, pm.to, pinned, true); + modify_contact(pm.to, pm.from, undefined, false); + } + + void private_list_evaluator::do_apply(const private_list_operation& pl) { + database& d = db(); + + if (!plugin_->is_tracked_account(pl.owner) && !plugin_->is_tracked_account(pl.contact)) { + return; + } + + GOLOS_CHECK_OP_PARAM(pl, contact, { + GOLOS_CHECK_VALUE(d.find_account(pl.contact) != nullptr, "Account doesn't exist"); + }); + + auto& idx = d.get_index().indices().get(); + auto itr = idx.find(std::make_tuple(pl.owner, pl.contact)); + + auto& sidx = d.get_index().indices().get(); + auto ditr = sidx.find(std::make_tuple(pl.owner, pl.type)); + + if (idx.end() != itr) { + GOLOS_CHECK_OP_PARAM(pl, type, { + GOLOS_CHECK_VALUE(pl.type != itr->type, "Contact already has requested type"); + }); + + auto sitr = sidx.find(std::make_tuple(pl.owner, itr->type)); + + d.modify(*sitr, [&](list_size_object& src) { + src.info.total_contacts--; + src.info.total_send_messages -= itr->total_send_messages; + src.info.unread_send_messages -= itr->unread_send_messages; + src.info.total_recv_messages -= itr->total_recv_messages; + src.info.unread_recv_messages -= itr->unread_recv_messages; }); + + // if contact is undefined and no messages then remove statistic about it + if (!sitr->info.total_contacts || + (sitr->type == undefined && !sitr->info.total_send_messages && !sitr->info.total_recv_messages) + ) { + d.remove(*sitr); + } + + auto modify_counters = [&](list_size_object& dst) { + dst.info.total_contacts++; + dst.info.total_send_messages += itr->total_send_messages; + dst.info.unread_send_messages += itr->unread_send_messages; + dst.info.total_recv_messages += itr->total_recv_messages; + dst.info.unread_recv_messages += itr->unread_recv_messages; + }; + + if (sidx.end() == ditr) { + d.create([&](list_size_object& dst) { + dst.owner = pl.owner; + dst.type = pl.type; + modify_counters(dst); + }); + } else { + d.modify(*ditr, modify_counters); + } + + // if contact is undefined and no messages then remove it + if (pl.type == undefined && !itr->total_send_messages && !itr->total_recv_messages) { + d.remove(*itr); + } else { + d.modify(*itr, [&](list_object& plo) { + plo.type = pl.type; + }); + } + } else if (pl.type != undefined) { + d.create([&](list_object& plo){ + plo.owner = pl.owner; + plo.contact = pl.contact; + plo.type = pl.type; + }); + + if (sidx.end() == ditr) { + d.create([&](list_size_object& plso) { + plso.owner = pl.owner; + plso.type = pl.type; + plso.info.total_contacts = 1; + }); + } else { + d.modify(*ditr, [&](list_size_object& plso) { + plso.info.total_contacts++; + }); + } } } @@ -155,6 +366,8 @@ namespace golos { namespace plugins { namespace private_message { my = std::make_unique(*this); add_plugin_index(my->db_); + add_plugin_index(my->db_); + add_plugin_index(my->db_); using pairstring = std::pair; LOAD_VALUE_SET(options, "pm-accounts", my->tracked_accounts_, pairstring); @@ -169,32 +382,90 @@ namespace golos { namespace plugins { namespace private_message { ilog("Shuting down private message plugin"); } - flat_map private_message_plugin::tracked_accounts() const { - return my->tracked_accounts_; + bool private_message_plugin::private_message_plugin_impl::is_tracked_account(account_name_type name) const { + if (tracked_accounts_.empty()) { + return true; + } + + auto itr = tracked_accounts_.lower_bound(name); + return tracked_accounts_.end() != itr && name >= itr->first && name <= itr->second; + } + + bool private_message_plugin::is_tracked_account(account_name_type name) const { + return my->is_tracked_account(name); } // Api Defines DEFINE_API(private_message_plugin, get_inbox) { + GOLOS_CHECK_ARGS_COUNT(args.args, 4) + auto to = args.args->at(0).as(); auto newest = args.args->at(1).as(); auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto &db = my->db_; + auto offset = args.args->at(3).as(); + auto& db = my->db_; + + GOLOS_CHECK_LIMIT(limit, 100); + return db.with_weak_read_lock([&]() { return my->get_inbox(to, newest, limit, offset); }); } DEFINE_API(private_message_plugin, get_outbox) { + GOLOS_CHECK_ARGS_COUNT(args.args, 4) + auto from = args.args->at(0).as(); auto newest = args.args->at(1).as(); auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto &db = my->db_; + auto offset = args.args->at(3).as(); + auto& db = my->db_; + + GOLOS_CHECK_LIMIT(limit, 100); + return db.with_weak_read_lock([&]() { return my->get_outbox(from, newest, limit, offset); }); } + DEFINE_API(private_message_plugin, get_list_size) { + GOLOS_CHECK_ARGS_COUNT(args.args, 1) + + auto owner = args.args->at(0).as(); + auto& db = my->db_; + + return db.with_weak_read_lock([&](){ + return my->get_list_size(owner); + }); + } + + DEFINE_API(private_message_plugin, get_list_info) { + GOLOS_CHECK_ARGS_COUNT(args.args, 2) + + auto owner = args.args->at(0).as(); + auto contact = args.args->at(1).as(); + auto& db = my->db_; + + return db.with_weak_read_lock([&](){ + return my->get_list_info(owner, contact); + }); + } + + DEFINE_API(private_message_plugin, get_list) { + GOLOS_CHECK_ARGS_COUNT(args.args, 4) + + auto owner = args.args->at(0).as(); + auto type = args.args->at(1).as(); + auto limit = args.args->at(2).as(); + auto offset = args.args->at(3).as(); + auto& db = my->db_; + + GOLOS_CHECK_LIMIT(limit, 100); + + return db.with_weak_read_lock([&](){ + return my->get_list(owner, type, limit, offset); + }); + } + } } } // golos::plugins::private_message From 8022c9786b8c337a7d7a9ba39168617318169613 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Mon, 23 Jul 2018 18:23:19 +0700 Subject: [PATCH 160/250] Add private contact lists to cli_wallet. #805 --- .../include/golos/wallet/remote_node_api.hpp | 10 ++++- .../wallet/include/golos/wallet/wallet.hpp | 30 ++++++++++++++- libraries/wallet/wallet.cpp | 37 ++++++++++++++++++- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 8979c85150..52bc992bdc 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -175,8 +175,11 @@ struct remote_market_history { * Class is used by wallet to send formatted API calls to market_history plugin on remote node. */ struct remote_private_message { - vector get_inbox(const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset) const; - vector get_outbox(const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; + vector get_inbox(const std::string& to, time_point newest, uint16_t limit, uint32_t offset) const; + vector get_outbox(const std::string& from, time_point newest, uint16_t limit, uint32_t offset) const; + list_size_api_object get_list_size(const std::string& owner) const; + list_api_object get_list_info(const std::string& owner, const std::string& contact) const; + std::vector get_list(const std::string& owner, private_list_type, uint16_t limit, uint32_t offset) const; }; /** @@ -324,6 +327,9 @@ FC_API( golos::wallet::remote_market_history, FC_API( golos::wallet::remote_private_message, (get_inbox) (get_outbox) + (get_list_size) + (get_list_info) + (get_list) ) /** diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index acce2f887b..a7922510e0 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1124,9 +1124,33 @@ namespace golos { namespace wallet { // Private message vector get_inbox( - const std::string& to, const std::string& newest, uint16_t limit, std::uint64_t offset); + const std::string& to, const std::string& newest, uint16_t limit, std::uint32_t offset); vector get_outbox( - const std::string& from, const std::string& newest, uint16_t limit, std::uint64_t offset); + const std::string& from, const std::string& newest, uint16_t limit, std::uint32_t offset); + + /** + * Add/modify contact list + * + * @param owner + * @param contact + * @param type (undefined, pinned, ignore) + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction add_private_contact( + const std::string& owner, const std::string& contact, private_list_type, bool broadcast); + + /** + * Get contact list + * + * @param owner + * @param type (undefined, pinned, ignore) + * @param limit + * @param offset + * @return the signed version of the transaction + */ + vector get_private_list( + const std::string& owner, private_list_type type, uint16_t limit, uint32_t offset); /** * Send an encrypted private message from one account to other @@ -1258,6 +1282,8 @@ FC_API( golos::wallet::wallet_api, (get_transaction) (get_inbox) (get_outbox) + (get_private_list) + (add_private_contact) (send_private_message) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 764f67d457..85fb672ff0 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2517,7 +2517,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } vector wallet_api::get_inbox( - const std::string& to, const std::string& newest_str, uint16_t limit, std::uint64_t offset + const std::string& to, const std::string& newest_str, uint16_t limit, std::uint32_t offset ) { FC_ASSERT(!is_locked()); std::vector result; @@ -2533,7 +2533,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } vector wallet_api::get_outbox( - const std::string& from, const std::string& newest_str, uint16_t limit, std::uint64_t offset + const std::string& from, const std::string& newest_str, uint16_t limit, std::uint32_t offset ) { FC_ASSERT(!is_locked()); std::vector result; @@ -2548,9 +2548,42 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return result; } + annotated_signed_transaction wallet_api::add_private_contact( + const std::string& owner, const std::string& contact, private_list_type type, bool broadcast + ) { + FC_ASSERT(!is_locked()); + + private_list_operation op; + + op.owner = owner; + op.contact = contact; + op.type = type; + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(owner); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + + vector wallet_api::get_private_list( + const std::string& owner, private_list_type type, uint16_t limit, uint32_t offset + ) { + return my->_remote_private_message->get_list(owner, type, limit, offset); + } + annotated_signed_transaction wallet_api::send_private_message( const std::string& from, const std::string& to, const message_body& message, bool broadcast ) { + FC_ASSERT(!is_locked()); + auto from_account = get_account(from); auto to_account = get_account(to); auto shared_secret = my->get_private_key(from_account.memo_key).get_shared_secret(to_account.memo_key); From 1606fb5605d4c73442322cf73acd582779dc474a Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Mon, 23 Jul 2018 18:43:33 +0700 Subject: [PATCH 161/250] Add ignore list logic. #805 --- plugins/private_message/private_message_plugin.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 5c36629b63..47b65e356b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -171,8 +171,13 @@ namespace golos { namespace plugins { namespace private_message { return; } + auto& idx = d.get_index().indices().get(); + auto gitr = idx.find(std::make_tuple(pm.to, pm.from)); + GOLOS_CHECK_OP_PARAM(pm, to, { - GOLOS_CHECK_VALUE(d.find_account(pm.to) != nullptr, "Account doesn't exist"); + d.get_account(pm.to); + // TODO: fix exception type + GOLOS_CHECK_VALUE(gitr == idx.end() || gitr->type != ignored, "Sender is in ignored list of receiver"); }); d.create([&](message_object& pmo) { @@ -192,7 +197,6 @@ namespace golos { namespace plugins { namespace private_message { // Ok, now update contact lists and counters in them - auto& idx = d.get_index().indices().get(); auto& sidx = d.get_index().indices().get(); // Increment counters depends on side of communication From 81788eb34c070bd274109315041cedf71d1a429c Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Mon, 23 Jul 2018 23:03:27 +0700 Subject: [PATCH 162/250] Add json_metadata to private lists. #805 --- .../wallet/include/golos/wallet/wallet.hpp | 4 +- libraries/wallet/wallet.cpp | 12 ++- .../private_message_objects.hpp | 13 ++- .../private_message_objects.cpp | 11 +- .../private_message_plugin.cpp | 102 +++++++++--------- 5 files changed, 85 insertions(+), 57 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index a7922510e0..761a0fe5b4 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1134,11 +1134,13 @@ namespace golos { namespace wallet { * @param owner * @param contact * @param type (undefined, pinned, ignore) + * @param json_metadata * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ annotated_signed_transaction add_private_contact( - const std::string& owner, const std::string& contact, private_list_type, bool broadcast); + const std::string& owner, const std::string& contact, private_list_type, + fc::optional json_metadata, bool broadcast); /** * Get contact list diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 85fb672ff0..d118c33266 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2549,9 +2549,11 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::add_private_contact( - const std::string& owner, const std::string& contact, private_list_type type, bool broadcast + const std::string& owner, const std::string& contact, + private_list_type type, fc::optional json_metadata, bool broadcast ) { FC_ASSERT(!is_locked()); + FC_ASSERT(type != golos::plugins::private_message::undefined || !json_metadata); private_list_operation op; @@ -2559,6 +2561,14 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.contact = contact; op.type = type; + if (type == golos::plugins::private_message::undefined) { + // op.json_metadata.clear(); + } else if (!json_metadata) { + op.json_metadata = my->_remote_private_message->get_list_info(owner, contact).json_metadata; + } else { + op.json_metadata = *json_metadata; + } + private_message_plugin_operation pop = op; custom_json_operation jop; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 4a1637e895..448d2e885d 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -122,7 +122,7 @@ namespace golos { namespace plugins { namespace private_message { class list_object: public object { public: template - list_object(Constructor&& c, allocator a) { + list_object(Constructor&& c, allocator a): json_metadata(a) { c(*this); } @@ -131,6 +131,7 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; account_name_type contact; private_list_type type; + shared_string json_metadata; uint32_t total_send_messages = 0; uint32_t unread_send_messages = 0; uint32_t total_recv_messages = 0; @@ -145,8 +146,9 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; account_name_type contact; - private_list_type owner_type = undefined; - private_list_type contact_type = undefined; + std::string json_metadata; + private_list_type local_type = undefined; + private_list_type remote_type = undefined; uint32_t total_send_messages = 0; uint32_t unread_send_messages = 0; uint32_t total_recv_messages = 0; @@ -233,6 +235,7 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; account_name_type contact; private_list_type type; + std::string json_metadata; void validate() const; void get_required_posting_authorities(flat_set& a) const; @@ -267,7 +270,7 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::list_api_object), - (owner)(contact)(owner_type)(contact_type) + (owner)(contact)(json_metadata)(local_type)(remote_type) (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) FC_REFLECT( @@ -280,7 +283,7 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::private_list_operation), - (owner)(contact)(type)) + (owner)(contact)(type)(json_metadata)) FC_REFLECT_TYPENAME((golos::plugins::private_message::private_message_plugin_operation)) diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_objects.cpp index 2098d10e60..0e3afc1672 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_objects.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace golos { namespace plugins { namespace private_message { @@ -26,7 +27,8 @@ namespace golos { namespace plugins { namespace private_message { list_api_object::list_api_object(const list_object& o) : owner(o.owner), contact(o.contact), - owner_type(o.type), + json_metadata(o.json_metadata.begin(), o.json_metadata.end()), + local_type(o.type), total_send_messages(o.total_send_messages), unread_send_messages(o.unread_send_messages), total_recv_messages(o.total_recv_messages), @@ -89,6 +91,13 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_PARAM(type, { GOLOS_CHECK_VALUE(is_valid_list_type(type), "Unknown list type"); }); + + if (json_metadata.size() > 0) { + GOLOS_CHECK_PARAM(json_metadata, { + GOLOS_CHECK_VALUE(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); + GOLOS_CHECK_VALUE(type != undefined, "JSON Metadata can't be set for undefined contact"); + }); + } } void private_list_operation::get_required_posting_authorities(flat_set& a) const { diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 47b65e356b..0f3687b4a8 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -45,6 +45,8 @@ namespace golos { namespace plugins { namespace private_message { std::vector get_outbox( const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; + list_api_object get_list_item(const list_object& o) const; + list_api_object get_list_info(const std::string& owner, const std::string& contact) const; list_size_api_object get_list_size(const std::string& owner) const; @@ -101,6 +103,19 @@ namespace golos { namespace plugins { namespace private_message { return result; } + list_api_object private_message_plugin::private_message_plugin_impl::get_list_item(const list_object& o) const { + list_api_object result(o); + + const auto& idx = db_.get_index().indices().get(); + auto ritr = idx.find(std::make_tuple(o.contact, o.owner)); + + if (idx.end() != ritr) { + result.remote_type = ritr->type; + } + + return result; + } + list_api_object private_message_plugin::private_message_plugin_impl::get_list_info( const std::string& owner, const std::string& contact ) const { @@ -108,12 +123,7 @@ namespace golos { namespace plugins { namespace private_message { auto itr = idx.find(std::make_tuple(owner, contact)); if (itr != idx.end()) { - list_api_object result(*itr); - auto ritr = idx.find(std::make_tuple(contact, owner)); - if (idx.end() != ritr) { - result.contact_type = ritr->type; - } - return result; + return get_list_item(*itr); } return list_api_object(); } @@ -147,19 +157,13 @@ namespace golos { namespace plugins { namespace private_message { result.reserve(limit); const auto& idx = db_.get_index().indices().get(); - const auto& ridx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(owner, type)); auto etr = idx.upper_bound(std::make_tuple(owner, type)); for (; itr != etr && offset; ++itr, --offset); for (; itr != etr; ++itr) { - result.emplace_back(*itr); - - auto ritr = ridx.find(std::make_tuple(itr->contact, itr->owner)); - if (ritr != ridx.end()) { - result.back().contact_type = ritr->type; - } + result.push_back(get_list_item(*itr)); } return result; } @@ -277,51 +281,50 @@ namespace golos { namespace plugins { namespace private_message { auto ditr = sidx.find(std::make_tuple(pl.owner, pl.type)); if (idx.end() != itr) { - GOLOS_CHECK_OP_PARAM(pl, type, { - GOLOS_CHECK_VALUE(pl.type != itr->type, "Contact already has requested type"); - }); - auto sitr = sidx.find(std::make_tuple(pl.owner, itr->type)); + if (itr->type != pl.type) { + // last contact + if (sitr->info.total_contacts == 1) { + d.remove(*sitr); + } else { + d.modify(*sitr, [&](list_size_object& src) { + src.info.total_contacts--; + src.info.total_send_messages -= itr->total_send_messages; + src.info.unread_send_messages -= itr->unread_send_messages; + src.info.total_recv_messages -= itr->total_recv_messages; + src.info.unread_recv_messages -= itr->unread_recv_messages; + }); + } - d.modify(*sitr, [&](list_size_object& src) { - src.info.total_contacts--; - src.info.total_send_messages -= itr->total_send_messages; - src.info.unread_send_messages -= itr->unread_send_messages; - src.info.total_recv_messages -= itr->total_recv_messages; - src.info.unread_recv_messages -= itr->unread_recv_messages; - }); - - // if contact is undefined and no messages then remove statistic about it - if (!sitr->info.total_contacts || - (sitr->type == undefined && !sitr->info.total_send_messages && !sitr->info.total_recv_messages) - ) { - d.remove(*sitr); - } - - auto modify_counters = [&](list_size_object& dst) { - dst.info.total_contacts++; - dst.info.total_send_messages += itr->total_send_messages; - dst.info.unread_send_messages += itr->unread_send_messages; - dst.info.total_recv_messages += itr->total_recv_messages; - dst.info.unread_recv_messages += itr->unread_recv_messages; - }; - - if (sidx.end() == ditr) { - d.create([&](list_size_object& dst) { - dst.owner = pl.owner; - dst.type = pl.type; - modify_counters(dst); - }); - } else { - d.modify(*ditr, modify_counters); + // has messages or type is not undefined + if (itr->total_send_messages || itr->total_recv_messages || pl.type != undefined) { + auto modify_counters = [&](list_size_object& dst) { + dst.info.total_contacts++; + dst.info.total_send_messages += itr->total_send_messages; + dst.info.unread_send_messages += itr->unread_send_messages; + dst.info.total_recv_messages += itr->total_recv_messages; + dst.info.unread_recv_messages += itr->unread_recv_messages; + }; + + if (sidx.end() == ditr) { + d.create([&](list_size_object& dst) { + dst.owner = pl.owner; + dst.type = pl.type; + modify_counters(dst); + }); + } else { + d.modify(*ditr, modify_counters); + } + } } - // if contact is undefined and no messages then remove it + // contact is undefined and no messages if (pl.type == undefined && !itr->total_send_messages && !itr->total_recv_messages) { d.remove(*itr); } else { d.modify(*itr, [&](list_object& plo) { plo.type = pl.type; + from_string(plo.json_metadata, pl.json_metadata); }); } } else if (pl.type != undefined) { @@ -329,6 +332,7 @@ namespace golos { namespace plugins { namespace private_message { plo.owner = pl.owner; plo.contact = pl.contact; plo.type = pl.type; + from_string(plo.json_metadata, pl.json_metadata); }); if (sidx.end() == ditr) { From 9f38b46631d2282c48b98047746fbbe3a7c27589 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 24 Jul 2018 13:04:13 +0700 Subject: [PATCH 163/250] Small refactor. #805 --- libraries/wallet/wallet.cpp | 4 +- .../private_message_evaluators.hpp | 28 ++++++- .../private_message_objects.hpp | 82 +++++++++++++------ .../private_message_objects.cpp | 11 +-- .../private_message_plugin.cpp | 69 +++++++++------- 5 files changed, 125 insertions(+), 69 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d118c33266..acf70bcf23 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2613,7 +2613,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.from_memo_key = from_account.memo_key; op.to = to; op.to_memo_key = to_account.memo_key; - op.sent_time = sent_time; + op.nonce = sent_time; op.encrypted_message = fc::aes_encrypt(encrypt_key, msg_data); op.checksum = fc::sha256::hash(encrypt_key)._hash[0]; @@ -2657,7 +2657,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } fc::sha512::encoder enc; - fc::raw::pack(enc, mo.sent_time); + fc::raw::pack(enc, mo.nonce); fc::raw::pack(enc, shared_secret); auto encrypt_key = enc.result(); diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index de7b4d90e2..e55c2168e5 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -7,14 +7,16 @@ namespace golos { namespace plugins { namespace private_message { + using golos::chain::evaluator_impl; + class private_message_evaluator: - public golos::chain::evaluator_impl + public evaluator_impl { public: using operation_type = private_message_operation; private_message_evaluator(database& db, private_message_plugin* plugin) - : golos::chain::evaluator_impl(db), + : evaluator_impl(db), plugin_(plugin) {} @@ -23,14 +25,30 @@ namespace golos { namespace plugins { namespace private_message { private_message_plugin* plugin_; }; + class private_settings_evaluator: + public evaluator_impl + { + public: + using operation_type = private_list_operation; + + private_settings_evaluator(database& db, private_message_plugin* plugin) + : evaluator_impl(db), + plugin_(plugin) + {} + + void do_apply(const private_list_operation& o); + + private_message_plugin* plugin_; + }; + class private_list_evaluator: - public golos::chain::evaluator_impl + public evaluator_impl { public: using operation_type = private_list_operation; private_list_evaluator(database& db, private_message_plugin* plugin) - : golos::chain::evaluator_impl(db), + : evaluator_impl(db), plugin_(plugin) {} @@ -38,4 +56,6 @@ namespace golos { namespace plugins { namespace private_message { private_message_plugin* plugin_; }; + + } } } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 448d2e885d..f19aff3a96 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -27,6 +27,9 @@ namespace golos { namespace plugins { namespace private_message { list_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, }; + /** + * Message + */ class message_object: public object { public: template @@ -41,7 +44,7 @@ namespace golos { namespace plugins { namespace private_message { account_name_type to; public_key_type from_memo_key; public_key_type to_memo_key; - uint64_t sent_time = 0; /// used as seed to secret generation + uint64_t nonce = 0; /// used as seed to secret generation time_point_sec receive_time; /// time received by blockchain uint32_t checksum = 0; time_point_sec read_time; @@ -58,7 +61,7 @@ namespace golos { namespace plugins { namespace private_message { account_name_type to; public_key_type from_memo_key; public_key_type to_memo_key; - uint64_t sent_time = 0; + uint64_t nonce = 0; time_point_sec receive_time; uint32_t checksum = 0; time_point_sec read_time; @@ -101,9 +104,9 @@ namespace golos { namespace plugins { namespace private_message { struct private_message_operation: public base_operation { account_name_type from; account_name_type to; + uint64_t nonce = 0; /// used as seed to secret generation public_key_type from_memo_key; public_key_type to_memo_key; - uint64_t sent_time = 0; /// used as seed to secret generation uint32_t checksum = 0; std::vector encrypted_message; @@ -111,6 +114,9 @@ namespace golos { namespace plugins { namespace private_message { void get_required_posting_authorities(flat_set& a) const; }; + /** + * Types of contact list + */ enum private_list_type: uint8_t { undefined = 1, pinned = 2, @@ -119,6 +125,36 @@ namespace golos { namespace plugins { namespace private_message { constexpr auto private_list_type_size = ignored + 1; + struct list_size_info { + fc::safe total_send_messages = 0; + fc::safe unread_send_messages = 0; + fc::safe total_recv_messages = 0; + fc::safe unread_recv_messages = 0; + + bool empty() const { + return !total_send_messages.value && !total_recv_messages.value; + } + + list_size_info& operator-=(const list_size_info& s) { + total_send_messages -= s.total_send_messages; + unread_send_messages -= s.unread_send_messages; + total_recv_messages -= s.total_recv_messages; + unread_recv_messages -= s.unread_send_messages; + return *this; + } + + list_size_info& operator+=(const list_size_info& s) { + total_send_messages += s.total_send_messages; + unread_send_messages += s.unread_send_messages; + total_recv_messages += s.total_recv_messages; + unread_recv_messages += s.unread_send_messages; + return *this; + } + }; + + /** + * Contact item + */ class list_object: public object { public: template @@ -132,10 +168,7 @@ namespace golos { namespace plugins { namespace private_message { account_name_type contact; private_list_type type; shared_string json_metadata; - uint32_t total_send_messages = 0; - uint32_t unread_send_messages = 0; - uint32_t total_recv_messages = 0; - uint32_t unread_recv_messages = 0; + list_size_info size; }; using list_id_type = list_object::id_type; @@ -149,10 +182,7 @@ namespace golos { namespace plugins { namespace private_message { std::string json_metadata; private_list_type local_type = undefined; private_list_type remote_type = undefined; - uint32_t total_send_messages = 0; - uint32_t unread_send_messages = 0; - uint32_t total_recv_messages = 0; - uint32_t unread_recv_messages = 0; + list_size_info size; }; struct by_owner; @@ -186,12 +216,11 @@ namespace golos { namespace plugins { namespace private_message { string_less>>>, allocator>; - struct list_size_info { - uint32_t total_contacts = 0; - uint32_t total_send_messages = 0; - uint32_t unread_send_messages = 0; - uint32_t total_recv_messages = 0; - uint32_t unread_recv_messages = 0; + /** + * + */ + struct contact_list_size_info: public list_size_info { + uint32_t total_contacts; }; struct list_size_object: public object { @@ -204,14 +233,14 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; private_list_type type; - list_size_info info; + contact_list_size_info size; }; using list_size_id_type = list_size_object::id_type; struct list_size_api_object { account_name_type owner; - fc::flat_map info; + fc::flat_map size; }; using list_size_index = multi_index_container< @@ -258,7 +287,7 @@ CHAINBASE_SET_INDEX_TYPE( FC_REFLECT( (golos::plugins::private_message::message_api_object), - (from)(to)(from_memo_key)(to_memo_key)(sent_time)(receive_time)(read_time)(checksum)(encrypted_message)) + (from)(to)(from_memo_key)(to_memo_key)(nonce)(receive_time)(read_time)(checksum)(encrypted_message)) FC_REFLECT_ENUM( golos::plugins::private_message::private_list_type, @@ -266,20 +295,23 @@ FC_REFLECT_ENUM( FC_REFLECT( (golos::plugins::private_message::list_size_info), - (total_contacts)(total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + +FC_REFLECT_DERIVED( + (golos::plugins::private_message::contact_list_size_info), ((golos::plugins::private_message::list_size_info)), + (total_contacts)) FC_REFLECT( (golos::plugins::private_message::list_api_object), - (owner)(contact)(json_metadata)(local_type)(remote_type) - (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + (owner)(contact)(json_metadata)(local_type)(remote_type)(size)) FC_REFLECT( (golos::plugins::private_message::list_size_api_object), - (owner)(info)) + (owner)(size)) FC_REFLECT( (golos::plugins::private_message::private_message_operation), - (from)(to)(from_memo_key)(to_memo_key)(sent_time)(checksum)(encrypted_message)) + (from)(to)(from_memo_key)(to_memo_key)(nonce)(checksum)(encrypted_message)) FC_REFLECT( (golos::plugins::private_message::private_list_operation), diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_objects.cpp index 0e3afc1672..3c698bcc42 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_objects.cpp @@ -15,7 +15,7 @@ namespace golos { namespace plugins { namespace private_message { to(o.to), from_memo_key(o.from_memo_key), to_memo_key(o.to_memo_key), - sent_time(o.sent_time), + nonce(o.nonce), receive_time(o.receive_time), checksum(o.checksum), read_time(o.read_time), @@ -29,10 +29,7 @@ namespace golos { namespace plugins { namespace private_message { contact(o.contact), json_metadata(o.json_metadata.begin(), o.json_metadata.end()), local_type(o.type), - total_send_messages(o.total_send_messages), - unread_send_messages(o.unread_send_messages), - total_recv_messages(o.total_recv_messages), - unread_recv_messages(o.unread_recv_messages) { + size(o.size) { } list_api_object::list_api_object() = default; @@ -54,8 +51,8 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_VALUE(from_memo_key != to_memo_key, "From_key can't be equal to to_key"); }); - GOLOS_CHECK_PARAM(sent_time, { - GOLOS_CHECK_VALUE(sent_time != 0, "Send time can't be zero"); + GOLOS_CHECK_PARAM(nonce, { + GOLOS_CHECK_VALUE(nonce != 0, "Nonce can't be zero"); }); GOLOS_CHECK_PARAM(encrypted_message, { diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 0f3687b4a8..098cc19fb7 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -140,9 +140,9 @@ namespace golos { namespace plugins { namespace private_message { auto t = static_cast(i); auto itr = idx.find(std::make_tuple(owner, t)); if (idx.end() != itr) { - result.info[t] = itr->info; + result.size[t] = itr->size; } else { - result.info[t] = list_size_info(); + result.size[t] = contact_list_size_info(); } } @@ -181,16 +181,16 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); // TODO: fix exception type - GOLOS_CHECK_VALUE(gitr == idx.end() || gitr->type != ignored, "Sender is in ignored list of receiver"); + GOLOS_CHECK_VALUE(gitr == idx.end() || gitr->type != ignored, "Sender is in ignore list of receiver"); }); d.create([&](message_object& pmo) { pmo.from = pm.from; pmo.to = pm.to; + pmo.nonce = pm.nonce; pmo.from_memo_key = pm.from_memo_key; pmo.to_memo_key = pm.to_memo_key; pmo.checksum = pm.checksum; - pmo.sent_time = pm.sent_time; pmo.read_time = time_point_sec::min(); pmo.receive_time = d.head_block_time(); pmo.encrypted_message.resize(pm.encrypted_message.size()); @@ -204,7 +204,7 @@ namespace golos { namespace plugins { namespace private_message { auto& sidx = d.get_index().indices().get(); // Increment counters depends on side of communication - auto modify_counters = [&](auto& o, const bool is_send) { + auto inc_counters = [&](auto& o, const bool is_send) { if (is_send) { o.total_send_messages++; o.unread_send_messages++; @@ -217,10 +217,10 @@ namespace golos { namespace plugins { namespace private_message { // Update global counters by type of contact auto modify_size = [&](auto& owner, auto type, const bool is_new_contact, const bool is_send) { - auto func = [&](list_size_object& plso) { - modify_counters(plso.info, is_send); + auto modify_counters = [&](list_size_object& plso) { + inc_counters(plso.size, is_send); if (is_new_contact) { - plso.info.total_contacts++; + plso.size.total_contacts++; } }; @@ -229,10 +229,10 @@ namespace golos { namespace plugins { namespace private_message { d.create([&](list_size_object& plso){ plso.owner = owner; plso.type = type; - func(plso); + modify_counters(plso); }); } else { - d.modify(*itr, func); + d.modify(*itr, modify_counters); } }; @@ -243,7 +243,7 @@ namespace golos { namespace plugins { namespace private_message { auto itr = idx.find(std::make_tuple(owner, contact)); if (idx.end() != itr) { d.modify(*itr, [&](list_object& plo) { - modify_counters(plo, is_send); + inc_counters(plo.size, is_send); }); is_new_contact = false; type = itr->type; @@ -252,7 +252,7 @@ namespace golos { namespace plugins { namespace private_message { plo.owner = owner; plo.contact = contact; plo.type = type; - modify_counters(plo, is_send); + inc_counters(plo.size, is_send); }); is_new_contact = true; } @@ -270,13 +270,26 @@ namespace golos { namespace plugins { namespace private_message { return; } - GOLOS_CHECK_OP_PARAM(pl, contact, { - GOLOS_CHECK_VALUE(d.find_account(pl.contact) != nullptr, "Account doesn't exist"); - }); - auto& idx = d.get_index().indices().get(); auto itr = idx.find(std::make_tuple(pl.owner, pl.contact)); + GOLOS_CHECK_OP_PARAM(pl, contact, { + d.get_account(pl.contact); + + if (d.is_producing()) { + // TODO: fix exception type + GOLOS_CHECK_VALUE( + idx.end() != itr || pl.type != undefined, + "Can't add undefined contact"); + + // TODO: fix exception type + std::string json_metadata(itr->json_metadata.begin(), itr->json_metadata.end()); + GOLOS_CHECK_VALUE( + itr->type != pl.type || pl.json_metadata != json_metadata, + "Contact has the same type"); + } + }); + auto& sidx = d.get_index().indices().get(); auto ditr = sidx.find(std::make_tuple(pl.owner, pl.type)); @@ -284,26 +297,20 @@ namespace golos { namespace plugins { namespace private_message { auto sitr = sidx.find(std::make_tuple(pl.owner, itr->type)); if (itr->type != pl.type) { // last contact - if (sitr->info.total_contacts == 1) { + if (sitr->size.total_contacts == 1) { d.remove(*sitr); } else { d.modify(*sitr, [&](list_size_object& src) { - src.info.total_contacts--; - src.info.total_send_messages -= itr->total_send_messages; - src.info.unread_send_messages -= itr->unread_send_messages; - src.info.total_recv_messages -= itr->total_recv_messages; - src.info.unread_recv_messages -= itr->unread_recv_messages; + src.size.total_contacts--; + src.size -= itr->size; }); } // has messages or type is not undefined - if (itr->total_send_messages || itr->total_recv_messages || pl.type != undefined) { + if (!itr->size.empty() || pl.type != undefined) { auto modify_counters = [&](list_size_object& dst) { - dst.info.total_contacts++; - dst.info.total_send_messages += itr->total_send_messages; - dst.info.unread_send_messages += itr->unread_send_messages; - dst.info.total_recv_messages += itr->total_recv_messages; - dst.info.unread_recv_messages += itr->unread_recv_messages; + dst.size.total_contacts++; + dst.size += itr->size; }; if (sidx.end() == ditr) { @@ -319,7 +326,7 @@ namespace golos { namespace plugins { namespace private_message { } // contact is undefined and no messages - if (pl.type == undefined && !itr->total_send_messages && !itr->total_recv_messages) { + if (pl.type == undefined && itr->size.empty()) { d.remove(*itr); } else { d.modify(*itr, [&](list_object& plo) { @@ -339,11 +346,11 @@ namespace golos { namespace plugins { namespace private_message { d.create([&](list_size_object& plso) { plso.owner = pl.owner; plso.type = pl.type; - plso.info.total_contacts = 1; + plso.size.total_contacts = 1; }); } else { d.modify(*ditr, [&](list_size_object& plso) { - plso.info.total_contacts++; + plso.size.total_contacts++; }); } } From bc27d6dd4db589975235db3085723857166bd84c Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 24 Jul 2018 18:10:57 +0700 Subject: [PATCH 164/250] Add settings for private messages. #805 --- .../include/golos/wallet/remote_node_api.hpp | 1 + .../wallet/include/golos/wallet/wallet.hpp | 12 +++ libraries/wallet/wallet.cpp | 23 ++++++ .../private_message_evaluators.hpp | 4 +- .../private_message_objects.hpp | 73 ++++++++++++++++--- .../private_message_plugin.hpp | 3 +- .../private_message_objects.cpp | 13 ++++ .../private_message_plugin.cpp | 56 +++++++++++++- 8 files changed, 172 insertions(+), 13 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 52bc992bdc..38acdd4880 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -177,6 +177,7 @@ struct remote_market_history { struct remote_private_message { vector get_inbox(const std::string& to, time_point newest, uint16_t limit, uint32_t offset) const; vector get_outbox(const std::string& from, time_point newest, uint16_t limit, uint32_t offset) const; + settings_api_object get_settings(const std::string& owner) const; list_size_api_object get_list_size(const std::string& owner) const; list_api_object get_list_info(const std::string& owner, const std::string& contact) const; std::vector get_list(const std::string& owner, private_list_type, uint16_t limit, uint32_t offset) const; diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 761a0fe5b4..bb02f4b2d0 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1128,6 +1128,17 @@ namespace golos { namespace wallet { vector get_outbox( const std::string& from, const std::string& newest, uint16_t limit, std::uint32_t offset); + /** + * Change settings for private messages + * + * @param owner + * @param settings + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction set_private_settings( + const std::string& owner, const settings_api_object& s, bool broadcast); + /** * Add/modify contact list * @@ -1284,6 +1295,7 @@ FC_API( golos::wallet::wallet_api, (get_transaction) (get_inbox) (get_outbox) + (set_private_settings) (get_private_list) (add_private_contact) (send_private_message) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index acf70bcf23..7d9d1eed73 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2548,6 +2548,29 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return result; } + annotated_signed_transaction wallet_api::set_private_settings( + const std::string& owner, const settings_api_object& s, bool broadcast + ) { + FC_ASSERT(!is_locked()); + private_settings_operation op; + + op.owner = owner; + op.ignore_messages_from_undefined_contact = s.ignore_messages_from_undefined_contact; + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(owner); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + annotated_signed_transaction wallet_api::add_private_contact( const std::string& owner, const std::string& contact, private_list_type type, fc::optional json_metadata, bool broadcast diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index e55c2168e5..1b3f8d0e96 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -29,14 +29,14 @@ namespace golos { namespace plugins { namespace private_message { public evaluator_impl { public: - using operation_type = private_list_operation; + using operation_type = private_settings_operation; private_settings_evaluator(database& db, private_message_plugin* plugin) : evaluator_impl(db), plugin_(plugin) {} - void do_apply(const private_list_operation& o); + void do_apply(const private_settings_operation& o); private_message_plugin* plugin_; }; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index f19aff3a96..2f8a0d37d9 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -23,8 +23,9 @@ namespace golos { namespace plugins { namespace private_message { enum private_message_object_type { message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8), - list_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 1, - list_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, + settings_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 1, + list_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, + list_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 3, }; /** @@ -70,6 +71,8 @@ namespace golos { namespace plugins { namespace private_message { struct by_to_date; struct by_from_date; + struct by_owner; + struct by_contact; using message_index = multi_index_container< message_object, @@ -114,6 +117,49 @@ namespace golos { namespace plugins { namespace private_message { void get_required_posting_authorities(flat_set& a) const; }; + /** + * Settings + */ + class settings_object: public object { + public: + template + settings_object(Constructor&& c, allocator a) { + c(*this); + } + + id_type id; + + account_name_type owner; + bool ignore_messages_from_undefined_contact = false; + }; + + using settings_id_type = settings_object::id_type; + + struct settings_api_object { + settings_api_object(const settings_object& o); + settings_api_object(); + + bool ignore_messages_from_undefined_contact = false; + }; + + using settings_index = multi_index_container< + settings_object, + indexed_by< + ordered_unique< + tag, + member>, + ordered_unique< + tag, + member>>, + allocator>; + + struct private_settings_operation: public base_operation { + account_name_type owner; + bool ignore_messages_from_undefined_contact = false; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; /** * Types of contact list */ @@ -185,9 +231,6 @@ namespace golos { namespace plugins { namespace private_message { list_size_info size; }; - struct by_owner; - struct by_contact; - using list_index = multi_index_container< list_object, indexed_by< @@ -216,13 +259,13 @@ namespace golos { namespace plugins { namespace private_message { string_less>>>, allocator>; - /** - * - */ struct contact_list_size_info: public list_size_info { uint32_t total_contacts; }; + /** + * Counters for account contact lists + */ struct list_size_object: public object { template list_size_object(Constructor&& c, allocator a) { @@ -272,6 +315,7 @@ namespace golos { namespace plugins { namespace private_message { using private_message_plugin_operation = fc::static_variant< private_message_operation, + private_settings_operation, private_list_operation>; } } } // golos::plugins::private_message @@ -279,6 +323,9 @@ namespace golos { namespace plugins { namespace private_message { CHAINBASE_SET_INDEX_TYPE( golos::plugins::private_message::message_object, golos::plugins::private_message::message_index) +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::private_message::settings_object, golos::plugins::private_message::settings_index) + CHAINBASE_SET_INDEX_TYPE( golos::plugins::private_message::list_object, golos::plugins::private_message::list_index) @@ -289,6 +336,10 @@ FC_REFLECT( (golos::plugins::private_message::message_api_object), (from)(to)(from_memo_key)(to_memo_key)(nonce)(receive_time)(read_time)(checksum)(encrypted_message)) +FC_REFLECT( + (golos::plugins::private_message::settings_api_object), + (ignore_messages_from_undefined_contact)) + FC_REFLECT_ENUM( golos::plugins::private_message::private_list_type, (undefined)(pinned)(ignored)) @@ -311,7 +362,11 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::private_message_operation), - (from)(to)(from_memo_key)(to_memo_key)(nonce)(checksum)(encrypted_message)) + (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(encrypted_message)) + +FC_REFLECT( + (golos::plugins::private_message::private_settings_operation), + (owner)(ignore_messages_from_undefined_contact)) FC_REFLECT( (golos::plugins::private_message::private_list_operation), diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index 56ee3503c6..ae4bef2535 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -18,6 +18,7 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_settings , json_rpc::msg_pack, settings_api_object) DEFINE_API_ARGS(get_list_size, json_rpc::msg_pack, list_size_api_object) DEFINE_API_ARGS(get_list_info, json_rpc::msg_pack, list_api_object) DEFINE_API_ARGS(get_list, json_rpc::msg_pack, std::vector) @@ -49,7 +50,7 @@ namespace golos { namespace plugins { namespace private_message { static const std::string& name(); - DECLARE_API((get_inbox)(get_outbox)(get_list_size)(get_list_info)(get_list)) + DECLARE_API((get_inbox)(get_outbox)(get_settings)(get_list_size)(get_list_info)(get_list)) private: class private_message_plugin_impl; diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_objects.cpp index 3c698bcc42..5430cb3824 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_objects.cpp @@ -24,6 +24,12 @@ namespace golos { namespace plugins { namespace private_message { message_api_object::message_api_object() = default; + settings_api_object::settings_api_object(const settings_object& o) + : ignore_messages_from_undefined_contact(o.ignore_messages_from_undefined_contact) { + } + + settings_api_object::settings_api_object() = default; + list_api_object::list_api_object(const list_object& o) : owner(o.owner), contact(o.contact), @@ -34,6 +40,13 @@ namespace golos { namespace plugins { namespace private_message { list_api_object::list_api_object() = default; + void private_settings_operation::validate() const { + GOLOS_CHECK_PARAM_ACCOUNT(owner); + } + void private_settings_operation::get_required_posting_authorities(flat_set& a) const { + a.insert(owner); + } + void private_message_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(to); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 098cc19fb7..8913205ded 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -34,6 +34,7 @@ namespace golos { namespace plugins { namespace private_message { >(db_); custom_operation_interpreter_->register_evaluator(&plugin); + custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); @@ -45,6 +46,8 @@ namespace golos { namespace plugins { namespace private_message { std::vector get_outbox( const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; + settings_api_object get_settings(const std::string& owner) const; + list_api_object get_list_item(const list_object& o) const; list_api_object get_list_info(const std::string& owner, const std::string& contact) const; @@ -103,6 +106,18 @@ namespace golos { namespace plugins { namespace private_message { return result; } + settings_api_object private_message_plugin::private_message_plugin_impl::get_settings( + const std::string& owner + ) const { + const auto& idx = db_.get_index().indices().get(); + auto itr = idx.find(owner); + if (itr != idx.end()) { + return settings_api_object(*itr); + } + + return settings_api_object(); + } + list_api_object private_message_plugin::private_message_plugin_impl::get_list_item(const list_object& o) const { list_api_object result(o); @@ -178,10 +193,19 @@ namespace golos { namespace plugins { namespace private_message { auto& idx = d.get_index().indices().get(); auto gitr = idx.find(std::make_tuple(pm.to, pm.from)); + auto& tidx = d.get_index().indices().get(); + auto titr = tidx.find(pm.to); + GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); // TODO: fix exception type - GOLOS_CHECK_VALUE(gitr == idx.end() || gitr->type != ignored, "Sender is in ignore list of receiver"); + GOLOS_CHECK_VALUE( + gitr == idx.end() || gitr->type != ignored, + "Sender is in ignore list of receiver"); + // TODO: fix exception type + GOLOS_CHECK_VALUE( + titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, + "Recipient accept messages only from his contact list"); }); d.create([&](message_object& pmo) { @@ -263,6 +287,24 @@ namespace golos { namespace plugins { namespace private_message { modify_contact(pm.to, pm.from, undefined, false); } + void private_settings_evaluator::do_apply(const private_settings_operation& ps) { + database& d = db(); + + auto& idx = d.get_index().indices().get(); + auto itr = idx.find(ps.owner); + + auto set_settings = [&](settings_object& pso) { + pso.owner = ps.owner; + pso.ignore_messages_from_undefined_contact = ps.ignore_messages_from_undefined_contact; + }; + + if (idx.end() != itr) { + d.modify(*itr, set_settings); + } else { + d.create(set_settings); + } + } + void private_list_evaluator::do_apply(const private_list_operation& pl) { database& d = db(); @@ -381,6 +423,7 @@ namespace golos { namespace plugins { namespace private_message { my = std::make_unique(*this); add_plugin_index(my->db_); + add_plugin_index(my->db_); add_plugin_index(my->db_); add_plugin_index(my->db_); @@ -444,6 +487,17 @@ namespace golos { namespace plugins { namespace private_message { }); } + DEFINE_API(private_message_plugin, get_settings) { + GOLOS_CHECK_ARGS_COUNT(args.args, 1) + + auto owner = args.args->at(0).as(); + auto& db = my->db_; + + return db.with_weak_read_lock([&](){ + return my->get_settings(owner); + }); + } + DEFINE_API(private_message_plugin, get_list_size) { GOLOS_CHECK_ARGS_COUNT(args.args, 1) From 4dfff271651d1834b89fc2945f4cc08a8162deb4 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 24 Jul 2018 19:44:11 +0700 Subject: [PATCH 165/250] Rename private list to private contact. #805 --- .../include/golos/wallet/remote_node_api.hpp | 15 +- .../wallet/include/golos/wallet/wallet.hpp | 30 ++- libraries/wallet/wallet.cpp | 22 +- plugins/private_message/CMakeLists.txt | 5 +- .../private_message_api_objects.hpp | 120 +++++++++ .../private_message_evaluators.hpp | 24 +- .../private_message_objects.hpp | 235 +++--------------- .../private_message_operations.hpp | 76 ++++++ .../private_message_plugin.hpp | 25 +- .../private_message_api_objects.cpp | 39 +++ ...cts.cpp => private_message_operations.cpp} | 61 ++--- .../private_message_plugin.cpp | 102 ++++---- 12 files changed, 422 insertions(+), 332 deletions(-) create mode 100644 plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp create mode 100644 plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp create mode 100644 plugins/private_message/private_message_api_objects.cpp rename plugins/private_message/{private_message_objects.cpp => private_message_operations.cpp} (65%) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 38acdd4880..2651656b8d 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -178,9 +178,9 @@ struct remote_private_message { vector get_inbox(const std::string& to, time_point newest, uint16_t limit, uint32_t offset) const; vector get_outbox(const std::string& from, time_point newest, uint16_t limit, uint32_t offset) const; settings_api_object get_settings(const std::string& owner) const; - list_size_api_object get_list_size(const std::string& owner) const; - list_api_object get_list_info(const std::string& owner, const std::string& contact) const; - std::vector get_list(const std::string& owner, private_list_type, uint16_t limit, uint32_t offset) const; + contacts_size_api_object get_contacts_size(const std::string& owner) const; + contact_api_object get_contact_info(const std::string& owner, const std::string& contact) const; + std::vector get_contacts(const std::string& owner, private_contact_type, uint16_t limit, uint32_t offset) const; }; /** @@ -328,9 +328,10 @@ FC_API( golos::wallet::remote_market_history, FC_API( golos::wallet::remote_private_message, (get_inbox) (get_outbox) - (get_list_size) - (get_list_info) - (get_list) + (get_settings) + (get_contacts) + (get_contacts_size) + (get_contact_info) ) /** diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index bb02f4b2d0..54188cef45 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1139,18 +1139,26 @@ namespace golos { namespace wallet { annotated_signed_transaction set_private_settings( const std::string& owner, const settings_api_object& s, bool broadcast); + /** + * Get settings for private messages + * + * @param owner + * @return the settings for private messages + */ + settings_api_object get_private_settings(const std::string& owner); + /** * Add/modify contact list * * @param owner * @param contact - * @param type (undefined, pinned, ignore) + * @param type (undefined - remove it if no messages, pinned, ignore) * @param json_metadata * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ annotated_signed_transaction add_private_contact( - const std::string& owner, const std::string& contact, private_list_type, + const std::string& owner, const std::string& contact, private_contact_type, fc::optional json_metadata, bool broadcast); /** @@ -1160,11 +1168,19 @@ namespace golos { namespace wallet { * @param type (undefined, pinned, ignore) * @param limit * @param offset - * @return the signed version of the transaction + * @return List of contacts */ - vector get_private_list( - const std::string& owner, private_list_type type, uint16_t limit, uint32_t offset); + vector get_private_contacts( + const std::string& owner, private_contact_type type, uint16_t limit, uint32_t offset); + /** + * Get contact info + * + * @param owner + * @param contact + * @return Contact + */ + contact_api_object get_private_contact(const std::string& owner, const std::string& contact); /** * Send an encrypted private message from one account to other * @@ -1296,7 +1312,9 @@ FC_API( golos::wallet::wallet_api, (get_inbox) (get_outbox) (set_private_settings) - (get_private_list) + (get_private_settings) + (get_private_contacts) + (get_private_contact) (add_private_contact) (send_private_message) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 7d9d1eed73..80f53475c2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2571,14 +2571,18 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction(trx, broadcast); } + settings_api_object wallet_api::get_private_settings(const std::string& owner) { + return my->_remote_private_message->get_settings(owner); + } + annotated_signed_transaction wallet_api::add_private_contact( const std::string& owner, const std::string& contact, - private_list_type type, fc::optional json_metadata, bool broadcast + private_contact_type type, fc::optional json_metadata, bool broadcast ) { FC_ASSERT(!is_locked()); FC_ASSERT(type != golos::plugins::private_message::undefined || !json_metadata); - private_list_operation op; + private_contact_operation op; op.owner = owner; op.contact = contact; @@ -2587,7 +2591,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st if (type == golos::plugins::private_message::undefined) { // op.json_metadata.clear(); } else if (!json_metadata) { - op.json_metadata = my->_remote_private_message->get_list_info(owner, contact).json_metadata; + op.json_metadata = my->_remote_private_message->get_contact_info(owner, contact).json_metadata; } else { op.json_metadata = *json_metadata; } @@ -2606,10 +2610,16 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction(trx, broadcast); } - vector wallet_api::get_private_list( - const std::string& owner, private_list_type type, uint16_t limit, uint32_t offset + vector wallet_api::get_private_contacts( + const std::string& owner, private_contact_type type, uint16_t limit, uint32_t offset + ) { + return my->_remote_private_message->get_contacts(owner, type, limit, offset); + } + + contact_api_object wallet_api::get_private_contact( + const std::string& owner, const std::string& contact ) { - return my->_remote_private_message->get_list(owner, type, limit, offset); + return my->_remote_private_message->get_contact_info(owner, contact); } annotated_signed_transaction wallet_api::send_private_message( diff --git a/plugins/private_message/CMakeLists.txt b/plugins/private_message/CMakeLists.txt index fd5daa2af8..40bfcbbd8f 100644 --- a/plugins/private_message/CMakeLists.txt +++ b/plugins/private_message/CMakeLists.txt @@ -2,13 +2,16 @@ set(CURRENT_TARGET private_message) list(APPEND CURRENT_TARGET_HEADERS include/golos/plugins/private_message/private_message_plugin.hpp + include/golos/plugins/private_message/private_message_api_objects.hpp include/golos/plugins/private_message/private_message_objects.hpp + include/golos/plugins/private_message/private_message_operations.hpp include/golos/plugins/private_message/private_message_evaluators.hpp ) list(APPEND CURRENT_TARGET_SOURCES private_message_plugin.cpp - private_message_objects.cpp + private_message_api_objects.cpp + private_message_operations.cpp ) if(BUILD_SHARED_LIBRARIES) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp new file mode 100644 index 0000000000..ac23ef9927 --- /dev/null +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include + +#include + + +namespace golos { namespace plugins { namespace private_message { + + using namespace golos::protocol; + + class message_object; + + struct message_api_object { + message_api_object(const message_object& o); + message_api_object(); + + account_name_type from; + account_name_type to; + uint64_t nonce = 0; + public_key_type from_memo_key; + public_key_type to_memo_key; + time_point_sec receive_time; + uint32_t checksum = 0; + time_point_sec read_time; + std::vector encrypted_message; + }; + + class settings_object; + + struct settings_api_object { + settings_api_object(const settings_object& o); + settings_api_object(); + + bool ignore_messages_from_undefined_contact = false; + }; + + struct contact_size_info { + fc::safe total_send_messages = 0; + fc::safe unread_send_messages = 0; + fc::safe total_recv_messages = 0; + fc::safe unread_recv_messages = 0; + + bool empty() const { + return !total_send_messages.value && !total_recv_messages.value; + } + + contact_size_info& operator-=(const contact_size_info& s) { + total_send_messages -= s.total_send_messages; + unread_send_messages -= s.unread_send_messages; + total_recv_messages -= s.total_recv_messages; + unread_recv_messages -= s.unread_send_messages; + return *this; + } + + contact_size_info& operator+=(const contact_size_info& s) { + total_send_messages += s.total_send_messages; + unread_send_messages += s.unread_send_messages; + total_recv_messages += s.total_recv_messages; + unread_recv_messages += s.unread_send_messages; + return *this; + } + }; + + struct contacts_size_info final: public contact_size_info { + uint32_t total_contacts; + }; + + /** + * Contact item + */ + class contact_object; + + struct contact_api_object { + contact_api_object(const contact_object& o); + contact_api_object(); + + account_name_type owner; + account_name_type contact; + std::string json_metadata; + private_contact_type local_type = undefined; + private_contact_type remote_type = undefined; + contact_size_info size; + }; + + /** + * Counters for account contact lists + */ + struct contact_size_object; + + struct contacts_size_api_object { + fc::flat_map size; + }; + +} } } // golos::plugins::private_message + +FC_REFLECT( + (golos::plugins::private_message::message_api_object), + (from)(to)(from_memo_key)(to_memo_key)(nonce)(receive_time)(read_time)(checksum)(encrypted_message)) + +FC_REFLECT( + (golos::plugins::private_message::settings_api_object), + (ignore_messages_from_undefined_contact)) + +FC_REFLECT( + (golos::plugins::private_message::contact_size_info), + (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + +FC_REFLECT_DERIVED( + (golos::plugins::private_message::contacts_size_info), ((golos::plugins::private_message::contact_size_info)), + (total_contacts)) + +FC_REFLECT( + (golos::plugins::private_message::contact_api_object), + (contact)(json_metadata)(local_type)(remote_type)(size)) + +FC_REFLECT( + (golos::plugins::private_message::contacts_size_api_object), + (size)) + diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index 1b3f8d0e96..7c245fdcf9 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -1,13 +1,18 @@ #pragma once -#include -#include -#include +#include #include +namespace golos { namespace chain { + class database; +} } // golos::chain + namespace golos { namespace plugins { namespace private_message { + class private_message_plugin; + using golos::chain::evaluator_impl; + using golos::chain::database; class private_message_evaluator: public evaluator_impl @@ -41,21 +46,20 @@ namespace golos { namespace plugins { namespace private_message { private_message_plugin* plugin_; }; - class private_list_evaluator: - public evaluator_impl + class private_contact_evaluator: + public evaluator_impl { public: - using operation_type = private_list_operation; + using operation_type = private_contact_operation; - private_list_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), + private_contact_evaluator(database& db, private_message_plugin* plugin) + : evaluator_impl(db), plugin_(plugin) {} - void do_apply(const private_list_operation& o); + void do_apply(const private_contact_operation& o); private_message_plugin* plugin_; }; - } } } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 2f8a0d37d9..b48bcb67c8 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -4,11 +4,8 @@ #include #include #include -#include -#include -#include -#include +#include namespace golos { namespace plugins { namespace private_message { @@ -24,8 +21,8 @@ namespace golos { namespace plugins { namespace private_message { enum private_message_object_type { message_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8), settings_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 1, - list_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, - list_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 3, + contact_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 2, + contact_size_object_type = (PRIVATE_MESSAGE_SPACE_ID << 8) + 3, }; /** @@ -43,9 +40,9 @@ namespace golos { namespace plugins { namespace private_message { account_name_type from; account_name_type to; + uint64_t nonce = 0; /// used as seed to secret generation public_key_type from_memo_key; public_key_type to_memo_key; - uint64_t nonce = 0; /// used as seed to secret generation time_point_sec receive_time; /// time received by blockchain uint32_t checksum = 0; time_point_sec read_time; @@ -54,21 +51,6 @@ namespace golos { namespace plugins { namespace private_message { using message_id_type = message_object::id_type; - struct message_api_object { - message_api_object(const message_object& o); - message_api_object(); - - account_name_type from; - account_name_type to; - public_key_type from_memo_key; - public_key_type to_memo_key; - uint64_t nonce = 0; - time_point_sec receive_time; - uint32_t checksum = 0; - time_point_sec read_time; - std::vector encrypted_message; - }; - struct by_to_date; struct by_from_date; struct by_owner; @@ -104,19 +86,6 @@ namespace golos { namespace plugins { namespace private_message { std::less>>>, allocator>; - struct private_message_operation: public base_operation { - account_name_type from; - account_name_type to; - uint64_t nonce = 0; /// used as seed to secret generation - public_key_type from_memo_key; - public_key_type to_memo_key; - uint32_t checksum = 0; - std::vector encrypted_message; - - void validate() const; - void get_required_posting_authorities(flat_set& a) const; - }; - /** * Settings */ @@ -135,13 +104,6 @@ namespace golos { namespace plugins { namespace private_message { using settings_id_type = settings_object::id_type; - struct settings_api_object { - settings_api_object(const settings_object& o); - settings_api_object(); - - bool ignore_messages_from_undefined_contact = false; - }; - using settings_index = multi_index_container< settings_object, indexed_by< @@ -153,58 +115,13 @@ namespace golos { namespace plugins { namespace private_message { member>>, allocator>; - struct private_settings_operation: public base_operation { - account_name_type owner; - bool ignore_messages_from_undefined_contact = false; - - void validate() const; - void get_required_posting_authorities(flat_set& a) const; - }; - /** - * Types of contact list - */ - enum private_list_type: uint8_t { - undefined = 1, - pinned = 2, - ignored = 3, - }; - - constexpr auto private_list_type_size = ignored + 1; - - struct list_size_info { - fc::safe total_send_messages = 0; - fc::safe unread_send_messages = 0; - fc::safe total_recv_messages = 0; - fc::safe unread_recv_messages = 0; - - bool empty() const { - return !total_send_messages.value && !total_recv_messages.value; - } - - list_size_info& operator-=(const list_size_info& s) { - total_send_messages -= s.total_send_messages; - unread_send_messages -= s.unread_send_messages; - total_recv_messages -= s.total_recv_messages; - unread_recv_messages -= s.unread_send_messages; - return *this; - } - - list_size_info& operator+=(const list_size_info& s) { - total_send_messages += s.total_send_messages; - unread_send_messages += s.unread_send_messages; - total_recv_messages += s.total_recv_messages; - unread_recv_messages += s.unread_send_messages; - return *this; - } - }; - /** * Contact item */ - class list_object: public object { + class contact_object: public object { public: template - list_object(Constructor&& c, allocator a): json_metadata(a) { + contact_object(Constructor&& c, allocator a): json_metadata(a) { c(*this); } @@ -212,111 +129,75 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; account_name_type contact; - private_list_type type; + private_contact_type type; shared_string json_metadata; - list_size_info size; + contact_size_info size; }; - using list_id_type = list_object::id_type; - - struct list_api_object { - list_api_object(const list_object& o); - list_api_object(); + using contact_id_type = contact_object::id_type; - account_name_type owner; - account_name_type contact; - std::string json_metadata; - private_list_type local_type = undefined; - private_list_type remote_type = undefined; - list_size_info size; - }; - - using list_index = multi_index_container< - list_object, + using contact_index = multi_index_container< + contact_object, indexed_by< ordered_unique< tag, - member>, + member>, ordered_unique< tag, composite_key< - list_object, - member, - member, - member>, + contact_object, + member, + member, + member>, composite_key_compare< string_less, - std::greater, + std::greater, string_less>>, ordered_unique< tag, composite_key< - list_object, - member, - member>, + contact_object, + member, + member>, composite_key_compare< string_less, string_less>>>, - allocator>; - - struct contact_list_size_info: public list_size_info { - uint32_t total_contacts; - }; + allocator>; /** * Counters for account contact lists */ - struct list_size_object: public object { + struct contact_size_object: public object { template - list_size_object(Constructor&& c, allocator a) { + contact_size_object(Constructor&& c, allocator a) { c(*this); } id_type id; account_name_type owner; - private_list_type type; - contact_list_size_info size; + private_contact_type type; + contacts_size_info size; }; - using list_size_id_type = list_size_object::id_type; + using contact_size_id_type = contact_size_object::id_type; - struct list_size_api_object { - account_name_type owner; - fc::flat_map size; - }; - - using list_size_index = multi_index_container< - list_size_object, + using contact_size_index = multi_index_container< + contact_size_object, indexed_by< ordered_unique< tag, - member>, + member>, ordered_unique< tag, composite_key< - list_size_object, - member, - member>, + contact_size_object, + member, + member>, composite_key_compare< string_less, - std::less>>>, - allocator>; - - struct private_list_operation: public base_operation { - account_name_type owner; - account_name_type contact; - private_list_type type; - std::string json_metadata; - - void validate() const; - void get_required_posting_authorities(flat_set& a) const; - }; - - using private_message_plugin_operation = fc::static_variant< - private_message_operation, - private_settings_operation, - private_list_operation>; + std::less>>>, + allocator>; } } } // golos::plugins::private_message @@ -327,51 +208,7 @@ CHAINBASE_SET_INDEX_TYPE( golos::plugins::private_message::settings_object, golos::plugins::private_message::settings_index) CHAINBASE_SET_INDEX_TYPE( - golos::plugins::private_message::list_object, golos::plugins::private_message::list_index) + golos::plugins::private_message::contact_object, golos::plugins::private_message::contact_index) CHAINBASE_SET_INDEX_TYPE( - golos::plugins::private_message::list_size_object, golos::plugins::private_message::list_size_index) - -FC_REFLECT( - (golos::plugins::private_message::message_api_object), - (from)(to)(from_memo_key)(to_memo_key)(nonce)(receive_time)(read_time)(checksum)(encrypted_message)) - -FC_REFLECT( - (golos::plugins::private_message::settings_api_object), - (ignore_messages_from_undefined_contact)) - -FC_REFLECT_ENUM( - golos::plugins::private_message::private_list_type, - (undefined)(pinned)(ignored)) - -FC_REFLECT( - (golos::plugins::private_message::list_size_info), - (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) - -FC_REFLECT_DERIVED( - (golos::plugins::private_message::contact_list_size_info), ((golos::plugins::private_message::list_size_info)), - (total_contacts)) - -FC_REFLECT( - (golos::plugins::private_message::list_api_object), - (owner)(contact)(json_metadata)(local_type)(remote_type)(size)) - -FC_REFLECT( - (golos::plugins::private_message::list_size_api_object), - (owner)(size)) - -FC_REFLECT( - (golos::plugins::private_message::private_message_operation), - (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(encrypted_message)) - -FC_REFLECT( - (golos::plugins::private_message::private_settings_operation), - (owner)(ignore_messages_from_undefined_contact)) - -FC_REFLECT( - (golos::plugins::private_message::private_list_operation), - (owner)(contact)(type)(json_metadata)) - -FC_REFLECT_TYPENAME((golos::plugins::private_message::private_message_plugin_operation)) - -DECLARE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation) \ No newline at end of file + golos::plugins::private_message::contact_size_object, golos::plugins::private_message::contact_size_index) \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp new file mode 100644 index 0000000000..149390ea72 --- /dev/null +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +namespace golos { namespace plugins { namespace private_message { + using namespace golos::protocol; + + struct private_message_operation: public base_operation { + account_name_type from; + account_name_type to; + uint64_t nonce = 0; /// used as seed to secret generation + public_key_type from_memo_key; + public_key_type to_memo_key; + uint32_t checksum = 0; + std::vector encrypted_message; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + + struct private_settings_operation: public base_operation { + account_name_type owner; + bool ignore_messages_from_undefined_contact = false; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + + /** + * Types of contacts + */ + enum private_contact_type: uint8_t { + undefined = 1, + pinned = 2, + ignored = 3, + }; + + constexpr auto private_contact_type_size = ignored + 1; + + struct private_contact_operation: public base_operation { + account_name_type owner; + account_name_type contact; + private_contact_type type; + std::string json_metadata; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + + using private_message_plugin_operation = fc::static_variant< + private_message_operation, + private_settings_operation, + private_contact_operation>; + +} } } // golos::plugins::private_message + +FC_REFLECT( + (golos::plugins::private_message::private_message_operation), + (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(encrypted_message)) + +FC_REFLECT( + (golos::plugins::private_message::private_settings_operation), + (owner)(ignore_messages_from_undefined_contact)) + +FC_REFLECT_ENUM( + golos::plugins::private_message::private_contact_type, + (undefined)(pinned)(ignored)) + +FC_REFLECT( + (golos::plugins::private_message::private_contact_operation), + (owner)(contact)(type)(json_metadata)) + +FC_REFLECT_TYPENAME((golos::plugins::private_message::private_message_plugin_operation)) + +DECLARE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation) \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index ae4bef2535..23716551c5 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -1,6 +1,6 @@ #pragma once -#include - +#include +#include #include #include @@ -16,12 +16,12 @@ namespace golos { namespace plugins { namespace private_message { using namespace golos::chain; - DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) - DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) - DEFINE_API_ARGS(get_settings , json_rpc::msg_pack, settings_api_object) - DEFINE_API_ARGS(get_list_size, json_rpc::msg_pack, list_size_api_object) - DEFINE_API_ARGS(get_list_info, json_rpc::msg_pack, list_api_object) - DEFINE_API_ARGS(get_list, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_settings , json_rpc::msg_pack, settings_api_object) + DEFINE_API_ARGS(get_contact_info, json_rpc::msg_pack, contact_api_object) + DEFINE_API_ARGS(get_contacts_size, json_rpc::msg_pack, contacts_size_api_object) + DEFINE_API_ARGS(get_contacts, json_rpc::msg_pack, std::vector) /** * This plugin scans the blockchain for custom operations containing a valid message and authorized @@ -50,7 +50,14 @@ namespace golos { namespace plugins { namespace private_message { static const std::string& name(); - DECLARE_API((get_inbox)(get_outbox)(get_settings)(get_list_size)(get_list_info)(get_list)) + DECLARE_API( + (get_inbox) + (get_outbox) + (get_settings) + (get_contact_info) + (get_contacts_size) + (get_contacts) + ) private: class private_message_plugin_impl; diff --git a/plugins/private_message/private_message_api_objects.cpp b/plugins/private_message/private_message_api_objects.cpp new file mode 100644 index 0000000000..a4f3cee137 --- /dev/null +++ b/plugins/private_message/private_message_api_objects.cpp @@ -0,0 +1,39 @@ +#include +#include + +namespace golos { namespace plugins { namespace private_message { + + message_api_object::message_api_object(const message_object& o) + : from(o.from), + to(o.to), + nonce(o.nonce), + from_memo_key(o.from_memo_key), + to_memo_key(o.to_memo_key), + receive_time(o.receive_time), + checksum(o.checksum), + read_time(o.read_time), + encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { + } + + message_api_object::message_api_object() = default; + + + settings_api_object::settings_api_object(const settings_object& o) + : ignore_messages_from_undefined_contact(o.ignore_messages_from_undefined_contact) { + } + + settings_api_object::settings_api_object() = default; + + + contact_api_object::contact_api_object(const contact_object& o) + : contact(o.contact), + json_metadata(o.json_metadata.begin(), o.json_metadata.end()), + local_type(o.type), + size(o.size) { + } + + contact_api_object::contact_api_object() = default; + +} } } // golos::plugins::private_message + + diff --git a/plugins/private_message/private_message_objects.cpp b/plugins/private_message/private_message_operations.cpp similarity index 65% rename from plugins/private_message/private_message_objects.cpp rename to plugins/private_message/private_message_operations.cpp index 5430cb3824..6639b58942 100644 --- a/plugins/private_message/private_message_objects.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -10,36 +10,19 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } - message_api_object::message_api_object(const message_object& o) - : from(o.from), - to(o.to), - from_memo_key(o.from_memo_key), - to_memo_key(o.to_memo_key), - nonce(o.nonce), - receive_time(o.receive_time), - checksum(o.checksum), - read_time(o.read_time), - encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { - } - - message_api_object::message_api_object() = default; - - settings_api_object::settings_api_object(const settings_object& o) - : ignore_messages_from_undefined_contact(o.ignore_messages_from_undefined_contact) { - } - - settings_api_object::settings_api_object() = default; + static inline bool is_valid_contact_type(private_contact_type type) { + switch(type) { + case undefined: + case pinned: + case ignored: + return true; - list_api_object::list_api_object(const list_object& o) - : owner(o.owner), - contact(o.contact), - json_metadata(o.json_metadata.begin(), o.json_metadata.end()), - local_type(o.type), - size(o.size) { + default: + break; + } + return false; } - list_api_object::list_api_object() = default; - void private_settings_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(owner); } @@ -47,6 +30,7 @@ namespace golos { namespace plugins { namespace private_message { a.insert(owner); } + void private_message_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(to); @@ -73,24 +57,13 @@ namespace golos { namespace plugins { namespace private_message { }); } + void private_message_operation::get_required_posting_authorities(flat_set& a) const { a.insert(from); } - bool is_valid_list_type(private_list_type type) { - switch(type) { - case undefined: - case pinned: - case ignored: - return true; - - default: - break; - } - return false; - } - void private_list_operation::validate() const { + void private_contact_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(contact); GOLOS_CHECK_PARAM(owner, { @@ -99,7 +72,7 @@ namespace golos { namespace plugins { namespace private_message { }); GOLOS_CHECK_PARAM(type, { - GOLOS_CHECK_VALUE(is_valid_list_type(type), "Unknown list type"); + GOLOS_CHECK_VALUE(is_valid_contact_type(type), "Unknown contact type"); }); if (json_metadata.size() > 0) { @@ -110,10 +83,10 @@ namespace golos { namespace plugins { namespace private_message { } } - void private_list_operation::get_required_posting_authorities(flat_set& a) const { + void private_contact_operation::get_required_posting_authorities(flat_set& a) const { a.insert(owner); } } } } // golos::plugins::private_message -DEFINE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation); +DEFINE_OPERATION_TYPE(golos::plugins::private_message::private_message_plugin_operation); \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 8913205ded..d77b25888d 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -35,7 +36,7 @@ namespace golos { namespace plugins { namespace private_message { custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); - custom_operation_interpreter_->register_evaluator(&plugin); + custom_operation_interpreter_->register_evaluator(&plugin); db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); } @@ -48,14 +49,14 @@ namespace golos { namespace plugins { namespace private_message { settings_api_object get_settings(const std::string& owner) const; - list_api_object get_list_item(const list_object& o) const; + contact_api_object get_contact_item(const contact_object& o) const; - list_api_object get_list_info(const std::string& owner, const std::string& contact) const; + contact_api_object get_contact_info(const std::string& owner, const std::string& contact) const; - list_size_api_object get_list_size(const std::string& owner) const; + contacts_size_api_object get_contacts_size(const std::string& owner) const; - std::vector get_list( - const std::string& owner, const private_list_type type, uint16_t limit, uint32_t offset) const; + std::vector get_contacts( + const std::string& owner, const private_contact_type, uint16_t limit, uint32_t offset) const; ~private_message_plugin_impl() = default; @@ -118,10 +119,12 @@ namespace golos { namespace plugins { namespace private_message { return settings_api_object(); } - list_api_object private_message_plugin::private_message_plugin_impl::get_list_item(const list_object& o) const { - list_api_object result(o); + contact_api_object private_message_plugin::private_message_plugin_impl::get_contact_item( + const contact_object& o + ) const { + contact_api_object result(o); - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto ritr = idx.find(std::make_tuple(o.contact, o.owner)); if (idx.end() != ritr) { @@ -131,54 +134,53 @@ namespace golos { namespace plugins { namespace private_message { return result; } - list_api_object private_message_plugin::private_message_plugin_impl::get_list_info( + contact_api_object private_message_plugin::private_message_plugin_impl::get_contact_info( const std::string& owner, const std::string& contact ) const { - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.find(std::make_tuple(owner, contact)); if (itr != idx.end()) { - return get_list_item(*itr); + return get_contact_item(*itr); } - return list_api_object(); + return contact_api_object(); } - list_size_api_object private_message_plugin::private_message_plugin_impl::get_list_size( + contacts_size_api_object private_message_plugin::private_message_plugin_impl::get_contacts_size( const std::string& owner ) const { - list_size_api_object result; + contacts_size_api_object result; - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); - result.owner = owner; - for (uint8_t i = undefined; i < private_list_type_size; ++i) { - auto t = static_cast(i); + for (uint8_t i = undefined; i < private_contact_type_size; ++i) { + auto t = static_cast(i); auto itr = idx.find(std::make_tuple(owner, t)); if (idx.end() != itr) { result.size[t] = itr->size; } else { - result.size[t] = contact_list_size_info(); + result.size[t] = contacts_size_info(); } } return result; } - std::vector private_message_plugin::private_message_plugin_impl::get_list( - const std::string& owner, const private_list_type type, uint16_t limit, uint32_t offset + std::vector private_message_plugin::private_message_plugin_impl::get_contacts( + const std::string& owner, const private_contact_type type, uint16_t limit, uint32_t offset ) const { - std::vector result; + std::vector result; result.reserve(limit); - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(owner, type)); auto etr = idx.upper_bound(std::make_tuple(owner, type)); for (; itr != etr && offset; ++itr, --offset); for (; itr != etr; ++itr) { - result.push_back(get_list_item(*itr)); + result.push_back(get_contact_item(*itr)); } return result; } @@ -190,7 +192,7 @@ namespace golos { namespace plugins { namespace private_message { return; } - auto& idx = d.get_index().indices().get(); + auto& idx = d.get_index().indices().get(); auto gitr = idx.find(std::make_tuple(pm.to, pm.from)); auto& tidx = d.get_index().indices().get(); @@ -225,7 +227,7 @@ namespace golos { namespace plugins { namespace private_message { // Ok, now update contact lists and counters in them - auto& sidx = d.get_index().indices().get(); + auto& sidx = d.get_index().indices().get(); // Increment counters depends on side of communication auto inc_counters = [&](auto& o, const bool is_send) { @@ -241,7 +243,7 @@ namespace golos { namespace plugins { namespace private_message { // Update global counters by type of contact auto modify_size = [&](auto& owner, auto type, const bool is_new_contact, const bool is_send) { - auto modify_counters = [&](list_size_object& plso) { + auto modify_counters = [&](auto& plso) { inc_counters(plso.size, is_send); if (is_new_contact) { plso.size.total_contacts++; @@ -250,7 +252,7 @@ namespace golos { namespace plugins { namespace private_message { auto itr = sidx.find(std::make_tuple(owner, type)); if (sidx.end() == itr) { - d.create([&](list_size_object& plso){ + d.create([&](auto& plso){ plso.owner = owner; plso.type = type; modify_counters(plso); @@ -266,13 +268,13 @@ namespace golos { namespace plugins { namespace private_message { bool is_new_contact; auto itr = idx.find(std::make_tuple(owner, contact)); if (idx.end() != itr) { - d.modify(*itr, [&](list_object& plo) { + d.modify(*itr, [&](auto& plo) { inc_counters(plo.size, is_send); }); is_new_contact = false; type = itr->type; } else { - d.create([&](list_object& plo) { + d.create([&](auto& plo) { plo.owner = owner; plo.contact = contact; plo.type = type; @@ -305,14 +307,14 @@ namespace golos { namespace plugins { namespace private_message { } } - void private_list_evaluator::do_apply(const private_list_operation& pl) { + void private_contact_evaluator::do_apply(const private_contact_operation& pl) { database& d = db(); if (!plugin_->is_tracked_account(pl.owner) && !plugin_->is_tracked_account(pl.contact)) { return; } - auto& idx = d.get_index().indices().get(); + auto& idx = d.get_index().indices().get(); auto itr = idx.find(std::make_tuple(pl.owner, pl.contact)); GOLOS_CHECK_OP_PARAM(pl, contact, { @@ -332,7 +334,7 @@ namespace golos { namespace plugins { namespace private_message { } }); - auto& sidx = d.get_index().indices().get(); + auto& sidx = d.get_index().indices().get(); auto ditr = sidx.find(std::make_tuple(pl.owner, pl.type)); if (idx.end() != itr) { @@ -342,7 +344,7 @@ namespace golos { namespace plugins { namespace private_message { if (sitr->size.total_contacts == 1) { d.remove(*sitr); } else { - d.modify(*sitr, [&](list_size_object& src) { + d.modify(*sitr, [&](auto& src) { src.size.total_contacts--; src.size -= itr->size; }); @@ -350,13 +352,13 @@ namespace golos { namespace plugins { namespace private_message { // has messages or type is not undefined if (!itr->size.empty() || pl.type != undefined) { - auto modify_counters = [&](list_size_object& dst) { + auto modify_counters = [&](auto& dst) { dst.size.total_contacts++; dst.size += itr->size; }; if (sidx.end() == ditr) { - d.create([&](list_size_object& dst) { + d.create([&](auto& dst) { dst.owner = pl.owner; dst.type = pl.type; modify_counters(dst); @@ -371,13 +373,13 @@ namespace golos { namespace plugins { namespace private_message { if (pl.type == undefined && itr->size.empty()) { d.remove(*itr); } else { - d.modify(*itr, [&](list_object& plo) { + d.modify(*itr, [&](auto& plo) { plo.type = pl.type; from_string(plo.json_metadata, pl.json_metadata); }); } } else if (pl.type != undefined) { - d.create([&](list_object& plo){ + d.create([&](auto& plo){ plo.owner = pl.owner; plo.contact = pl.contact; plo.type = pl.type; @@ -385,13 +387,13 @@ namespace golos { namespace plugins { namespace private_message { }); if (sidx.end() == ditr) { - d.create([&](list_size_object& plso) { + d.create([&](auto& plso) { plso.owner = pl.owner; plso.type = pl.type; plso.size.total_contacts = 1; }); } else { - d.modify(*ditr, [&](list_size_object& plso) { + d.modify(*ditr, [&](auto& plso) { plso.size.total_contacts++; }); } @@ -424,8 +426,8 @@ namespace golos { namespace plugins { namespace private_message { add_plugin_index(my->db_); add_plugin_index(my->db_); - add_plugin_index(my->db_); - add_plugin_index(my->db_); + add_plugin_index(my->db_); + add_plugin_index(my->db_); using pairstring = std::pair; LOAD_VALUE_SET(options, "pm-accounts", my->tracked_accounts_, pairstring); @@ -498,18 +500,18 @@ namespace golos { namespace plugins { namespace private_message { }); } - DEFINE_API(private_message_plugin, get_list_size) { + DEFINE_API(private_message_plugin, get_contacts_size) { GOLOS_CHECK_ARGS_COUNT(args.args, 1) auto owner = args.args->at(0).as(); auto& db = my->db_; return db.with_weak_read_lock([&](){ - return my->get_list_size(owner); + return my->get_contacts_size(owner); }); } - DEFINE_API(private_message_plugin, get_list_info) { + DEFINE_API(private_message_plugin, get_contact_info) { GOLOS_CHECK_ARGS_COUNT(args.args, 2) auto owner = args.args->at(0).as(); @@ -517,15 +519,15 @@ namespace golos { namespace plugins { namespace private_message { auto& db = my->db_; return db.with_weak_read_lock([&](){ - return my->get_list_info(owner, contact); + return my->get_contact_info(owner, contact); }); } - DEFINE_API(private_message_plugin, get_list) { + DEFINE_API(private_message_plugin, get_contacts) { GOLOS_CHECK_ARGS_COUNT(args.args, 4) auto owner = args.args->at(0).as(); - auto type = args.args->at(1).as(); + auto type = args.args->at(1).as(); auto limit = args.args->at(2).as(); auto offset = args.args->at(3).as(); auto& db = my->db_; @@ -533,7 +535,7 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_LIMIT(limit, 100); return db.with_weak_read_lock([&](){ - return my->get_list(owner, type, limit, offset); + return my->get_contacts(owner, type, limit, offset); }); } From bbb9261ab3c99bd21c7d31ba8ac948be41f40c51 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 26 Jul 2018 18:09:47 +0700 Subject: [PATCH 166/250] Small refactor. #805 --- .../private_message_plugin.cpp | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index d77b25888d..c2c4c527c7 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -72,7 +72,7 @@ namespace golos { namespace plugins { namespace private_message { const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset ) const { std::vector result; - const auto &idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(to, newest)); auto etr = idx.upper_bound(std::make_tuple(to, time_point::min())); @@ -92,7 +92,7 @@ namespace golos { namespace plugins { namespace private_message { ) const { std::vector result; - const auto &idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(from, newest)); auto etr = idx.upper_bound(std::make_tuple(from, time_point::min())); @@ -125,10 +125,10 @@ namespace golos { namespace plugins { namespace private_message { contact_api_object result(o); const auto& idx = db_.get_index().indices().get(); - auto ritr = idx.find(std::make_tuple(o.contact, o.owner)); + auto itr = idx.find(std::make_tuple(o.contact, o.owner)); - if (idx.end() != ritr) { - result.remote_type = ritr->type; + if (idx.end() != itr) { + result.remote_type = itr->type; } return result; @@ -314,8 +314,8 @@ namespace golos { namespace plugins { namespace private_message { return; } - auto& idx = d.get_index().indices().get(); - auto itr = idx.find(std::make_tuple(pl.owner, pl.contact)); + auto& contact_idx = d.get_index().indices().get(); + auto contact_itr = contact_idx.find(std::make_tuple(pl.owner, pl.contact)); GOLOS_CHECK_OP_PARAM(pl, contact, { d.get_account(pl.contact); @@ -323,57 +323,57 @@ namespace golos { namespace plugins { namespace private_message { if (d.is_producing()) { // TODO: fix exception type GOLOS_CHECK_VALUE( - idx.end() != itr || pl.type != undefined, + contact_idx.end() != contact_itr || pl.type != undefined, "Can't add undefined contact"); // TODO: fix exception type - std::string json_metadata(itr->json_metadata.begin(), itr->json_metadata.end()); + std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); GOLOS_CHECK_VALUE( - itr->type != pl.type || pl.json_metadata != json_metadata, + contact_itr->type != pl.type || pl.json_metadata != json_metadata, "Contact has the same type"); } }); - auto& sidx = d.get_index().indices().get(); - auto ditr = sidx.find(std::make_tuple(pl.owner, pl.type)); + auto& owner_idx = d.get_index().indices().get(); + auto dst_itr = owner_idx.find(std::make_tuple(pl.owner, pl.type)); - if (idx.end() != itr) { - auto sitr = sidx.find(std::make_tuple(pl.owner, itr->type)); - if (itr->type != pl.type) { + if (contact_idx.end() != contact_itr) { + auto src_itr = owner_idx.find(std::make_tuple(pl.owner, contact_itr->type)); + if (contact_itr->type != pl.type) { // last contact - if (sitr->size.total_contacts == 1) { - d.remove(*sitr); + if (src_itr->size.total_contacts == 1) { + d.remove(*src_itr); } else { - d.modify(*sitr, [&](auto& src) { + d.modify(*src_itr, [&](auto& src) { src.size.total_contacts--; - src.size -= itr->size; + src.size -= contact_itr->size; }); } // has messages or type is not undefined - if (!itr->size.empty() || pl.type != undefined) { + if (!contact_itr->size.empty() || pl.type != undefined) { auto modify_counters = [&](auto& dst) { dst.size.total_contacts++; - dst.size += itr->size; + dst.size += contact_itr->size; }; - if (sidx.end() == ditr) { + if (owner_idx.end() == dst_itr) { d.create([&](auto& dst) { dst.owner = pl.owner; dst.type = pl.type; modify_counters(dst); }); } else { - d.modify(*ditr, modify_counters); + d.modify(*dst_itr, modify_counters); } } } // contact is undefined and no messages - if (pl.type == undefined && itr->size.empty()) { - d.remove(*itr); + if (pl.type == undefined && contact_itr->size.empty()) { + d.remove(*contact_itr); } else { - d.modify(*itr, [&](auto& plo) { + d.modify(*contact_itr, [&](auto& plo) { plo.type = pl.type; from_string(plo.json_metadata, pl.json_metadata); }); @@ -386,14 +386,14 @@ namespace golos { namespace plugins { namespace private_message { from_string(plo.json_metadata, pl.json_metadata); }); - if (sidx.end() == ditr) { + if (owner_idx.end() == dst_itr) { d.create([&](auto& plso) { plso.owner = pl.owner; plso.type = pl.type; plso.size.total_contacts = 1; }); } else { - d.modify(*ditr, [&](auto& plso) { + d.modify(*dst_itr, [&](auto& plso) { plso.size.total_contacts++; }); } From fab752e4885b05270e79cfe32ac00e93efedc443 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 26 Jul 2018 18:27:27 +0700 Subject: [PATCH 167/250] Add pm-account-list. #805 --- .../private_message_plugin.cpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index c2c4c527c7..ef093cb62f 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -63,7 +63,8 @@ namespace golos { namespace plugins { namespace private_message { bool is_tracked_account(account_name_type) const; std::shared_ptr> custom_operation_interpreter_; - flat_map tracked_accounts_; + flat_map tracked_account_ranges_; + flat_set tracked_account_list_; golos::chain::database& db_; }; @@ -413,11 +414,13 @@ namespace golos { namespace plugins { namespace private_message { boost::program_options::options_description &cli, boost::program_options::options_description &cfg ) { - cli.add_options() + cfg.add_options() ("pm-account-range", - boost::program_options::value < std::vector < std::string >> ()->composing()->multitoken(), - "Defines a range of accounts to private messages to/from as a json pair [\"from\",\"to\"] [from,to)"); - cfg.add(cli); + boost::program_options::value>()->composing()->multitoken(), + "Defines a range of accounts to private messages to/from as a json pair [\"from\",\"to\"] [from,to]") + ("pm-account-list", + boost::program_options::value>()->composing()->multitoken(), + "Defines a list of accounts to private messages to/from"); } void private_message_plugin::plugin_initialize(const boost::program_options::variables_map &options) { @@ -430,7 +433,9 @@ namespace golos { namespace plugins { namespace private_message { add_plugin_index(my->db_); using pairstring = std::pair; - LOAD_VALUE_SET(options, "pm-accounts", my->tracked_accounts_, pairstring); + LOAD_VALUE_SET(options, "pm-account-range", my->tracked_account_ranges_, pairstring); + auto list = options["pm-account-list"].as>(); + my->tracked_account_list_.insert(list.begin(), list.end()); JSON_RPC_REGISTER_API(name()) } @@ -443,12 +448,17 @@ namespace golos { namespace plugins { namespace private_message { } bool private_message_plugin::private_message_plugin_impl::is_tracked_account(account_name_type name) const { - if (tracked_accounts_.empty()) { + if (tracked_account_ranges_.empty() && tracked_account_list_.empty()) { return true; } - auto itr = tracked_accounts_.lower_bound(name); - return tracked_accounts_.end() != itr && name >= itr->first && name <= itr->second; + auto list_itr = tracked_account_list_.find(name); + if (tracked_account_list_.end() != list_itr) { + return true; + } + + auto range_itr = tracked_account_ranges_.lower_bound(name); + return tracked_account_ranges_.end() != range_itr && name >= range_itr->first && name <= range_itr->second; } bool private_message_plugin::is_tracked_account(account_name_type name) const { From 5235871ab168744a3cd6afa5a3a609ae7aa325a2 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 20:17:05 +0700 Subject: [PATCH 168/250] Refactor errors: network_broadcast_api plugin #791 --- .../network_broadcast_api.cpp | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/plugins/network_broadcast_api/network_broadcast_api.cpp b/plugins/network_broadcast_api/network_broadcast_api.cpp index 3d458a076c..ea2b1da7c1 100644 --- a/plugins/network_broadcast_api/network_broadcast_api.cpp +++ b/plugins/network_broadcast_api/network_broadcast_api.cpp @@ -1,11 +1,14 @@ #include #include +#include #include #include #include +#include + namespace golos { namespace plugins { namespace network_broadcast_api { @@ -39,12 +42,12 @@ namespace golos { } DEFINE_API(network_broadcast_api_plugin, broadcast_transaction) { - auto n_args = args.args->size(); - FC_ASSERT(n_args == 1, "Expected at least 1 argument, got 0"); - auto trx = args.args->at(0).as(); - if (n_args > 1) { - const auto max_block_age = args.args->at(1).as(); - FC_ASSERT(!check_max_block_age(max_block_age)); + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + (uint32_t, max_block_age, 0) + ); + if (args.args->size() >= 2) { + GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } pimpl->_chain.accept_transaction(trx); pimpl->_p2p.broadcast_transaction(trx); @@ -53,12 +56,12 @@ namespace golos { } DEFINE_API(network_broadcast_api_plugin, broadcast_transaction_synchronous) { - const auto n_args = args.args->size(); - FC_ASSERT(n_args >= 1, "Expected at least 1 argument, got 0"); - auto trx = args.args->at(0).as(); - if (n_args > 1) { - const auto max_block_age = args.args->at(1).as(); - FC_ASSERT(!check_max_block_age(max_block_age)); + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + (uint32_t, max_block_age, 0) + ); + if (args.args->size() >= 2) { + GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } // Delegate connection handlers to callback @@ -81,9 +84,9 @@ namespace golos { } DEFINE_API(network_broadcast_api_plugin, broadcast_block) { - const auto n_args = args.args->size(); - FC_ASSERT(n_args == 1, "Expected 1 argument, got 0"); - auto block = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (signed_block, block) + ); pimpl->_chain.accept_block(block); pimpl->_p2p.broadcast_block(block); return broadcast_block_return(); @@ -92,12 +95,12 @@ namespace golos { DEFINE_API(network_broadcast_api_plugin,broadcast_transaction_with_callback){ // TODO: implement commit semantic for delegating connection handlers - const auto n_args = args.args->size(); - FC_ASSERT(n_args >= 2, "Expected at least 1 argument, got 0"); - auto trx = args.args->at(1).as(); - if (n_args > 2) { - const auto max_block_age = args.args->at(2).as(); - FC_ASSERT(!check_max_block_age(max_block_age)); + PLUGIN_API_VALIDATE_ARGS( + (signed_transaction, trx) + (uint32_t, max_block_age, 0) + ); + if (args.args->size() >= 2) { + GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } trx.validate(); From 3ac1c5c93ae5fa51ca3e125340d7b7597a527742 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 20:40:24 +0700 Subject: [PATCH 169/250] Refactor errors: operation_history plugin #791 --- .../include/golos/protocol/exceptions.hpp | 7 ++++++ plugins/operation_history/plugin.cpp | 23 +++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 0d343f6275..02201faa22 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -100,6 +100,9 @@ } \ FC_MULTILINE_MACRO_END +#define GOLOS_CHECK_OPTION(COND, MSG, ...) \ + GOLOS_ASSERT((COND), golos::invalid_option, MSG, __VA_ARGS__) + #define GOLOS_CHECK_VALUE(COND, MSG, ...) \ GOLOS_ASSERT((COND), golos::invalid_value, MSG, __VA_ARGS__) @@ -343,6 +346,10 @@ namespace golos { limit_too_large, invalid_value, 4020100, "Exceeded limit value"); + GOLOS_DECLARE_DERIVED_EXCEPTION( + invalid_option, golos_exception, + 5000000, "invalid option"); + } // golos diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 44ee9cbb5e..d2f3341203 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -1,6 +1,8 @@ #include #include +#include +#include #include #include @@ -8,10 +10,6 @@ #define STEEM_NAMESPACE_PREFIX "golos::protocol::" #define OPERATION_POSTFIX "_operation" -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); - - namespace golos { namespace plugins { namespace operation_history { @@ -150,7 +148,7 @@ namespace golos { namespace plugins { namespace operation_history { result.transaction_num = itr->trx_in_block; return result; } - FC_ASSERT(false, "Unknown Transaction ${t}", ("t", id)); + GOLOS_THROW_MISSING_OBJECT("transaction", id); } bool filter_content = false; @@ -162,17 +160,19 @@ namespace golos { namespace plugins { namespace operation_history { }; DEFINE_API(plugin, get_ops_in_block) { - CHECK_ARG_SIZE(2) - auto block_num = args.args->at(0).as(); - auto only_virtual = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, block_num) + (bool, only_virtual) + ); return pimpl->database.with_weak_read_lock([&](){ return pimpl->get_ops_in_block(block_num, only_virtual); }); } DEFINE_API(plugin, get_transaction) { - CHECK_ARG_SIZE(1) - auto id = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (transaction_id_type, id) + ); return pimpl->database.with_weak_read_lock([&](){ return pimpl->get_transaction(id); }); @@ -231,8 +231,7 @@ namespace golos { namespace plugins { namespace operation_history { }; if (options.count("history-whitelist-ops")) { - FC_ASSERT( - !options.count("history-blacklist-ops"), + GOLOS_CHECK_OPTION(!options.count("history-blacklist-ops"), "history-blacklist-ops and history-whitelist-ops can't be specified together"); pimpl->filter_content = true; From 971e287cf05a4a5b5002ec8960998ebd2abf16ab Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 20:44:49 +0700 Subject: [PATCH 170/250] Refactor errors: raw_block plugin #791 --- plugins/raw_block/plugin.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/raw_block/plugin.cpp b/plugins/raw_block/plugin.cpp index f0a35753b1..b167eb1786 100644 --- a/plugins/raw_block/plugin.cpp +++ b/plugins/raw_block/plugin.cpp @@ -1,8 +1,10 @@ #include #include #include +#include #include #include +#include namespace golos { namespace plugins { @@ -45,10 +47,12 @@ get_raw_block_r plugin::plugin_impl::get_raw_block(uint32_t block_num) { } DEFINE_API ( plugin, get_raw_block ) { - auto tmp = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (uint32_t, block_num) + ); auto &db = my->database(); return db.with_weak_read_lock([&]() { - return my->get_raw_block(tmp); + return my->get_raw_block(block_num); }); } From 465fea8f546504da53415e60292caea1ee7b0a8b Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 20:52:43 +0700 Subject: [PATCH 171/250] Refactor errors: social_network plugin #791 --- plugins/social_network/social_network.cpp | 78 ++++++++++------------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 4b0291533a..f5d82fcdd7 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -7,6 +7,7 @@ #include // These visitors creates additional tables, we don't really need them in LOW_MEM mode #include +#include #include #include #include @@ -15,22 +16,6 @@ #include #include -#define CHECK_ARG_SIZE(_S) \ - FC_ASSERT( \ - args.args->size() == _S, \ - "Expected #_S argument(s), was ${n}", \ - ("n", args.args->size()) ); - -#define CHECK_ARG_MIN_SIZE(_S, _M) \ - FC_ASSERT( \ - args.args->size() >= _S && args.args->size() <= _M, \ - "Expected #_S (maximum #_M) argument(s), was ${n}", \ - ("n", args.args->size()) ); - -#define GET_OPTIONAL_ARG(_I, _T, _D) \ - (args.args->size() > _I) ? \ - (args.args->at(_I).as<_T>()) : \ - static_cast<_T>(_D) #ifndef DEFAULT_VOTE_LIMIT # define DEFAULT_VOTE_LIMIT 10000 @@ -454,10 +439,11 @@ namespace golos { namespace plugins { namespace social_network { } DEFINE_API(social_network, get_content_replies) { - CHECK_ARG_MIN_SIZE(2, 3) - auto author = args.args->at(0).as(); - auto permlink = args.args->at(1).as(); - auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + (string, permlink) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_content_replies(author, permlink, vote_limit); }); @@ -481,21 +467,22 @@ namespace golos { namespace plugins { namespace social_network { } DEFINE_API(social_network, get_all_content_replies) { - CHECK_ARG_MIN_SIZE(2, 3) - auto author = args.args->at(0).as(); - auto permlink = args.args->at(1).as(); - auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + (string, permlink) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_all_content_replies(author, permlink, vote_limit); }); } DEFINE_API(social_network, get_account_votes) { - CHECK_ARG_MIN_SIZE(1, 3) - account_name_type voter = args.args->at(0).as(); - auto from = GET_OPTIONAL_ARG(1, uint32_t, 0); - auto limit = GET_OPTIONAL_ARG(2, uint64_t, DEFAULT_VOTE_LIMIT); - + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, voter) + (uint32_t, from, 0) + (uint64_t, limit, DEFAULT_VOTE_LIMIT) + ); auto& db = pimpl->db; return db.with_weak_read_lock([&]() { std::vector result; @@ -536,24 +523,26 @@ namespace golos { namespace plugins { namespace social_network { } DEFINE_API(social_network, get_content) { - CHECK_ARG_MIN_SIZE(2, 3) - auto author = args.args->at(0).as(); - auto permlink = args.args->at(1).as(); - auto vote_limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + (string, permlink) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_content(author, permlink, vote_limit); }); } DEFINE_API(social_network, get_active_votes) { - CHECK_ARG_MIN_SIZE(2, 3) - auto author = args.args->at(0).as(); - auto permlink = args.args->at(1).as(); - auto limit = GET_OPTIONAL_ARG(2, uint32_t, DEFAULT_VOTE_LIMIT); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + (string, permlink) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); return pimpl->db.with_weak_read_lock([&]() { std::vector result; uint32_t total_count; - pimpl->select_active_votes(result, total_count, author, permlink, limit); + pimpl->select_active_votes(result, total_count, author, permlink, vote_limit); return result; }); } @@ -598,12 +587,13 @@ namespace golos { namespace plugins { namespace social_network { * Subsequent calls should be (last_author, last_permlink, limit) */ DEFINE_API(social_network, get_replies_by_last_update) { - CHECK_ARG_MIN_SIZE(3, 4) - auto start_parent_author = args.args->at(0).as(); - auto start_permlink = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto vote_limit = GET_OPTIONAL_ARG(3, uint32_t, DEFAULT_VOTE_LIMIT); - FC_ASSERT(limit <= 100); + PLUGIN_API_VALIDATE_ARGS( + (string, start_parent_author) + (string, start_permlink) + (uint32_t, limit) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); return pimpl->db.with_weak_read_lock([&]() { return pimpl->get_replies_by_last_update(start_parent_author, start_permlink, limit, vote_limit); }); From e9eef9d78b4f6b83dde8a4295ca72af3182d9380 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 21:14:20 +0700 Subject: [PATCH 172/250] Refactor errors: tags plugin #791 --- plugins/tags/discussion_query.cpp | 23 ++++-- plugins/tags/plugin.cpp | 123 ++++++++++++++++-------------- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/plugins/tags/discussion_query.cpp b/plugins/tags/discussion_query.cpp index 76fd186e0c..793751b330 100644 --- a/plugins/tags/discussion_query.cpp +++ b/plugins/tags/discussion_query.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -24,15 +25,23 @@ namespace golos { namespace plugins { namespace tags { } void discussion_query::validate() const { - FC_ASSERT(limit <= 100); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); - for (auto& itr : filter_tags) { - FC_ASSERT(select_tags.find(itr) == select_tags.end()); - } + GOLOS_CHECK_PARAM(filter_tags, { + for (auto& itr : filter_tags) { + GOLOS_CHECK_VALUE(select_tags.find(itr) == select_tags.end(), + "Can't filter and select tag '${tag}' at the same time", + ("tag", itr)); + } + }); - for (auto& itr : filter_languages) { - FC_ASSERT(select_languages.find(itr) == select_languages.end()); - } + GOLOS_CHECK_PARAM(filter_languages, { + for (auto& itr : filter_languages) { + GOLOS_CHECK_VALUE(select_languages.find(itr) == select_languages.end(), + "Can't filter and select language '${language}' at the same time", + ("language", itr)); + } + }); } bool discussion_query::is_good_tags(const discussion& d) const { diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index e9685f1e3b..22b7e56dba 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,23 +10,8 @@ #include #include #include +#include -#define CHECK_ARG_SIZE(_S) \ - FC_ASSERT( \ - args.args->size() == _S, \ - "Expected #_S argument(s), was ${n}", \ - ("n", args.args->size()) ); - -#define CHECK_ARG_MIN_SIZE(_S, _M) \ - FC_ASSERT( \ - args.args->size() >= _S && args.args->size() <= _M, \ - "Expected #_S (maximum #_M) argument(s), was ${n}", \ - ("n", args.args->size()) ); - -#define GET_OPTIONAL_ARG(_I, _T, _D) \ - (args.args->size() > _I) ? \ - (args.args->at(_I).as<_T>()) : \ - static_cast<_T>(_D) namespace golos { namespace plugins { namespace tags { @@ -188,6 +174,7 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_languages) { + PLUGIN_API_VALIDATE_ARGS(); return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_languages(); }); @@ -552,15 +539,18 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_blog) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); - auto query = args.args->at(0).as(); query.prepare(); query.validate(); - FC_ASSERT(query.select_authors.size(), "Must get blogs for specific authors"); + GOLOS_CHECK_PARAM(query.select_authors, + GOLOS_CHECK_VALUE(query.select_authors.size(), "Must get blogs for specific authors")); auto& db = pimpl->database(); - FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); + GOLOS_ASSERT(db.has_index(), golos::unsupported_operation, + "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { return pimpl->select_unordered_discussions( @@ -572,15 +562,17 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_feed) { - CHECK_ARG_SIZE(1) - - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); - FC_ASSERT(query.select_authors.size(), "Must get feeds for specific authors"); + GOLOS_CHECK_PARAM(query.select_authors, + GOLOS_CHECK_VALUE(query.select_authors.size(), "Must get feeds for specific authors")); auto& db = pimpl->database(); - FC_ASSERT(db.has_index(), "Node is not running the follow plugin"); + GOLOS_ASSERT(db.has_index(), golos::unsupported_operation, + "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { return pimpl->select_unordered_discussions( @@ -594,12 +586,14 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_comments) { - CHECK_ARG_SIZE(1) + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); std::vector result; - auto query = args.args->at(0).as(); query.prepare(); query.validate(); - FC_ASSERT(!!query.start_author, "Must get comments for a specific author"); + GOLOS_CHECK_PARAM(query.start_author, + GOLOS_CHECK_VALUE(!!query.start_author, "Must get comments for specific authors")); auto& db = pimpl->database(); return db.with_weak_read_lock([&]() { @@ -642,8 +636,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_trending) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -655,8 +650,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_promoted) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -668,8 +664,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_created) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -681,8 +678,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_active) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -694,8 +692,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_cashout) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -707,8 +706,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_payout) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -720,8 +720,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_votes) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -733,8 +734,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_children) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -746,8 +748,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_discussions_by_hot) { - CHECK_ARG_SIZE(1) - auto query = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (discussion_query, query) + ); query.prepare(); query.validate(); return pimpl->select_ordered_discussions( @@ -793,9 +796,10 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_trending_tags) { - CHECK_ARG_SIZE(2) - auto after = args.args->at(0).as(); - auto limit = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, after) + (uint32_t, limit) + ); return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_trending_tags(after, limit); @@ -826,8 +830,9 @@ namespace golos { namespace plugins { namespace tags { } DEFINE_API(tags_plugin, get_tags_used_by_author) { - CHECK_ARG_SIZE(1) - auto author = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + ); return pimpl->database().with_weak_read_lock([&]() { return pimpl->get_tags_used_by_author(author); }); @@ -836,14 +841,14 @@ namespace golos { namespace plugins { namespace tags { DEFINE_API(tags_plugin, get_discussions_by_author_before_date) { std::vector result; - CHECK_ARG_MIN_SIZE(4, 5) - auto author = args.args->at(0).as(); - auto start_permlink = args.args->at(1).as(); - auto before_date = args.args->at(2).as(); - auto limit = args.args->at(3).as(); - auto vote_limit = GET_OPTIONAL_ARG(4, uint32_t, DEFAULT_VOTE_LIMIT); - - FC_ASSERT(limit <= 100); + PLUGIN_API_VALIDATE_ARGS( + (string, author) + (string, start_permlink) + (time_point_sec, before_date) + (uint32_t, limit) + (uint32_t, vote_limit, DEFAULT_VOTE_LIMIT) + ); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); result.reserve(limit); From 065eef62d994cdbe604e0d28561ff7ef917c8e41 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 21:16:43 +0700 Subject: [PATCH 173/250] Refactor errors: witness plugin #791 --- plugins/witness/witness.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/witness/witness.cpp b/plugins/witness/witness.cpp index 972b84b2ca..9b18221c40 100644 --- a/plugins/witness/witness.cpp +++ b/plugins/witness/witness.cpp @@ -169,7 +169,7 @@ namespace golos { idump((m)); fc::optional private_key = golos::utilities::wif_to_key(m.second); - FC_ASSERT(private_key.valid(), "unable to parse private key"); + GOLOS_CHECK_OPTION(private_key.valid(), "unable to parse private key"); pimpl->_private_keys[private_key->get_public_key()] = *private_key; pimpl->_miners[m.first] = private_key->get_public_key(); } @@ -197,7 +197,7 @@ namespace golos { const std::vector keys = options["private-key"].as>(); for (const std::string &wif_key : keys) { fc::optional private_key = golos::utilities::wif_to_key(wif_key); - FC_ASSERT(private_key.valid(), "unable to parse private key"); + GOLOS_CHECK_OPTION(private_key.valid(), "unable to parse private key"); pimpl->_private_keys[private_key->get_public_key()] = *private_key; } } From 7c56739bb8a1a0b9a2b74d2fbd2f1ec48a3930ee Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 21:25:53 +0700 Subject: [PATCH 174/250] Refactor errors: witness_api #791 --- plugins/witness_api/plugin.cpp | 42 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/plugins/witness_api/plugin.cpp b/plugins/witness_api/plugin.cpp index 440dbedfb9..2d7b69f24b 100644 --- a/plugins/witness_api/plugin.cpp +++ b/plugins/witness_api/plugin.cpp @@ -1,10 +1,9 @@ #include #include +#include +#include -#define CHECK_ARG_SIZE(s) \ - FC_ASSERT( args.args->size() == s, "Expected #s argument(s), was ${n}", ("n", args.args->size()) ); - namespace golos { namespace plugins { namespace witness_api { using namespace golos::protocol; @@ -29,12 +28,14 @@ struct plugin::witness_plugin_impl { DEFINE_API(plugin, get_current_median_history_price) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { return my->database.get_feed_history().current_median_history; }); } DEFINE_API(plugin, get_feed_history) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { return feed_history_api_object(my->database.get_feed_history()); }); @@ -55,6 +56,7 @@ std::vector plugin::witness_plugin_impl::get_miner_queue() co } DEFINE_API(plugin, get_miner_queue) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { return my->get_miner_queue(); }); @@ -62,6 +64,7 @@ DEFINE_API(plugin, get_miner_queue) { DEFINE_API(plugin, get_active_witnesses) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { const auto &wso = my->database.get_witness_schedule_object(); size_t n = wso.current_shuffled_witnesses.size(); @@ -77,6 +80,7 @@ DEFINE_API(plugin, get_active_witnesses) { } DEFINE_API(plugin, get_witness_schedule) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { return my->database.get(witness_schedule_object::id_type()); }); @@ -99,16 +103,18 @@ std::vector> plugin::witness_plugin_impl::get_witne } DEFINE_API(plugin, get_witnesses) { - CHECK_ARG_SIZE(1) - auto witness_ids = args.args->at(0).as >(); + PLUGIN_API_VALIDATE_ARGS( + (vector, witness_ids) + ); return my->database.with_weak_read_lock([&]() { return my->get_witnesses(witness_ids); }); } DEFINE_API(plugin, get_witness_by_account) { - CHECK_ARG_SIZE(1) - auto account_name = args.args->at(0).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, account_name) + ); return my->database.with_weak_read_lock([&]() { return my->get_witness_by_account(account_name); }); @@ -125,9 +131,10 @@ fc::optional plugin::witness_plugin_impl::get_witness_by_acc } DEFINE_API(plugin, get_witnesses_by_vote) { - CHECK_ARG_SIZE(2) - auto from = args.args->at(0).as(); - auto limit = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, from) + (uint32_t, limit) + ); return my->database.with_weak_read_lock([&]() { return my->get_witnesses_by_vote(from, limit); }); @@ -136,7 +143,7 @@ DEFINE_API(plugin, get_witnesses_by_vote) { std::vector plugin::witness_plugin_impl::get_witnesses_by_vote( std::string from, uint32_t limit ) const { - FC_ASSERT(limit <= 100); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); std::vector result; result.reserve(limit); @@ -147,7 +154,8 @@ std::vector plugin::witness_plugin_impl::get_witnesses_by_vo auto itr = vote_idx.begin(); if (from.size()) { auto nameitr = name_idx.find(from); - FC_ASSERT(nameitr != name_idx.end(), "invalid witness name ${n}", ("n", from)); + GOLOS_CHECK_PARAM(from, + GOLOS_CHECK_VALUE(nameitr != name_idx.end(), "Witness name after last witness")); itr = vote_idx.iterator_to(*nameitr); } @@ -159,6 +167,7 @@ std::vector plugin::witness_plugin_impl::get_witnesses_by_vo } DEFINE_API(plugin, get_witness_count) { + PLUGIN_API_VALIDATE_ARGS(); return my->database.with_weak_read_lock([&]() { return my->get_witness_count(); }); @@ -169,9 +178,10 @@ uint64_t plugin::witness_plugin_impl::get_witness_count() const { } DEFINE_API(plugin, lookup_witness_accounts) { - CHECK_ARG_SIZE(2) - auto lower_bound_name = args.args->at(0).as(); - auto limit = args.args->at(1).as(); + PLUGIN_API_VALIDATE_ARGS( + (string, lower_bound_name) + (uint32_t, limit) + ); return my->database.with_weak_read_lock([&]() { return my->lookup_witness_accounts(lower_bound_name, limit); }); @@ -181,7 +191,7 @@ std::set plugin::witness_plugin_impl::lookup_witness_accounts const std::string &lower_bound_name, uint32_t limit ) const { - FC_ASSERT(limit <= 1000); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &witnesses_by_id = database.get_index().indices().get(); // get all the names and look them all up, sort them, then figure out what From c46b8a09c48993c4b2493e1f0fe7cf629f7bd7b2 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 26 Jul 2018 21:34:18 +0700 Subject: [PATCH 175/250] Refactor errors: chain plugin #790 --- plugins/chain/plugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 693ab060de..d5b96ef142 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -97,7 +97,10 @@ namespace chain { uint64_t max_accept_time = now.sec_since_epoch(); max_accept_time += allow_future_time; - FC_ASSERT(block.timestamp.sec_since_epoch() <= max_accept_time); + GOLOS_CHECK_VALUE(block.timestamp.sec_since_epoch() <= max_accept_time, + "Block timestamp is too far in the future", + ("timestamp", block.timestamp.sec_since_epoch()) + ("max_accept_time", max_accept_time)); } bool plugin::plugin_impl::accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip) { From 53855aaa0a34dd0e8bbff7da148103bdf6f38041 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 26 Jul 2018 21:38:31 +0700 Subject: [PATCH 176/250] Add private messages exceptions. #805 --- plugins/private_message/CMakeLists.txt | 3 +- .../private_message_exceptions.hpp | 40 +++++++ .../private_message_operations.cpp | 25 ++-- .../private_message_plugin.cpp | 108 +++++++++--------- 4 files changed, 108 insertions(+), 68 deletions(-) create mode 100644 plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp diff --git a/plugins/private_message/CMakeLists.txt b/plugins/private_message/CMakeLists.txt index 40bfcbbd8f..8d81dfd05d 100644 --- a/plugins/private_message/CMakeLists.txt +++ b/plugins/private_message/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND CURRENT_TARGET_HEADERS include/golos/plugins/private_message/private_message_objects.hpp include/golos/plugins/private_message/private_message_operations.hpp include/golos/plugins/private_message/private_message_evaluators.hpp + include/golos/plugins/private_message/private_message_exceptions.hpp ) list(APPEND CURRENT_TARGET_SOURCES @@ -32,9 +33,9 @@ set_property(TARGET golos_${CURRENT_TARGET} PROPERTY EXPORT_NAME ${CURRENT_TARGE target_link_libraries( golos_${CURRENT_TARGET} golos::chain_plugin - golos::p2p golos::protocol golos::network + golos::json_rpc graphene_utilities graphene_time appbase diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp new file mode 100644 index 0000000000..be39ee1f3f --- /dev/null +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#define PLUGIN_CHECK_LOGIC(expr, type, msg, ...) \ + GOLOS_CHECK_LOGIC(expr, type, msg, ("plugin", "private_message") __VA_ARGS__) + +namespace golos { namespace plugins { namespace private_message { + + struct logic_errors { + enum types { + cannot_send_to_yourself, + from_and_to_memo_keys_must_be_different, + cannot_add_contact_to_yourself, + sender_in_ignore_list, + recepient_ignore_messages_from_undefined_contact, + add_undefined_contact, + contact_has_same_type, + }; + }; + +} } } // golos::plugins::private_message + +namespace golos { + template<> + inline std::string get_logic_error_namespace() { + return golos::plugins::private_message::private_message_plugin::name(); + } +} + +FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, + (cannot_send_to_yourself) + (from_and_to_memo_keys_must_be_different) + (cannot_add_contact_to_yourself) + (sender_in_ignore_list) + (recepient_ignore_messages_from_undefined_contact) + (add_undefined_contact) + (contact_has_same_type) +); \ No newline at end of file diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index 6639b58942..442625ba5c 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -33,21 +34,25 @@ namespace golos { namespace plugins { namespace private_message { void private_message_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(to); + GOLOS_CHECK_PARAM_ACCOUNT(from); - GOLOS_CHECK_PARAM(from, { - validate_account_name(from); - GOLOS_CHECK_VALUE(from != to, "You cannot write to yourself"); - }); + PLUGIN_CHECK_LOGIC(from != to, + logic_errors::cannot_send_to_yourself, + "You cannot write to yourself"); GOLOS_CHECK_PARAM(to_memo_key, { - GOLOS_CHECK_VALUE(to_memo_key != public_key_type(), "To_key can't be empty"); + GOLOS_CHECK_VALUE(to_memo_key != public_key_type(), "to_key can't be empty"); }); GOLOS_CHECK_PARAM(from_memo_key, { GOLOS_CHECK_VALUE(from_memo_key != public_key_type(), "From_key can't be empty"); - GOLOS_CHECK_VALUE(from_memo_key != to_memo_key, "From_key can't be equal to to_key"); }); + PLUGIN_CHECK_LOGIC( + from_memo_key != to_memo_key, + logic_errors::from_and_to_memo_keys_must_be_different, + "from_key can't be equal to to_key"); + GOLOS_CHECK_PARAM(nonce, { GOLOS_CHECK_VALUE(nonce != 0, "Nonce can't be zero"); }); @@ -65,11 +70,11 @@ namespace golos { namespace plugins { namespace private_message { void private_contact_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(contact); + GOLOS_CHECK_PARAM_ACCOUNT(owner); - GOLOS_CHECK_PARAM(owner, { - validate_account_name(owner); - GOLOS_CHECK_VALUE(owner != contact, "You cannot add contact to yourself"); - }); + PLUGIN_CHECK_LOGIC(contact != owner, + logic_errors::cannot_add_contact_to_yourself, + "You add contact to yourself"); GOLOS_CHECK_PARAM(type, { GOLOS_CHECK_VALUE(is_valid_contact_type(type), "Unknown contact type"); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index ef093cb62f..1b03bf291b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include @@ -201,13 +203,11 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); - // TODO: fix exception type - GOLOS_CHECK_VALUE( - gitr == idx.end() || gitr->type != ignored, + PLUGIN_CHECK_LOGIC(gitr == idx.end() || gitr->type != ignored, + logic_errors::sender_in_ignore_list, "Sender is in ignore list of receiver"); - // TODO: fix exception type - GOLOS_CHECK_VALUE( - titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, + PLUGIN_CHECK_LOGIC(titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, + logic_errors::recepient_ignore_messages_from_undefined_contact, "Recipient accept messages only from his contact list"); }); @@ -322,15 +322,13 @@ namespace golos { namespace plugins { namespace private_message { d.get_account(pl.contact); if (d.is_producing()) { - // TODO: fix exception type - GOLOS_CHECK_VALUE( - contact_idx.end() != contact_itr || pl.type != undefined, + PLUGIN_CHECK_LOGIC(contact_idx.end() != contact_itr || pl.type != undefined, + logic_errors::add_undefined_contact, "Can't add undefined contact"); - // TODO: fix exception type std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); - GOLOS_CHECK_VALUE( - contact_itr->type != pl.type || pl.json_metadata != json_metadata, + PLUGIN_CHECK_LOGIC(contact_itr->type != pl.type || pl.json_metadata != json_metadata, + logic_errors::contact_has_same_type, "Contact has the same type"); } }); @@ -434,8 +432,10 @@ namespace golos { namespace plugins { namespace private_message { using pairstring = std::pair; LOAD_VALUE_SET(options, "pm-account-range", my->tracked_account_ranges_, pairstring); - auto list = options["pm-account-list"].as>(); - my->tracked_account_list_.insert(list.begin(), list.end()); + if (options.count("pm-account-list")) { + auto list = options["pm-account-list"].as>(); + my->tracked_account_list_.insert(list.begin(), list.end()); + } JSON_RPC_REGISTER_API(name()) } @@ -468,83 +468,77 @@ namespace golos { namespace plugins { namespace private_message { // Api Defines DEFINE_API(private_message_plugin, get_inbox) { - GOLOS_CHECK_ARGS_COUNT(args.args, 4) - - auto to = args.args->at(0).as(); - auto newest = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto& db = my->db_; + PLUGIN_API_VALIDATE_ARGS( + (std::string, to) + (time_point, newest) + (uint16_t, limit) + (uint32_t, offset) + ); - GOLOS_CHECK_LIMIT(limit, 100); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); - return db.with_weak_read_lock([&]() { + return my->db_.with_weak_read_lock([&]() { return my->get_inbox(to, newest, limit, offset); }); } DEFINE_API(private_message_plugin, get_outbox) { - GOLOS_CHECK_ARGS_COUNT(args.args, 4) + PLUGIN_API_VALIDATE_ARGS( + (std::string, from) + (time_point, newest) + (uint16_t, limit) + (uint32_t, offset) + ); - auto from = args.args->at(0).as(); - auto newest = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto& db = my->db_; + GOLOS_CHECK_LIMIT_PARAM(limit, 100); - GOLOS_CHECK_LIMIT(limit, 100); - - return db.with_weak_read_lock([&]() { + return my->db_.with_weak_read_lock([&]() { return my->get_outbox(from, newest, limit, offset); }); } DEFINE_API(private_message_plugin, get_settings) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1) - - auto owner = args.args->at(0).as(); - auto& db = my->db_; + PLUGIN_API_VALIDATE_ARGS( + (std::string, owner) + ); - return db.with_weak_read_lock([&](){ + return my->db_.with_weak_read_lock([&](){ return my->get_settings(owner); }); } DEFINE_API(private_message_plugin, get_contacts_size) { - GOLOS_CHECK_ARGS_COUNT(args.args, 1) + PLUGIN_API_VALIDATE_ARGS( + (std::string, owner) + ); - auto owner = args.args->at(0).as(); - auto& db = my->db_; - - return db.with_weak_read_lock([&](){ + return my->db_.with_weak_read_lock([&](){ return my->get_contacts_size(owner); }); } DEFINE_API(private_message_plugin, get_contact_info) { - GOLOS_CHECK_ARGS_COUNT(args.args, 2) - - auto owner = args.args->at(0).as(); - auto contact = args.args->at(1).as(); - auto& db = my->db_; + PLUGIN_API_VALIDATE_ARGS( + (std::string, owner) + (std::string, contact) + ); - return db.with_weak_read_lock([&](){ + return my->db_.with_weak_read_lock([&](){ return my->get_contact_info(owner, contact); }); } DEFINE_API(private_message_plugin, get_contacts) { - GOLOS_CHECK_ARGS_COUNT(args.args, 4) - - auto owner = args.args->at(0).as(); - auto type = args.args->at(1).as(); - auto limit = args.args->at(2).as(); - auto offset = args.args->at(3).as(); - auto& db = my->db_; + PLUGIN_API_VALIDATE_ARGS( + (std::string, owner) + (private_contact_type, type) + (uint16_t, limit) + (uint32_t, offset) + ); - GOLOS_CHECK_LIMIT(limit, 100); + GOLOS_CHECK_LIMIT_PARAM(limit, 100); - return db.with_weak_read_lock([&](){ + return my->db_.with_weak_read_lock([&](){ return my->get_contacts(owner, type, limit, offset); }); } From b13d02dcca2d78ec1c4c906ff68045d6dce64b9e Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 27 Jul 2018 13:41:16 +0700 Subject: [PATCH 177/250] Change PLUGIN_CHECK_LOGIC to GOLOS_CHECK_LOGIC in private messages. #805 --- .../private_message/private_message_exceptions.hpp | 7 ++----- .../private_message/private_message_operations.cpp | 6 +++--- plugins/private_message/private_message_plugin.cpp | 14 +++++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index be39ee1f3f..07e2b60075 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -3,9 +3,6 @@ #include #include -#define PLUGIN_CHECK_LOGIC(expr, type, msg, ...) \ - GOLOS_CHECK_LOGIC(expr, type, msg, ("plugin", "private_message") __VA_ARGS__) - namespace golos { namespace plugins { namespace private_message { struct logic_errors { @@ -14,7 +11,7 @@ namespace golos { namespace plugins { namespace private_message { from_and_to_memo_keys_must_be_different, cannot_add_contact_to_yourself, sender_in_ignore_list, - recepient_ignore_messages_from_undefined_contact, + recepient_ignores_messages_from_undefined_contact, add_undefined_contact, contact_has_same_type, }; @@ -34,7 +31,7 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (from_and_to_memo_keys_must_be_different) (cannot_add_contact_to_yourself) (sender_in_ignore_list) - (recepient_ignore_messages_from_undefined_contact) + (recepient_ignores_messages_from_undefined_contact) (add_undefined_contact) (contact_has_same_type) ); \ No newline at end of file diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index 442625ba5c..a642f08a08 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -36,7 +36,7 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_PARAM_ACCOUNT(to); GOLOS_CHECK_PARAM_ACCOUNT(from); - PLUGIN_CHECK_LOGIC(from != to, + GOLOS_CHECK_LOGIC(from != to, logic_errors::cannot_send_to_yourself, "You cannot write to yourself"); @@ -48,7 +48,7 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_VALUE(from_memo_key != public_key_type(), "From_key can't be empty"); }); - PLUGIN_CHECK_LOGIC( + GOLOS_CHECK_LOGIC( from_memo_key != to_memo_key, logic_errors::from_and_to_memo_keys_must_be_different, "from_key can't be equal to to_key"); @@ -72,7 +72,7 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_PARAM_ACCOUNT(contact); GOLOS_CHECK_PARAM_ACCOUNT(owner); - PLUGIN_CHECK_LOGIC(contact != owner, + GOLOS_CHECK_LOGIC(contact != owner, logic_errors::cannot_add_contact_to_yourself, "You add contact to yourself"); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 1b03bf291b..e36b4a5b1b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -203,12 +203,12 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); - PLUGIN_CHECK_LOGIC(gitr == idx.end() || gitr->type != ignored, + GOLOS_CHECK_LOGIC(gitr == idx.end() || gitr->type != ignored, logic_errors::sender_in_ignore_list, - "Sender is in ignore list of receiver"); - PLUGIN_CHECK_LOGIC(titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, - logic_errors::recepient_ignore_messages_from_undefined_contact, - "Recipient accept messages only from his contact list"); + "Sender is in the ignore list of recipient"); + GOLOS_CHECK_LOGIC(titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, + logic_errors::recepient_ignores_messages_from_undefined_contact, + "Recipient accepts messages only from his contact list"); }); d.create([&](message_object& pmo) { @@ -322,12 +322,12 @@ namespace golos { namespace plugins { namespace private_message { d.get_account(pl.contact); if (d.is_producing()) { - PLUGIN_CHECK_LOGIC(contact_idx.end() != contact_itr || pl.type != undefined, + GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pl.type != undefined, logic_errors::add_undefined_contact, "Can't add undefined contact"); std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); - PLUGIN_CHECK_LOGIC(contact_itr->type != pl.type || pl.json_metadata != json_metadata, + GOLOS_CHECK_LOGIC(contact_itr->type != pl.type || pl.json_metadata != json_metadata, logic_errors::contact_has_same_type, "Contact has the same type"); } From 65f9e81e19f3f0760a256d35dbc594e84794ccf2 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 13:56:55 +0700 Subject: [PATCH 178/250] Refactor errors: cli_wallet #804 --- .../wallet/include/golos/wallet/wallet.hpp | 5 +- libraries/wallet/wallet.cpp | 313 +++++++++++------- 2 files changed, 189 insertions(+), 129 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index bc2ef4c747..eb7668bb3f 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -66,7 +67,7 @@ namespace golos { namespace wallet { if( str.size() > sizeof(memo_data) && str[0] == '#') { auto data = fc::from_base58( str.substr(1) ); auto m = fc::raw::unpack( data ); - FC_ASSERT( string(m) == str ); + GOLOS_CHECK_VALUE( string(m) == str, "Invalid encoded memo data" ); return m; } } catch ( ... ) {} @@ -1281,4 +1282,4 @@ FC_REFLECT( FC_REFLECT_DERIVED( (golos::wallet::extended_message_object), ((golos::plugins::private_message::message_api_obj)), - (message)); \ No newline at end of file + (message)); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index fe19ebf0c9..477d69abe5 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -57,8 +58,38 @@ # include #endif +#define WALLET_CHECK_UNLOCKED() \ + GOLOS_ASSERT(!is_locked(), golos::wallet::wallet_is_locked, "The wallet must be unlocked before operation") + #define BRAIN_KEY_WORD_COUNT 16 +namespace golos { namespace wallet { + + struct logic_errors { + enum types { + detected_private_key_in_memo, + owner_authority_change_would_render_account_irrecoverable, + private_key_not_available, + no_account_in_lut, + malformed_private_key, + }; + }; + + GOLOS_DECLARE_DERIVED_EXCEPTION( + wallet_is_locked, golos::golos_exception, + 10000, "The wallet must be unlocked"); + +} } // golos::wallet + +namespace golos { + +template<> +std::string get_logic_error_namespace() { + return "wallet"; +} + +} // golos + namespace golos { namespace wallet { namespace detail { @@ -370,6 +401,18 @@ namespace golos { namespace wallet { return result; } + fc::variant make_operation_id(transaction_handle_type handle, uint32_t op_index) { + return fc::mutable_variant_object()("transaction",handle)("op_index",op_index); + } + + signed_transaction &get_builder_transaction(transaction_handle_type handle) { + auto trx = _builder_transactions.find(handle); + if (trx == _builder_transactions.end()) { + GOLOS_THROW_MISSING_OBJECT("transaction", handle); + } + return trx->second; + } + transaction_handle_type begin_builder_transaction() { transaction_handle_type handle = 0; if (!_builder_transactions.empty()) { @@ -382,8 +425,8 @@ namespace golos { namespace wallet { void add_operation_to_builder_transaction( transaction_handle_type handle, const operation& op ) { - FC_ASSERT(_builder_transactions.count(handle)); - _builder_transactions[handle].operations.emplace_back(op); + auto& trx = get_builder_transaction(handle); + trx.operations.emplace_back(op); } void add_operation_copy_to_builder_transaction( @@ -391,12 +434,12 @@ namespace golos { namespace wallet { transaction_handle_type dst_handle, uint32_t op_index ) { - FC_ASSERT(_builder_transactions.count(src_handle)); - FC_ASSERT(_builder_transactions.count(dst_handle)); - signed_transaction& trx = _builder_transactions[src_handle]; - FC_ASSERT(op_index < trx.operations.size()); - const auto op = trx.operations[op_index]; - _builder_transactions[dst_handle].operations.emplace_back(op); + auto& src_trx = get_builder_transaction(src_handle); + auto& dst_trx = get_builder_transaction(dst_handle); + if (op_index >= src_trx.operations.size()) + GOLOS_THROW_MISSING_OBJECT("operation", make_operation_id(src_handle,op_index)); + const auto op = src_trx.operations[op_index]; + dst_trx.operations.emplace_back(op); } void replace_operation_in_builder_transaction( @@ -404,20 +447,19 @@ namespace golos { namespace wallet { uint32_t op_index, const operation& new_op ) { - FC_ASSERT(_builder_transactions.count(handle)); - signed_transaction& trx = _builder_transactions[handle]; - FC_ASSERT(op_index < trx.operations.size()); + auto& trx = get_builder_transaction(handle); + if (op_index >= trx.operations.size()) + GOLOS_THROW_MISSING_OBJECT("operation", make_operation_id(handle,op_index)); trx.operations[op_index] = new_op; } transaction preview_builder_transaction(transaction_handle_type handle) { - FC_ASSERT(_builder_transactions.count(handle)); - return _builder_transactions[handle]; + return get_builder_transaction(handle); } signed_transaction sign_builder_transaction(transaction_handle_type handle, bool broadcast) { - FC_ASSERT(_builder_transactions.count(handle)); - return _builder_transactions[handle] = sign_transaction(_builder_transactions[handle], broadcast); + auto& trx = get_builder_transaction(handle); + return _builder_transactions[handle] = sign_transaction(trx, broadcast); } signed_transaction propose_builder_transaction( @@ -429,7 +471,7 @@ namespace golos { namespace wallet { std::string review_period_time, bool broadcast ) { - FC_ASSERT(_builder_transactions.count(handle)); + (void)get_builder_transaction(handle); proposal_create_operation op; op.author = author; op.title = title; @@ -501,9 +543,11 @@ namespace golos { namespace wallet { return _remote_database_api->get_proposed_transactions(account, from, limit); } - golos::api::account_api_object get_account( string account_name ) const { + golos::api::account_api_object get_account(const string& account_name) const { auto accounts = _remote_database_api->get_accounts( { account_name } ); - FC_ASSERT( !accounts.empty(), "Unknown account" ); + if (accounts.size() != 1 || account_name != accounts[0].name) { + GOLOS_THROW_MISSING_OBJECT("account", account_name); + } return accounts.front(); } @@ -518,7 +562,8 @@ namespace golos { namespace wallet { fc::ecc::private_key get_private_key(const public_key_type& id)const { auto has_key = try_get_private_key( id ); - FC_ASSERT( has_key ); + if (!has_key) + GOLOS_THROW_MISSING_OBJECT("private_key", id); return *has_key; } @@ -676,7 +721,7 @@ namespace golos { namespace wallet { } void set_transaction_expiration( uint32_t tx_expiration_seconds ) { - FC_ASSERT( tx_expiration_seconds < STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); + GOLOS_CHECK_VALUE_LT( tx_expiration_seconds, STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); _tx_expiration_seconds = tx_expiration_seconds; } @@ -770,7 +815,9 @@ namespace golos { namespace wallet { auto get_account_from_lut = [&]( const std::string& name ) -> const golos::api::account_api_object& { auto it = approving_account_lut.find( name ); - FC_ASSERT( it != approving_account_lut.end(), "No account in lut: '${name}'", ("name",name) ); + GOLOS_CHECK_LOGIC( it != approving_account_lut.end(), + logic_errors::no_account_in_lut, + "No account in lut: '${name}'", ("name",name) ); return it->second; }; @@ -798,7 +845,10 @@ namespace golos { namespace wallet { if( it != _keys.end() ) { fc::optional privkey = wif_to_key( it->second ); - FC_ASSERT( privkey.valid(), "Malformed private key in _keys" ); + GOLOS_CHECK_LOGIC(privkey.valid(), + logic_errors::malformed_private_key, + "Malformed private key in _keys for public key ${key}", + ("key",key)); available_keys.insert(key); available_private_keys[key] = *privkey; } @@ -820,7 +870,10 @@ namespace golos { namespace wallet { // checking if each private key exists and signing tx with it for( const public_key_type& k : minimal_signing_keys ) { auto it = available_private_keys.find(k); - FC_ASSERT( it != available_private_keys.end() ); + GOLOS_CHECK_LOGIC( it != available_private_keys.end(), + logic_errors::private_key_not_available, + "Private key for public key ${key} not available", + ("key",k)); tx.sign( it->second, steem_chain_id ); } @@ -1055,7 +1108,7 @@ namespace golos { namespace wallet { } vector< golos::api::account_api_object > wallet_api::list_my_accounts() { - FC_ASSERT( !is_locked(), "Wallet must be unlocked to list accounts" ); + WALLET_CHECK_UNLOCKED(); vector result; vector pub_keys; @@ -1133,7 +1186,7 @@ namespace golos { namespace wallet { bool wallet_api::import_key(string wif_key) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); // backup wallet fc::optional optional_private_key = wif_to_key(wif_key); if (!optional_private_key) @@ -1330,7 +1383,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st void wallet_api::lock() { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); encrypt_keys(); for( auto& key : my->_keys ) key.second = key_to_wif(fc::ecc::private_key()); @@ -1341,27 +1394,28 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st void wallet_api::unlock(string password) { try { - FC_ASSERT(password.size() > 0); + GOLOS_CHECK_PARAM(password, GOLOS_CHECK_VALUE(password.size() > 0, "Password should be non empty")); auto pw = fc::sha512::hash(password.c_str(), password.size()); vector decrypted = fc::aes_decrypt(pw, my->_wallet.cipher_keys); auto pk = fc::raw::unpack(decrypted); - FC_ASSERT(pk.checksum == pw); my->_keys = std::move(pk.keys); my->_checksum = pk.checksum; my->self.lock_changed(false); + } catch (const fc::aes_exception& e) { + GOLOS_CHECK_PARAM(password, FC_THROW_EXCEPTION(golos::invalid_value, "Invalid password")); } FC_CAPTURE_AND_RETHROW() } void wallet_api::set_password( string password ) { if( !is_new() ) - FC_ASSERT( !is_locked(), "The wallet must be unlocked before the password can be set" ); + WALLET_CHECK_UNLOCKED(); my->_checksum = fc::sha512::hash( password.c_str(), password.size() ); lock(); } vector wallet_api::list_keys(string account) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); vector all_keys; @@ -1421,7 +1475,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st pair wallet_api::get_private_key_from_password( string account, string role, string password )const { auto seed = account + role + password; - FC_ASSERT( seed.size() ); + GOLOS_CHECK_PARAM(account, GOLOS_CHECK_VALUE(seed.size(), "At least one of 'account', 'role', 'password' should be non empty")); auto secret = fc::sha256::hash( seed.c_str(), seed.size() ); auto priv = fc::ecc::private_key::regenerate( secret ); return std::make_pair( public_key_type( priv.get_public_key() ), key_to_wif( priv ) ); @@ -1457,7 +1511,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) const { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); account_create_operation op; op.creator = creator; op.new_account_name = new_account_name; @@ -1486,7 +1540,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st string json_meta, bool broadcast ) { try { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); auto owner = suggest_brain_key(); auto active = suggest_brain_key(); auto posting = suggest_brain_key(); @@ -1519,7 +1573,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) const { try { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); account_create_with_delegation_operation op; op.creator = creator; op.new_account_name = new_account_name; @@ -1546,7 +1600,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st */ annotated_signed_transaction wallet_api::request_account_recovery( string recovery_account, string account_to_recover, authority new_authority, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); request_account_recovery_operation op; op.recovery_account = recovery_account; op.account_to_recover = account_to_recover; @@ -1560,7 +1614,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::recover_account( string account_to_recover, authority recent_authority, authority new_authority, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); recover_account_operation op; op.account_to_recover = account_to_recover; @@ -1575,7 +1629,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::change_recovery_account( string owner, string new_recovery_account, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); change_recovery_account_operation op; op.account_to_recover = owner; @@ -1603,7 +1657,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); account_update_operation op; op.account = account_name; @@ -1624,29 +1678,27 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::update_account_auth_key( string account_name, authority_type type, public_key_type key, weight_type weight, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); - auto accounts = my->_remote_database_api->get_accounts( { account_name } ); - FC_ASSERT( accounts.size() == 1, "Account does not exist" ); - FC_ASSERT( account_name == accounts[0].name, "Account name doesn't match?" ); + auto account = get_account(account_name); account_update_operation op; op.account = account_name; - op.memo_key = accounts[0].memo_key; - op.json_metadata = accounts[0].json_metadata; + op.memo_key = account.memo_key; + op.json_metadata = account.json_metadata; authority new_auth; switch( type ) { case( owner ): - new_auth = accounts[0].owner; + new_auth = account.owner; break; case( active ): - new_auth = accounts[0].active; + new_auth = account.active; break; case( posting ): - new_auth = accounts[0].posting; + new_auth = account.posting; break; } @@ -1660,9 +1712,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } if( new_auth.is_impossible() ) { - if ( type == owner ) { - FC_ASSERT( false, "Owner authority change would render account irrecoverable." ); - } + GOLOS_CHECK_LOGIC(type != owner, logic_errors::owner_authority_change_would_render_account_irrecoverable, + "Owner authority change would render account irrecoverable." ); wlog( "Authority is now impossible." ); } @@ -1688,29 +1739,27 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::update_account_auth_account( string account_name, authority_type type, string auth_account, weight_type weight, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); - auto accounts = my->_remote_database_api->get_accounts( { account_name } ); - FC_ASSERT( accounts.size() == 1, "Account does not exist" ); - FC_ASSERT( account_name == accounts[0].name, "Account name doesn't match?" ); + auto account = get_account(account_name); account_update_operation op; op.account = account_name; - op.memo_key = accounts[0].memo_key; - op.json_metadata = accounts[0].json_metadata; + op.memo_key = account.memo_key; + op.json_metadata = account.json_metadata; authority new_auth; switch( type ) { case( owner ): - new_auth = accounts[0].owner; + new_auth = account.owner; break; case( active ): - new_auth = accounts[0].active; + new_auth = account.active; break; case( posting ): - new_auth = accounts[0].posting; + new_auth = account.posting; break; } @@ -1725,10 +1774,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st if( new_auth.is_impossible() ) { - if ( type == owner ) - { - FC_ASSERT( false, "Owner authority change would render account irrecoverable." ); - } + GOLOS_CHECK_LOGIC(type != owner, logic_errors::owner_authority_change_would_render_account_irrecoverable, + "Owner authority change would render account irrecoverable." ); wlog( "Authority is now impossible." ); } @@ -1755,30 +1802,28 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::update_account_auth_threshold( string account_name, authority_type type, uint32_t threshold, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); - auto accounts = my->_remote_database_api->get_accounts( { account_name } ); - FC_ASSERT( accounts.size() == 1, "Account does not exist" ); - FC_ASSERT( account_name == accounts[0].name, "Account name doesn't match?" ); - FC_ASSERT( threshold != 0, "Authority is implicitly satisfied" ); + auto account = get_account(account_name); + GOLOS_CHECK_PARAM(threshold, GOLOS_CHECK_VALUE(threshold != 0, "Authority is implicitly satisfied")); account_update_operation op; op.account = account_name; - op.memo_key = accounts[0].memo_key; - op.json_metadata = accounts[0].json_metadata; + op.memo_key = account.memo_key; + op.json_metadata = account.json_metadata; authority new_auth; switch( type ) { case( owner ): - new_auth = accounts[0].owner; + new_auth = account.owner; break; case( active ): - new_auth = accounts[0].active; + new_auth = account.active; break; case( posting ): - new_auth = accounts[0].posting; + new_auth = account.posting; break; } @@ -1786,10 +1831,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st if( new_auth.is_impossible() ) { - if ( type == owner ) - { - FC_ASSERT( false, "Owner authority change would render account irrecoverable." ); - } + GOLOS_CHECK_LOGIC(type != owner, logic_errors::owner_authority_change_would_render_account_irrecoverable, + "Owner authority change would render account irrecoverable." ); wlog( "Authority is now impossible." ); } @@ -1815,10 +1858,9 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::update_account_meta(string account_name, string json_meta, bool broadcast) { - FC_ASSERT(!is_locked()); - auto accounts = my->_remote_database_api->get_accounts({account_name}); - FC_ASSERT(accounts.size() == 1, "Account does not exist"); - FC_ASSERT(account_name == accounts[0].name, "Account name doesn't match?"); + WALLET_CHECK_UNLOCKED(); + + auto account = get_account(account_name); signed_transaction tx; auto hf = my->_remote_database_api->get_hardfork_version(); @@ -1826,7 +1868,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st // TODO: remove this branch after HF 0.18 account_update_operation op; op.account = account_name; - op.memo_key = accounts[0].memo_key; + op.memo_key = account.memo_key; op.json_metadata = json_meta; tx.operations.push_back(op); } else { @@ -1841,16 +1883,14 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::update_account_memo_key( string account_name, public_key_type key, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); - auto accounts = my->_remote_database_api->get_accounts( { account_name } ); - FC_ASSERT( accounts.size() == 1, "Account does not exist" ); - FC_ASSERT( account_name == accounts[0].name, "Account name doesn't match?" ); + auto account = get_account(account_name); account_update_operation op; op.account = account_name; op.memo_key = key; - op.json_metadata = accounts[0].json_metadata; + op.json_metadata = account.json_metadata; signed_transaction tx; tx.operations.push_back(op); @@ -1860,11 +1900,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::delegate_vesting_shares(string delegator, string delegatee, asset vesting_shares, bool broadcast) { - FC_ASSERT(!is_locked()); - auto accounts = my->_remote_database_api->get_accounts({delegator, delegatee}); - FC_ASSERT(accounts.size() == 2, "One or more of the accounts specified do not exist."); - FC_ASSERT(delegator == accounts[0].name, "Delegator account is not right?"); - FC_ASSERT(delegatee == accounts[1].name, "Delegatee account is not right?"); + WALLET_CHECK_UNLOCKED(); delegate_vesting_shares_operation op; op.delegator = delegator; @@ -1886,7 +1922,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st string creator, string new_account_name, string json_meta, asset fee, bool broadcast ) { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); auto owner = suggest_brain_key(); auto active = suggest_brain_key(); auto posting = suggest_brain_key(); @@ -1918,7 +1954,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st optional props, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); const auto hf = my->_remote_database_api->get_hardfork_version(); const auto has_hf18 = hf >= hardfork_version(0, STEEMIT_HARDFORK_0_18__673); @@ -1960,7 +1996,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const optional_chain_props& props, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); signed_transaction tx; chain_properties_update_operation op; @@ -2000,7 +2036,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::vote_for_witness(string voting_account, string witness_to_vote_for, bool approve, bool broadcast ) { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); account_witness_vote_operation op; op.account = voting_account; op.witness = witness_to_vote_for; @@ -2042,30 +2078,45 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st for( auto& key_weight_pair : account.owner.key_auths ) { for( auto& key : keys ) - FC_ASSERT( key_weight_pair.first != key, "Detected private owner key in memo field. Cancelling transaction." ); + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + logic_errors::detected_private_key_in_memo, + "Detected ${type} private key in memo field", + ("type","owner")); } for( auto& key_weight_pair : account.active.key_auths ) { for( auto& key : keys ) - FC_ASSERT( key_weight_pair.first != key, "Detected private active key in memo field. Cancelling transaction." ); + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + logic_errors::detected_private_key_in_memo, + "Detected ${type} private key in memo field", + ("type","active")); } for( auto& key_weight_pair : account.posting.key_auths ) { for( auto& key : keys ) - FC_ASSERT( key_weight_pair.first != key, "Detected private posting key in memo field. Cancelling transaction." ); + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + logic_errors::detected_private_key_in_memo, + "Detected ${type} private key in memo field", + ("type","posting")); } const auto& memo_key = account.memo_key; for( auto& key : keys ) - FC_ASSERT( memo_key != key, "Detected private memo key in memo field. Cancelling transaction." ); + GOLOS_CHECK_LOGIC(memo_key != key, + logic_errors::detected_private_key_in_memo, + "Detected ${type} private key in memo field", + ("type","memo")); // Check against imported keys for( auto& key_pair : my->_keys ) { for( auto& key : keys ) - FC_ASSERT( key != key_pair.first, "Detected imported private key in memo field. Cancelling trasanction." ); + GOLOS_CHECK_LOGIC(key_pair.first != key, + logic_errors::detected_private_key_in_memo, + "Detected ${type} private key in memo field", + ("type","imported")); } } @@ -2099,7 +2150,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::transfer(string from, string to, asset amount, string memo, bool broadcast) { try { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); check_memo( memo, get_account( from ) ); transfer_operation op; op.from = from; @@ -2129,7 +2180,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); escrow_transfer_operation op; op.from = from; op.to = to; @@ -2159,7 +2210,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); escrow_approve_operation op; op.from = from; op.to = to; @@ -2183,7 +2234,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); escrow_dispute_operation op; op.from = from; op.to = to; @@ -2210,7 +2261,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); escrow_release_operation op; op.from = from; op.to = to; @@ -2232,7 +2283,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st */ annotated_signed_transaction wallet_api::transfer_to_savings( string from, string to, asset amount, string memo, bool broadcast) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); check_memo( memo, get_account( from ) ); transfer_to_savings_operation op; op.from = from; @@ -2252,7 +2303,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st */ annotated_signed_transaction wallet_api::transfer_from_savings( string from, uint32_t request_id, string to, asset amount, string memo, bool broadcast) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); check_memo( memo, get_account( from ) ); transfer_from_savings_operation op; op.from = from; @@ -2274,7 +2325,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st */ annotated_signed_transaction wallet_api::cancel_transfer_from_savings( string from, uint32_t request_id, bool broadcast) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); cancel_transfer_from_savings_operation op; op.from = from; op.request_id = request_id; @@ -2287,7 +2338,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::transfer_to_vesting(string from, string to, asset amount, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); transfer_to_vesting_operation op; op.from = from; op.to = (to == from ? "" : to); @@ -2302,7 +2353,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::withdraw_vesting(string from, asset vesting_shares, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); withdraw_vesting_operation op; op.account = from; op.vesting_shares = vesting_shares; @@ -2316,7 +2367,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::set_withdraw_vesting_route( string from, string to, uint16_t percent, bool auto_vest, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); set_withdraw_vesting_route_operation op; op.from_account = from; op.to_account = to; @@ -2332,7 +2383,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::convert_sbd(string from, asset amount, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); convert_operation op; op.owner = from; op.requestid = fc::time_point::now().sec_since_epoch(); @@ -2347,7 +2398,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::publish_feed(string witness, price exchange_rate, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); feed_publish_operation op; op.publisher = witness; op.exchange_rate = exchange_rate; @@ -2397,7 +2448,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::decline_voting_rights( string account, bool decline, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); decline_voting_rights_operation op; op.account = account; op.decline = decline; @@ -2435,7 +2486,6 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } market_history::order_book wallet_api::get_order_book( uint32_t limit ) { - FC_ASSERT( limit <= 1000 ); return my->_remote_market_history->get_order_book( limit ); } @@ -2444,7 +2494,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::create_order(string owner, uint32_t order_id, asset amount_to_sell, asset min_to_receive, bool fill_or_kill, uint32_t expiration_sec, bool broadcast) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); limit_order_create_operation op; op.owner = owner; op.orderid = order_id; @@ -2461,7 +2511,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::cancel_order( string owner, uint32_t orderid, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); limit_order_cancel_operation op; op.owner = owner; op.orderid = orderid; @@ -2474,7 +2524,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::post_comment( string author, string permlink, string parent_author, string parent_permlink, string title, string body, string json, bool broadcast ) { - FC_ASSERT( !is_locked() ); + WALLET_CHECK_UNLOCKED(); comment_operation op; op.parent_author = parent_author; op.parent_permlink = parent_permlink; @@ -2492,8 +2542,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } annotated_signed_transaction wallet_api::vote( string voter, string author, string permlink, int16_t weight, bool broadcast ) { - FC_ASSERT( !is_locked() ); - FC_ASSERT( abs(weight) <= 100, "Weight must be between -100 and 100 and not 0" ); + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(weight, GOLOS_CHECK_VALUE(abs(weight) <= 100, "Weight must be between -100 and 100")); vote_operation op; op.voter = voter; @@ -2509,7 +2559,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } void wallet_api::set_transaction_expiration(uint32_t seconds) { - my->set_transaction_expiration(seconds); + GOLOS_CHECK_PARAM(seconds, + my->set_transaction_expiration(seconds)); } annotated_signed_transaction wallet_api::get_transaction( transaction_id_type id )const { @@ -2519,7 +2570,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st vector wallet_api::get_inbox( const std::string& to, const std::string& newest_str, uint16_t limit, std::uint64_t offset ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); std::vector result; auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); auto remote_result = my->_remote_private_message->get_inbox(to, newest, limit, offset); @@ -2535,7 +2586,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st vector wallet_api::get_outbox( const std::string& from, const std::string& newest_str, uint16_t limit, std::uint64_t offset ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); std::vector result; auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); auto remote_result = my->_remote_private_message->get_outbox(from, newest, limit, offset); @@ -2640,17 +2691,17 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const string& following, const set& what, const bool broadcast) { + + GOLOS_CHECK_PARAM(following, GOLOS_CHECK_VALUE(following.size() > 0, "Empty string is not allowed")); string _following = following; auto follwer_account = get_account( follower ); - FC_ASSERT( _following.size() ); if( _following[0] != '@' || _following[0] != '#' ) { _following = '@' + _following; } if( _following[0] == '@' ) { get_account( _following.substr(1) ); } - FC_ASSERT( _following.size() > 1 ); follow::follow_operation fop; fop.follower = follower; @@ -2670,4 +2721,12 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction( trx, broadcast ); } - } } // steem::wallet +} } // golos::wallet + +FC_REFLECT_ENUM(golos::wallet::logic_errors::types, + (detected_private_key_in_memo) + (owner_authority_change_would_render_account_irrecoverable) + (private_key_not_available) + (no_account_in_lut) + (malformed_private_key) +); From 16bbdfa51fe2777d033868374ee6277b50ef39b9 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 16:31:12 +0700 Subject: [PATCH 179/250] Refactor errors: network_broadcast_api plugin (review fixes) #791 --- plugins/network_broadcast_api/network_broadcast_api.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/network_broadcast_api/network_broadcast_api.cpp b/plugins/network_broadcast_api/network_broadcast_api.cpp index ea2b1da7c1..188a513b93 100644 --- a/plugins/network_broadcast_api/network_broadcast_api.cpp +++ b/plugins/network_broadcast_api/network_broadcast_api.cpp @@ -46,7 +46,7 @@ namespace golos { (signed_transaction, trx) (uint32_t, max_block_age, 0) ); - if (args.args->size() >= 2) { + if (n_args >= 2) { GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } pimpl->_chain.accept_transaction(trx); @@ -60,7 +60,7 @@ namespace golos { (signed_transaction, trx) (uint32_t, max_block_age, 0) ); - if (args.args->size() >= 2) { + if (n_args >= 2) { GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } @@ -99,7 +99,7 @@ namespace golos { (signed_transaction, trx) (uint32_t, max_block_age, 0) ); - if (args.args->size() >= 2) { + if (n_args >= 2) { GOLOS_CHECK_PARAM(max_block_age, GOLOS_CHECK_VALUE(!check_max_block_age(max_block_age), "Invalid value")); } From a34a48eb3d60c88dc99e725e6c94ba2378b1fd69 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 16:31:29 +0700 Subject: [PATCH 180/250] Refactor errors: database_api plugin (review fixes) #791 --- plugins/database_api/api.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/database_api/api.cpp b/plugins/database_api/api.cpp index d84151ec65..63d8b60683 100755 --- a/plugins/database_api/api.cpp +++ b/plugins/database_api/api.cpp @@ -213,9 +213,18 @@ optional plugin::api_impl::get_block(uint32_t block_num) const { ////////////////////////////////////////////////////////////////////// DEFINE_API(plugin, set_block_applied_callback) { - PLUGIN_API_VALIDATE_ARGS( - (block_applied_callback_result_type, type) - ); + auto n_args = args.args->size(); + GOLOS_ASSERT(n_args == 1, golos::invalid_arguments_count, "Expected 1 parameter, received ${n}", ("n", n_args)("required",1)); + + // Use default value in case of converting errors to preserve + // previous HF behaviour, where 1st argument can be any integer + block_applied_callback_result_type type = block; + auto arg = args.args->at(0); + try { + type = arg.as(); + } catch (...) { + ilog("Bad argument (${a}) passed to set_block_applied_callback, using default", ("a",arg)); + } // Delegate connection handlers to callback msg_pack_transfer transfer(args); From 9719079b9f132b9ec746ef3cff0b6b225079fb44 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 16:31:45 +0700 Subject: [PATCH 181/250] Refactor errors: market_history plugin (review fixes) #791 --- plugins/market_history/market_history_plugin.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/market_history/market_history_plugin.cpp b/plugins/market_history/market_history_plugin.cpp index dc855ade69..c1183dfdba 100644 --- a/plugins/market_history/market_history_plugin.cpp +++ b/plugins/market_history/market_history_plugin.cpp @@ -221,8 +221,6 @@ namespace golos { } order_book market_history_plugin::market_history_plugin_impl::get_order_book(uint32_t limit) const { - GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, 500)); - const auto &order_idx = database().get_index().indices().get(); auto itr = order_idx.lower_bound(price::max(SBD_SYMBOL, STEEM_SYMBOL)); @@ -256,7 +254,6 @@ namespace golos { } order_book_extended market_history_plugin::market_history_plugin_impl::get_order_book_extended(uint32_t limit) const { - GOLOS_CHECK_LIMIT_PARAM(limit, 1000); order_book_extended result; auto max_sell = price::max(SBD_SYMBOL, STEEM_SYMBOL); @@ -299,7 +296,6 @@ namespace golos { vector market_history_plugin::market_history_plugin_impl::get_trade_history( time_point_sec start, time_point_sec end, uint32_t limit) const { - GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &bucket_idx = database().get_index().indices().get(); auto itr = bucket_idx.lower_bound(start); @@ -319,7 +315,6 @@ namespace golos { } vector market_history_plugin::market_history_plugin_impl::get_recent_trades(uint32_t limit) const { - GOLOS_CHECK_LIMIT_PARAM(limit, 1000); const auto &order_idx = database().get_index().indices().get(); auto itr = order_idx.rbegin(); @@ -467,6 +462,8 @@ namespace golos { PLUGIN_API_VALIDATE_ARGS( (uint32_t, limit) ); + GOLOS_CHECK_LIMIT_PARAM(limit, 500); + auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_order_book(limit); @@ -477,6 +474,8 @@ namespace golos { PLUGIN_API_VALIDATE_ARGS( (uint32_t, limit) ); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); + auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_order_book_extended(limit); @@ -490,6 +489,8 @@ namespace golos { (time_point_sec, end) (uint32_t, limit) ); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); + auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_trade_history(start, end, limit); @@ -500,6 +501,8 @@ namespace golos { PLUGIN_API_VALIDATE_ARGS( (uint32_t, limit) ); + GOLOS_CHECK_LIMIT_PARAM(limit, 1000); + auto &db = _my->database(); return db.with_weak_read_lock([&]() { return _my->get_recent_trades(limit); From e978da8d58e47a49ba685e46cbe499ed0d4183fe Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 17:39:25 +0700 Subject: [PATCH 182/250] Refactor errors: add unsupported_api_method #791 --- libraries/protocol/include/golos/protocol/exceptions.hpp | 4 ++++ plugins/tags/plugin.cpp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 02201faa22..37e6bf335e 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -151,6 +151,10 @@ namespace golos { unsupported_operation, operation_exception, 1010000, "Unsupported operation"); + GOLOS_DECLARE_DERIVED_EXCEPTION( + unsupported_api_method, unsupported_operation, + 1010100, "Unsupported api method"); + GOLOS_DECLARE_DERIVED_EXCEPTION( parameter_exception, operation_exception, 1020000, "Parameter exception"); diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 22b7e56dba..05cd43b19a 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -549,7 +549,7 @@ namespace golos { namespace plugins { namespace tags { GOLOS_CHECK_VALUE(query.select_authors.size(), "Must get blogs for specific authors")); auto& db = pimpl->database(); - GOLOS_ASSERT(db.has_index(), golos::unsupported_operation, + GOLOS_ASSERT(db.has_index(), golos::unsupported_api_method, "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { @@ -571,7 +571,7 @@ namespace golos { namespace plugins { namespace tags { GOLOS_CHECK_VALUE(query.select_authors.size(), "Must get feeds for specific authors")); auto& db = pimpl->database(); - GOLOS_ASSERT(db.has_index(), golos::unsupported_operation, + GOLOS_ASSERT(db.has_index(), golos::unsupported_api_method, "Node is not running the follow plugin"); return db.with_weak_read_lock([&]() { From fb56ec952b6be87550b01dd127c56fc806f25fc7 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 17:24:32 +0700 Subject: [PATCH 183/250] Refactor errors: add protocol & database logic_exception codes #792 --- .../include/golos/protocol/exceptions.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 3d838221bc..7f779def5e 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -330,6 +330,15 @@ namespace golos { account_already_scheduled_for_work, cannot_specify_owner_key_unless_creating_account, witness_must_be_created_before_minning, + + // custom operations + inner_authorities_does_not_match_outer, + + // database logic + account_exceeded_bandwidth_per_vestring_share, + + // protocol logic + cannot_mix_posting_and_active_owner_autority_operation, }; }; @@ -559,6 +568,15 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (account_already_scheduled_for_work) (cannot_specify_owner_key_unless_creating_account) (witness_must_be_created_before_minning) + + // custom operations + (inner_authorities_does_not_match_outer) + + // database logic + (account_exceeded_bandwidth_per_vestring_share) + + // protocol logic + (cannot_mix_posting_and_active_owner_autority_operation) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, From 4f4cba567d07a59915ebd324813486f2ce9aa4fd Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 17:25:18 +0700 Subject: [PATCH 184/250] Refactor errors: database library #793 --- libraries/chain/database.cpp | 7 ++++--- .../generic_custom_operation_interpreter.hpp | 20 +++++++++++++++---- libraries/chain/shared_authority.cpp | 4 +++- libraries/chain/steem_evaluator.cpp | 9 +++++---- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 99a1133eb8..400b14c5d6 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -793,8 +793,7 @@ namespace golos { namespace chain { } void database::pay_fee(const account_object &account, asset fee) { - FC_ASSERT(fee.amount >= - 0); /// NOTE if this fails then validate() on some operation is probably wrong + FC_ASSERT(fee.amount >= 0); /// NOTE if this fails then validate() on some operation is probably wrong if (fee.amount == 0) { return; } @@ -847,7 +846,9 @@ namespace golos { namespace chain { has_bandwidth = (account_vshares * max_virtual_bandwidth) > (account_average_bandwidth * total_vshares); if (is_producing()) - FC_ASSERT(has_bandwidth, "Account exceeded maximum allowed bandwidth per vesting share.", + GOLOS_CHECK_LOGIC(has_bandwidth, + logic_exception::account_exceeded_bandwidth_per_vestring_share, + "Account exceeded maximum allowed bandwidth per vesting share.", ("account_vshares", account_vshares) ("account_average_bandwidth", account_average_bandwidth) ("max_virtual_bandwidth", max_virtual_bandwidth) diff --git a/libraries/chain/include/golos/chain/generic_custom_operation_interpreter.hpp b/libraries/chain/include/golos/chain/generic_custom_operation_interpreter.hpp index 05b53f56dc..3a5a0ab99c 100644 --- a/libraries/chain/include/golos/chain/generic_custom_operation_interpreter.hpp +++ b/libraries/chain/include/golos/chain/generic_custom_operation_interpreter.hpp @@ -47,10 +47,22 @@ namespace golos { operation_get_required_authorities(inner_o, inner_active, inner_owner, inner_posting, inner_other); } - FC_ASSERT(inner_owner == outer_owner); - FC_ASSERT(inner_active == outer_active); - FC_ASSERT(inner_posting == outer_posting); - FC_ASSERT(inner_other == outer_other); + GOLOS_CHECK_LOGIC(inner_owner == outer_owner, + logic_exception::inner_authorities_does_not_match_outer, + "Owner authorities for inner operations are not equal to those for operation", + ("authority","owner")("inner",inner_owner)("outer",outer_owner)); + GOLOS_CHECK_LOGIC(inner_active == outer_active, + logic_exception::inner_authorities_does_not_match_outer, + "Active authorities for inner operations are not equal to those for operation", + ("authority","active")("inner",inner_active)("outer",outer_active)); + GOLOS_CHECK_LOGIC(inner_posting == outer_posting, + logic_exception::inner_authorities_does_not_match_outer, + "Posting authorities for inner operations are not equal to those for operation", + ("authority","posting")("inner",inner_posting)("outer",outer_posting)); + GOLOS_CHECK_LOGIC(inner_other == outer_other, + logic_exception::inner_authorities_does_not_match_outer, + "Other authorities for inner operations are not equal to those for operation", + ("authority","other")("inner",inner_other)("outer",outer_other)); for (const CustomOperationType &inner_o : custom_operations) { // gcc errors if this-> is not here diff --git a/libraries/chain/shared_authority.cpp b/libraries/chain/shared_authority.cpp index 2b090b0504..3b235467a5 100644 --- a/libraries/chain/shared_authority.cpp +++ b/libraries/chain/shared_authority.cpp @@ -1,4 +1,5 @@ #include +#include namespace golos { namespace chain { @@ -76,7 +77,8 @@ namespace golos { void shared_authority::validate() const { for (const auto &item : account_auths) { - FC_ASSERT(protocol::is_valid_account_name(item.first)); + GOLOS_CHECK_VALUE(protocol::is_valid_account_name(item.first), + "Account name \"${account}\" is invalid", ("account",item.first)); } } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 329c0b4db7..8eb18388f7 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -78,7 +78,7 @@ namespace golos { namespace chain { GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.available_vesting_shares(false); case AVAILABLE_VESTING: - FC_ASSERT(symbol == VESTS_SYMBOL, "invalid symbol"); + GOLOS_CHECK_VALUE(symbol == VESTS_SYMBOL, "invalid symbol"); return account.available_vesting_shares(true); default: FC_ASSERT(false, "invalid balance type"); } @@ -97,9 +97,10 @@ namespace golos { namespace chain { } inline void validate_permlink_0_1(const string &permlink) { - FC_ASSERT(permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && - permlink.size() < - STEEMIT_MAX_PERMLINK_LENGTH, "Permlink is not a valid size."); + GOLOS_CHECK_VALUE(permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && + permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH, + "Permlink is not a valid size. Permlink length should be more ${min} and less ${max}", + ("min", STEEMIT_MIN_PERMLINK_LENGTH)("max", STEEMIT_MAX_PERMLINK_LENGTH)); for (auto c : permlink) { switch (c) { From 912bd24f0d2cb0a0b2f3efc76451719f8fc239bb Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Fri, 27 Jul 2018 17:25:48 +0700 Subject: [PATCH 185/250] Refactor errors: protocol library #792 --- libraries/protocol/asset.cpp | 7 ++-- libraries/protocol/transaction.cpp | 20 +++++++---- libraries/protocol/types.cpp | 54 ++++++++++-------------------- libraries/protocol/version.cpp | 15 ++++----- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/libraries/protocol/asset.cpp b/libraries/protocol/asset.cpp index 6dec81a0c8..4eb8ab4707 100644 --- a/libraries/protocol/asset.cpp +++ b/libraries/protocol/asset.cpp @@ -66,18 +66,19 @@ namespace golos { auto space_pos = s.find(" "); auto dot_pos = s.find("."); - FC_ASSERT(space_pos != std::string::npos); + GOLOS_CHECK_VALUE(space_pos != std::string::npos, "Invalid asset notation"); asset result; result.symbol = uint64_t(0); auto sy = (char *)&result.symbol; if (dot_pos != std::string::npos) { - FC_ASSERT(space_pos > dot_pos); + GOLOS_CHECK_VALUE(space_pos > dot_pos, "Invalid asset notation"); auto intpart = s.substr(0, dot_pos); auto fractpart = "1" + s.substr( dot_pos + 1, space_pos - dot_pos - 1); + GOLOS_CHECK_VALUE(fractpart.size() - 1 < 15, "Asset fraction part is too length"); result.set_decimals(fractpart.size() - 1); result.amount = fc::to_int64(intpart); @@ -93,7 +94,7 @@ namespace golos { size_t symbol_size = symbol.size(); if (symbol_size > 0) { - FC_ASSERT(symbol_size <= 6); + GOLOS_CHECK_VALUE(symbol_size <= 6, "Asset symbol is too length"); memcpy(sy + 1, symbol.c_str(), symbol_size); } diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index 6799e4f107..bd917309d5 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -28,8 +28,9 @@ namespace golos { } void transaction::validate() const { - FC_ASSERT(operations.size() > - 0, "A transaction must have at least one operation", ("trx", *this)); + GOLOS_ASSERT(operations.size() > 0, + golos::protocol::transaction_exception, + "A transaction must have at least one operation", ("trx", *this)); uint32_t _current_op_in_trx = 0; for (const auto &op : operations) { @@ -133,9 +134,11 @@ namespace golos { * check for the merged authority of active and posting. */ if (required_posting.size()) { - FC_ASSERT(required_active.size() == 0); - FC_ASSERT(required_owner.size() == 0); - FC_ASSERT(other.size() == 0); + GOLOS_CHECK_LOGIC( + required_active.size() == 0 && required_owner.size() == 0 && other.size() == 0, + logic_exception::cannot_mix_posting_and_active_owner_autority_operation, + "Transactions with operations required posting authority cannot be combined " + "with transactions requiring active or owner authority"); sign_state s(sigs, get_posting, avail); s.max_recursion = max_recursion_depth; @@ -266,8 +269,11 @@ namespace golos { sign_state s(get_signature_keys(chain_id), get_posting, available_keys); s.max_recursion = max_recursion_depth; - FC_ASSERT(!required_owner.size()); - FC_ASSERT(!required_active.size()); + GOLOS_CHECK_LOGIC( + required_active.size() == 0 && required_owner.size() == 0, + logic_exception::cannot_mix_posting_and_active_owner_autority_operation, + "Transactions with operations required posting authority cannot be combined " + "with transactions requiring active or owner authority"); for (auto &posting : required_posting) { s.check_authority(posting); } diff --git a/libraries/protocol/types.cpp b/libraries/protocol/types.cpp index 2fbe075bc8..fd0577f4da 100644 --- a/libraries/protocol/types.cpp +++ b/libraries/protocol/types.cpp @@ -13,6 +13,21 @@ namespace golos { namespace protocol { + template + binary_key key_data_from_string(const std::string &base58str) { + std::string prefix(STEEMIT_ADDRESS_PREFIX); + + const size_t prefix_len = prefix.size(); + GOLOS_CHECK_VALUE(base58str.size() > prefix_len, "Public key is too short"); + GOLOS_CHECK_VALUE(base58str.substr(0, prefix_len) == prefix, "Invalid public key prefix", ("base58str", base58str)); + auto bin = fc::from_base58(base58str.substr(prefix_len)); + auto bin_key = fc::raw::unpack(bin); // TODO catch exceptions from unpack + auto key_data = bin_key.data; + GOLOS_CHECK_VALUE(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check, + "Invalid public key"); + return bin_key; + } + public_key_type::public_key_type() : key_data() { }; @@ -27,18 +42,7 @@ namespace golos { public_key_type::public_key_type(const std::string &base58str) { // TODO: Refactor syntactic checks into static is_valid() // to make public_key_type API more similar to address API - std::string prefix(STEEMIT_ADDRESS_PREFIX); - - const size_t prefix_len = prefix.size(); - FC_ASSERT(base58str.size() > prefix_len); - FC_ASSERT(base58str.substr(0, prefix_len) == - prefix, "", ("base58str", base58str)); - auto bin = fc::from_base58(base58str.substr(prefix_len)); - auto bin_key = fc::raw::unpack(bin); - key_data = bin_key.data; - FC_ASSERT( - fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == - bin_key.check); + key_data = key_data_from_string(base58str).data; }; @@ -85,18 +89,7 @@ namespace golos { }; extended_public_key_type::extended_public_key_type(const std::string &base58str) { - std::string prefix(STEEMIT_ADDRESS_PREFIX); - - const size_t prefix_len = prefix.size(); - FC_ASSERT(base58str.size() > prefix_len); - FC_ASSERT(base58str.substr(0, prefix_len) == - prefix, "", ("base58str", base58str)); - auto bin = fc::from_base58(base58str.substr(prefix_len)); - auto bin_key = fc::raw::unpack(bin); - FC_ASSERT( - fc::ripemd160::hash(bin_key.data.data, bin_key.data.size())._hash[0] == - bin_key.check); - key_data = bin_key.data; + key_data = key_data_from_string(base58str).data; } extended_public_key_type::operator fc::ecc::extended_public_key() const { @@ -138,18 +131,7 @@ namespace golos { }; extended_private_key_type::extended_private_key_type(const std::string &base58str) { - std::string prefix(STEEMIT_ADDRESS_PREFIX); - - const size_t prefix_len = prefix.size(); - FC_ASSERT(base58str.size() > prefix_len); - FC_ASSERT(base58str.substr(0, prefix_len) == - prefix, "", ("base58str", base58str)); - auto bin = fc::from_base58(base58str.substr(prefix_len)); - auto bin_key = fc::raw::unpack(bin); - FC_ASSERT( - fc::ripemd160::hash(bin_key.data.data, bin_key.data.size())._hash[0] == - bin_key.check); - key_data = bin_key.data; + key_data = key_data_from_string(base58str).data; } extended_private_key_type::operator fc::ecc::extended_private_key() const { diff --git a/libraries/protocol/version.cpp b/libraries/protocol/version.cpp index c058628204..eb36fb548f 100644 --- a/libraries/protocol/version.cpp +++ b/libraries/protocol/version.cpp @@ -1,6 +1,5 @@ #include - -#include +#include namespace golos { namespace protocol { @@ -52,12 +51,12 @@ namespace fc { s >> major >> dot_a >> hardfork >> dot_b >> revision; // We'll accept either m.h.v or m_h_v as canonical version strings - FC_ASSERT((dot_a == '.' || dot_a == '_') && dot_a == - dot_b, "Variant does not contain proper dotted decimal format"); - FC_ASSERT(major <= 0xFF, "Major version is out of range"); - FC_ASSERT(hardfork <= 0xFF, "Hardfork version is out of range"); - FC_ASSERT(revision <= 0xFFFF, "Revision version is out of range"); - FC_ASSERT(s.eof(), "Extra information at end of version string"); + GOLOS_CHECK_VALUE((dot_a == '.' || dot_a == '_') && dot_a == dot_b, + "Variant does not contain proper dotted decimal format"); + GOLOS_CHECK_VALUE(major <= 0xFF, "Major version is out of range"); + GOLOS_CHECK_VALUE(hardfork <= 0xFF, "Hardfork version is out of range"); + GOLOS_CHECK_VALUE(revision <= 0xFFFF, "Revision version is out of range"); + GOLOS_CHECK_VALUE(s.eof(), "Extra information at end of version string"); v.v_num = 0 | (major << 24) | (hardfork << 16) | revision; } From 70df1e5db9359cb28e044a30ca15d41bf005508f Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 30 Jul 2018 11:36:10 +0300 Subject: [PATCH 186/250] Add option to delete votes older n blocks #801 --- libraries/chain/database.cpp | 36 +-- .../include/golos/chain/comment_object.hpp | 79 +++-- .../chain/include/golos/chain/database.hpp | 4 +- libraries/chain/steem_evaluator.cpp | 206 +++++------- libraries/protocol/steem_operations.cpp | 6 +- .../include/golos/plugins/chain/plugin.hpp | 33 +- plugins/chain/plugin.cpp | 144 +++++---- plugins/social_network/social_network.cpp | 8 +- tests/common/database_fixture.cpp | 1 - tests/common/database_fixture.hpp | 8 +- tests/plugin_tests/account_history.cpp | 2 +- tests/plugin_tests/chain.cpp | 297 ++++++++++++++++++ tests/plugin_tests/operation_history.cpp | 4 +- tests/tests/operation_time_tests.cpp | 21 +- 14 files changed, 525 insertions(+), 324 deletions(-) create mode 100644 tests/plugin_tests/chain.cpp diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 99a1133eb8..ce1d7e5704 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -344,13 +344,6 @@ namespace golos { namespace chain { _block_num_check_free_memory = value; } - void database::set_clear_votes(uint32_t clear_votes_block) { - _clear_votes_block = clear_votes_block; - } - - bool database::clear_votes() { - return _clear_votes_block > head_block_num(); - } void database::set_store_account_metadata(store_metadata_modes store_account_metadata) { _store_account_metadata = store_account_metadata; @@ -2339,9 +2332,7 @@ namespace golos { namespace chain { author_tokens -= total_beneficiary; - auto sbd_steem = (author_tokens * - comment.percent_steem_dollars) / - (2 * STEEMIT_100_PERCENT); + auto sbd_steem = (author_tokens * comment.percent_steem_dollars) / (2 * STEEMIT_100_PERCENT); auto vesting_steem = author_tokens - sbd_steem; const auto &author = get_account(comment.author); @@ -2376,7 +2367,6 @@ namespace golos { namespace chain { a.posting_rewards += author_tokens; }); #endif - } fc::uint128_t old_rshares2 = calculate_vshares(comment.net_rshares.value); @@ -2400,15 +2390,14 @@ namespace golos { namespace chain { if (has_hardfork(STEEMIT_HARDFORK_0_17__431)) { c.cashout_time = fc::time_point_sec::maximum(); } else if (c.parent_author == STEEMIT_ROOT_POST_PARENT) { - if (has_hardfork(STEEMIT_HARDFORK_0_12__177) && c.last_payout == fc::time_point_sec::min()) { + if (c.last_payout == fc::time_point_sec::min()) { c.cashout_time = head_block_time() + STEEMIT_SECOND_CASHOUT_WINDOW; } else { c.cashout_time = fc::time_point_sec::maximum(); } } - if (calculate_discussion_payout_time(c) == - fc::time_point_sec::maximum()) { + if (calculate_discussion_payout_time(c) == fc::time_point_sec::maximum()) { c.mode = archived; } else { c.mode = second_payout; @@ -2419,22 +2408,15 @@ namespace golos { namespace chain { push_virtual_operation(comment_payout_update_operation(comment.author, to_string(comment.permlink))); - const auto &vote_idx = get_index().indices().get(); + const auto& vote_idx = get_index().indices().get(); auto vote_itr = vote_idx.lower_bound(comment.id); - while (vote_itr != vote_idx.end() && - vote_itr->comment == comment.id) { - const auto &cur_vote = *vote_itr; + while (vote_itr != vote_idx.end() && vote_itr->comment == comment.id) { + const auto& cur_vote = *vote_itr; ++vote_itr; - if (!has_hardfork(STEEMIT_HARDFORK_0_12__177) || - calculate_discussion_payout_time(comment) != - fc::time_point_sec::maximum()) { - modify(cur_vote, [&](comment_vote_object &cvo) { - cvo.num_changes = -1; + if (comment.mode == archived) { + modify(cur_vote, [&](comment_vote_object& cvo) { + cvo.num_changes = -1; // mark vote that it's ready to be removed (archived comment) }); - } else { - if(clear_votes()) { - remove(cur_vote); - } } } } FC_CAPTURE_AND_RETHROW() diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index 62758c0706..ac1957fd97 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -130,54 +130,47 @@ namespace golos { int64_t rshares = 0; ///< The number of rshares this vote is responsible for int16_t vote_percent = 0; ///< The percent weight of the vote time_point_sec last_update; ///< The time of the last update of the vote - int8_t num_changes = 0; + int8_t num_changes = 0; ///< Count of vote changes (while consensus). If = -1 then related post is archived & vote no more needed for consensus }; struct by_comment_voter; struct by_voter_comment; struct by_comment_weight_voter; - struct by_voter_last_update; - typedef multi_index_container < - comment_vote_object, - indexed_by< - ordered_unique < tag < - by_id>, member>, - ordered_unique , - composite_key, - member - > - >, - ordered_unique , - composite_key, - member - > - >, - ordered_unique , - composite_key, - member, - member - >, - composite_key_compare , std::greater, std::less> - >, - ordered_unique , - composite_key, - member, - member - >, - composite_key_compare , std::greater, std::less> - > - >, - allocator - > - comment_vote_index; + struct by_vote_last_update; + using comment_vote_index = multi_index_container< + comment_vote_object, + indexed_by< + ordered_unique, + member>, + ordered_unique, + composite_key, + member + > + >, + ordered_unique, + composite_key, + member + > + >, + ordered_non_unique, + composite_key, + member + > + >, + ordered_unique, + composite_key, + member, + member + >, + composite_key_compare, std::greater, std::less> + > + >, + allocator + >; struct by_cashout_time; /// cashout_time diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 925c9c3a2b..743519ad09 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -102,9 +102,7 @@ namespace golos { namespace chain { void set_block_num_check_free_size(uint32_t); void check_free_memory(bool skip_print, uint32_t current_block_num); - void set_clear_votes(uint32_t clear_votes_block); void set_skip_virtual_ops(); - bool clear_votes(); void set_store_account_metadata(store_metadata_modes store_account_metadata); void set_accounts_to_store_metadata(const std::vector& accounts_to_store_metadata); @@ -615,7 +613,7 @@ namespace golos { namespace chain { template friend void add_plugin_index(database &db); - friend class database_fixture; + friend struct database_fixture; fc::signal _plugin_index_signal; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 329c0b4db7..0cdff71c7e 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -142,7 +142,7 @@ namespace golos { namespace chain { case '-': break; default: - FC_THROW_EXCEPTION(invalid_value, "Invalid permlink character: ${s}", + FC_THROW_EXCEPTION(invalid_value, "Invalid permlink character: ${s}", ("s", std::string() + c)); } } @@ -574,17 +574,9 @@ namespace golos { namespace chain { if (itr == by_permlink_idx.end()) { if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { - GOLOS_CHECK_LOGIC(_db.get(parent->root_comment).allow_replies, + GOLOS_CHECK_LOGIC(_db.get(parent->root_comment).allow_replies, logic_exception::replies_are_not_allowed, "The parent comment has disabled replies."); - - if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && !_db.has_hardfork( STEEMIT_HARDFORK_0_18__536) ) { - GOLOS_CHECK_LOGIC( - _db.calculate_discussion_payout_time(*parent) != - fc::time_point_sec::maximum(), - logic_exception::discussion_is_frozen, - "Discussion is frozen."); - } } auto band = _db.find(std::make_tuple(o.author, bandwidth_type::post)); @@ -703,22 +695,10 @@ namespace golos { namespace chain { } } - } else // start edit case - { - const auto &comment = *itr; - if ( !_db.has_hardfork( STEEMIT_HARDFORK_0_18__536 ) ) { - if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__306)) { - GOLOS_CHECK_LOGIC(_db.calculate_discussion_payout_time(comment) != fc::time_point_sec::maximum(), - logic_exception::comment_is_archived, - "The comment is archived."); - } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) { - GOLOS_CHECK_LOGIC(comment.last_payout == fc::time_point_sec::min(), - logic_exception::comment_editable_during_first_24_hours, - "Can only edit during the first 24 hours."); - } - } - - _db.modify(comment, [&](comment_object &com) { + } else { + // start edit case + const auto& comment = *itr; + _db.modify(comment, [&](comment_object& com) { com.last_update = _db.head_block_time(); com.active = com.last_update; strcmp_equal equal; @@ -978,7 +958,7 @@ namespace golos { namespace chain { if (o.vesting_shares.amount == 0) { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__57)) - GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate.amount != 0, + GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate.amount != 0, logic_exception::operation_would_not_change_vesting_withdraw_rate, "This operation would not change the vesting withdraw rate."); @@ -1004,7 +984,7 @@ namespace golos { namespace chain { if (_db.is_producing() || _db.has_hardfork(STEEMIT_HARDFORK_0_5__57)) - GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate != new_vesting_withdraw_rate, + GOLOS_CHECK_LOGIC(account.vesting_withdraw_rate != new_vesting_withdraw_rate, logic_exception::operation_would_not_change_vesting_withdraw_rate, "This operation would not change the vesting withdraw rate."); @@ -1028,7 +1008,7 @@ namespace golos { namespace chain { GOLOS_CHECK_LOGIC(o.percent != 0, logic_exception::cannot_create_zero_percent_destination, "Cannot create a 0% destination."); - GOLOS_CHECK_LOGIC(from_account.withdraw_routes < STEEMIT_MAX_WITHDRAW_ROUTES, + GOLOS_CHECK_LOGIC(from_account.withdraw_routes < STEEMIT_MAX_WITHDRAW_ROUTES, logic_exception::reached_maxumum_number_of_routes, "Account already has the maximum number of routes (${max}).", ("max",STEEMIT_MAX_WITHDRAW_ROUTES)); @@ -1067,7 +1047,7 @@ namespace golos { namespace chain { ++itr; } - GOLOS_CHECK_LOGIC(total_percent <= STEEMIT_100_PERCENT, + GOLOS_CHECK_LOGIC(total_percent <= STEEMIT_100_PERCENT, logic_exception::more_100percent_allocated_to_destinations, "More than 100% of vesting withdrawals allocated to destinations."); } @@ -1076,7 +1056,7 @@ namespace golos { namespace chain { void account_witness_proxy_evaluator::do_apply(const account_witness_proxy_operation &o) { const auto &account = _db.get_account(o.account); - GOLOS_CHECK_LOGIC(account.proxy != o.proxy, + GOLOS_CHECK_LOGIC(account.proxy != o.proxy, logic_exception::proxy_must_change, "Proxy must change."); @@ -1133,12 +1113,12 @@ namespace golos { namespace chain { void account_witness_vote_evaluator::do_apply(const account_witness_vote_operation &o) { const auto &voter = _db.get_account(o.account); - GOLOS_CHECK_LOGIC(voter.proxy.size() == 0, + GOLOS_CHECK_LOGIC(voter.proxy.size() == 0, logic_exception::cannot_vote_when_route_are_set, "A proxy is currently set, please clear the proxy before voting for a witness."); if (o.approve) - GOLOS_CHECK_LOGIC(voter.can_vote, + GOLOS_CHECK_LOGIC(voter.can_vote, logic_exception::voter_declined_voting_rights, "Account has declined its voting rights."); @@ -1148,12 +1128,12 @@ namespace golos { namespace chain { auto itr = by_account_witness_idx.find(boost::make_tuple(voter.id, witness.id)); if (itr == by_account_witness_idx.end()) { - GOLOS_CHECK_LOGIC(o.approve, + GOLOS_CHECK_LOGIC(o.approve, logic_exception::witness_vote_does_not_exist, "Vote doesn't exist, user must indicate a desire to approve witness."); if (_db.has_hardfork(STEEMIT_HARDFORK_0_2)) { - GOLOS_CHECK_LOGIC(voter.witnesses_voted_for < STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, + GOLOS_CHECK_LOGIC(voter.witnesses_voted_for < STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, logic_exception::account_has_too_many_witness_votes, "Account has voted for too many witnesses.", ("max_votes", STEEMIT_MAX_ACCOUNT_WITNESS_VOTES)); // TODO: Remove after hardfork 2 @@ -1185,7 +1165,7 @@ namespace golos { namespace chain { }); } else { - GOLOS_CHECK_LOGIC(!o.approve, + GOLOS_CHECK_LOGIC(!o.approve, logic_exception::witness_vote_already_exist, "Vote currently exists, user must indicate a desire to reject witness."); @@ -1207,83 +1187,76 @@ namespace golos { namespace chain { } } - void vote_evaluator::do_apply(const vote_operation &o) { + void vote_evaluator::do_apply(const vote_operation& o) { try { - const auto &comment = _db.get_comment(o.author, o.permlink); - const auto &voter = _db.get_account(o.voter); + const auto& comment = _db.get_comment(o.author, o.permlink); + const auto& voter = _db.get_account(o.voter); - if (_db.has_hardfork(STEEMIT_HARDFORK_0_10)) - GOLOS_CHECK_LOGIC(!(voter.owner_challenged || voter.active_challenged), - logic_exception::account_is_currently_challenged, - "Account \"${account}\" is currently challenged", ("account", voter.name)); + GOLOS_CHECK_LOGIC(!(voter.owner_challenged || voter.active_challenged), + logic_exception::account_is_currently_challenged, + "Account \"${account}\" is currently challenged", ("account", voter.name)); GOLOS_CHECK_LOGIC(voter.can_vote, logic_exception::voter_declined_voting_rights, - "Voter has declined their voting rights"); + "Voter has declined their voting rights"); - if (o.weight > 0) + if (o.weight > 0) { GOLOS_CHECK_LOGIC(comment.allow_votes, logic_exception::votes_are_not_allowed, - "Votes are not allowed on the comment."); - - if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && - _db.calculate_discussion_payout_time(comment) == - fc::time_point_sec::maximum() - ) { - if(!_db.clear_votes()) { - const auto& comment_vote_idx = _db.get_index< comment_vote_index >().indices().get< by_comment_voter >(); - auto itr = comment_vote_idx.find( std::make_tuple( comment.id, voter.id ) ); - - if( itr == comment_vote_idx.end() ) - _db.create< comment_vote_object >( [&]( comment_vote_object& cvo ) { - cvo.voter = voter.id; - cvo.comment = comment.id; - cvo.vote_percent = o.weight; - cvo.last_update = _db.head_block_time(); - }); - else - _db.modify( *itr, [&]( comment_vote_object& cvo ) { - cvo.vote_percent = o.weight; - cvo.last_update = _db.head_block_time(); + "Votes are not allowed on the comment."); + } + + if (_db.calculate_discussion_payout_time(comment) == fc::time_point_sec::maximum()) { + // non-consensus vote (after cashout) + const auto& comment_vote_idx = _db.get_index().indices().get(); + auto itr = comment_vote_idx.find(std::make_tuple(comment.id, voter.id)); + if (itr == comment_vote_idx.end()) { + _db.create([&](comment_vote_object& cvo) { + cvo.voter = voter.id; + cvo.comment = comment.id; + cvo.vote_percent = o.weight; + cvo.last_update = _db.head_block_time(); + cvo.num_changes = -1; // mark vote that it's ready to be removed (archived comment) + }); + } else { + _db.modify(*itr, [&](comment_vote_object& cvo) { + cvo.vote_percent = o.weight; + cvo.last_update = _db.head_block_time(); }); } return; } - const auto &comment_vote_idx = _db.get_index().indices().get(); + const auto& comment_vote_idx = _db.get_index().indices().get(); auto itr = comment_vote_idx.find(std::make_tuple(comment.id, voter.id)); - int64_t elapsed_seconds = (_db.head_block_time() - - voter.last_vote_time).to_seconds(); + int64_t elapsed_seconds = (_db.head_block_time() - voter.last_vote_time).to_seconds(); - if (_db.has_hardfork(STEEMIT_HARDFORK_0_11)) - GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), voter.last_vote_time + STEEMIT_MIN_VOTE_INTERVAL_SEC-1, - bandwidth_exception::vote_bandwidth, "Can only vote once every 3 seconds."); + GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), voter.last_vote_time + STEEMIT_MIN_VOTE_INTERVAL_SEC-1, + bandwidth_exception::vote_bandwidth, "Can only vote once every 3 seconds."); int64_t regenerated_power = (STEEMIT_100_PERCENT * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; - int64_t current_power = std::min(int64_t(voter.voting_power + - regenerated_power), int64_t(STEEMIT_100_PERCENT)); + int64_t current_power = std::min( + int64_t(voter.voting_power + regenerated_power), + int64_t(STEEMIT_100_PERCENT)); GOLOS_CHECK_LOGIC(current_power > 0, logic_exception::does_not_have_voting_power, "Account currently does not have voting power."); int64_t abs_weight = abs(o.weight); - int64_t used_power = - (current_power * abs_weight) / STEEMIT_100_PERCENT; + int64_t used_power = (current_power * abs_weight) / STEEMIT_100_PERCENT; const dynamic_global_property_object &dgpo = _db.get_dynamic_global_properties(); // used_power = (current_power * abs_weight / STEEMIT_100_PERCENT) * (reserve / max_vote_denom) // The second multiplication is rounded up as of HF 259 int64_t max_vote_denom = dgpo.vote_regeneration_per_day * - STEEMIT_VOTE_REGENERATION_SECONDS / - (60 * 60 * 24); + STEEMIT_VOTE_REGENERATION_SECONDS / (60 * 60 * 24); GOLOS_ASSERT(max_vote_denom > 0, golos::internal_error, "max_vote_denom is too small"); if (!_db.has_hardfork(STEEMIT_HARDFORK_0_14__259)) { used_power = (used_power / max_vote_denom) + 1; } else { - used_power = - (used_power + max_vote_denom - 1) / max_vote_denom; + used_power = (used_power + max_vote_denom - 1) / max_vote_denom; } GOLOS_CHECK_LOGIC(used_power <= current_power, logic_exception::does_not_have_voting_power, "Account does not have enough power to vote."); @@ -1296,40 +1269,25 @@ namespace golos { namespace chain { } if (_db.has_hardfork(STEEMIT_HARDFORK_0_14__259)) { - GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || o.weight == 0, + GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || o.weight == 0, logic_exception::voting_weight_is_too_small, "Voting weight is too small, please accumulate more voting power or steem power."); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_13__248)) { - GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || abs_rshares == 1, + GOLOS_CHECK_LOGIC(abs_rshares > 30000000 || abs_rshares == 1, logic_exception::voting_weight_is_too_small, "Voting weight is too small, please accumulate more voting power or steem power."); } - - // Lazily delete vote - if (itr != comment_vote_idx.end() && itr->num_changes == -1) { - if (_db.is_producing() || - _db.has_hardfork(STEEMIT_HARDFORK_0_12__177)) - GOLOS_CHECK_LOGIC(false, logic_exception::cannot_vote_after_payout, - "Cannot vote again on a comment after payout."); - - _db.remove(*itr); - itr = comment_vote_idx.end(); - } - if (itr == comment_vote_idx.end()) { GOLOS_CHECK_OP_PARAM(o, weight, GOLOS_CHECK_VALUE(o.weight != 0, "Vote weight cannot be 0")); /// this is the rshares voting for or against the post int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; - if (rshares > 0) { - if (_db.has_hardfork(STEEMIT_HARDFORK_0_7)) { - GOLOS_CHECK_LOGIC(_db.head_block_time() < - _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, - logic_exception::cannot_vote_within_last_minute_before_payout, - "Cannot increase reward of post within the last minute before payout."); - } + GOLOS_CHECK_LOGIC(_db.head_block_time() < + _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, + logic_exception::cannot_vote_within_last_minute_before_payout, + "Cannot increase reward of post within the last minute before payout."); } //used_power /= (50*7); /// a 100% vote means use .28% of voting power which should force users to spread their votes around over 50+ posts day for a week @@ -1380,8 +1338,7 @@ namespace golos { namespace chain { } else { c.net_votes--; } - if (!_db.has_hardfork(STEEMIT_HARDFORK_0_6__114) && - c.net_rshares == -c.abs_rshares) + if (!_db.has_hardfork(STEEMIT_HARDFORK_0_6__114) && c.net_rshares == -c.abs_rshares) GOLOS_ASSERT(c.net_votes < 0, golos::internal_error, "Comment has negative network votes?"); }); @@ -1455,8 +1412,7 @@ namespace golos { namespace chain { rshares3 = rshares3 * rshares3 * rshares3; total2 *= total2; - cv.weight = static_cast( rshares3 / - total2 ); + cv.weight = static_cast(rshares3 / total2); } else {// cv.weight = W(R_1) - W(R_0) if (_db.has_hardfork(STEEMIT_HARDFORK_0_1)) { uint64_t old_weight = ( @@ -1509,38 +1465,33 @@ namespace golos { namespace chain { } }); - if (max_vote_weight) // Optimization - { - _db.modify(comment, [&](comment_object &c) { + if (max_vote_weight) { + // Optimization + _db.modify(comment, [&](comment_object& c) { c.total_vote_weight += max_vote_weight; }); } _db.adjust_rshares2(comment, old_rshares, new_rshares); } else { - GOLOS_CHECK_LOGIC(itr->num_changes < STEEMIT_MAX_VOTE_CHANGES, + GOLOS_CHECK_LOGIC(itr->num_changes < STEEMIT_MAX_VOTE_CHANGES, logic_exception::voter_has_used_maximum_vote_changes, "Voter has used the maximum number of vote changes on this comment."); - - if (_db.is_producing() || - _db.has_hardfork(STEEMIT_HARDFORK_0_6__112)) - GOLOS_CHECK_LOGIC(itr->vote_percent != o.weight, - logic_exception::already_voted_in_similar_way, - "You have already voted in a similar way."); + GOLOS_CHECK_LOGIC(itr->vote_percent != o.weight, + logic_exception::already_voted_in_similar_way, + "You have already voted in a similar way."); /// this is the rshares voting for or against the post int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; if (itr->rshares < rshares) { - if (_db.has_hardfork(STEEMIT_HARDFORK_0_7)) { - GOLOS_CHECK_LOGIC(_db.head_block_time() < - _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, - logic_exception::cannot_vote_within_last_minute_before_payout, - "Cannot increase reward of post within the last minute before payout."); - } + GOLOS_CHECK_LOGIC(_db.head_block_time() < + _db.calculate_discussion_payout_time(comment) - STEEMIT_UPVOTE_LOCKOUT, + logic_exception::cannot_vote_within_last_minute_before_payout, + "Cannot increase reward of post within the last minute before payout."); } - _db.modify(voter, [&](account_object &a) { + _db.modify(voter, [&](account_object& a) { a.voting_power = current_power - used_power; a.last_vote_time = _db.head_block_time(); }); @@ -1552,7 +1503,7 @@ namespace golos { namespace chain { fc::uint128_t avg_cashout_sec = 0; - if (!_db.has_hardfork( STEEMIT_HARDFORK_0_17__431)) { + if (!_db.has_hardfork(STEEMIT_HARDFORK_0_17__431)) { fc::uint128_t cur_cashout_time_sec = _db.calculate_discussion_payout_time(comment).sec_since_epoch(); fc::uint128_t new_cashout_time_sec = _db.head_block_time().sec_since_epoch(); @@ -1596,20 +1547,19 @@ namespace golos { namespace chain { _db.modify(root, [&](comment_object &c) { c.children_abs_rshares += abs_rshares; - if (!_db.has_hardfork( STEEMIT_HARDFORK_0_17__431)) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && c.last_payout > fc::time_point_sec::min() ) { + if (!_db.has_hardfork(STEEMIT_HARDFORK_0_17__431)) { c.cashout_time = c.last_payout + STEEMIT_SECOND_CASHOUT_WINDOW; } else { - c.cashout_time = fc::time_point_sec( - std::min(uint32_t(avg_cashout_sec.to_uint64()), - c.max_cashout_time.sec_since_epoch())); + c.cashout_time = fc::time_point_sec(std::min( + uint32_t(avg_cashout_sec.to_uint64()), c.max_cashout_time.sec_since_epoch())); } if (c.max_cashout_time == fc::time_point_sec::maximum()) { c.max_cashout_time = - _db.head_block_time() + fc::seconds(STEEMIT_MAX_CASHOUT_WINDOW_SECONDS); + _db.head_block_time() + fc::seconds(STEEMIT_MAX_CASHOUT_WINDOW_SECONDS); } } }); diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 65b45cd300..f82f18fcdc 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -270,13 +270,13 @@ namespace golos { namespace protocol { void custom_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed - GOLOS_CHECK_PARAM(required_auths, + GOLOS_CHECK_PARAM(required_auths, GOLOS_CHECK_VALUE(required_auths.size() > 0, "at least one account must be specified")); } void custom_json_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed - GOLOS_CHECK_PARAM(required_auths, + GOLOS_CHECK_PARAM(required_auths, GOLOS_CHECK_VALUE((required_auths.size() + required_posting_auths.size()) > 0, "at least on account must be specified")); GOLOS_CHECK_PARAM(id, GOLOS_CHECK_VALUE_MAX_SIZE(id, 32)); GOLOS_CHECK_PARAM(json, { @@ -288,7 +288,7 @@ namespace golos { namespace protocol { void custom_binary_operation::validate() const { /// required auth accounts are the ones whose bandwidth is consumed GOLOS_CHECK_PARAM(required_owner_auths, - GOLOS_CHECK_VALUE((required_owner_auths.size() + required_active_auths.size() + required_posting_auths.size()) > 0, + GOLOS_CHECK_VALUE((required_owner_auths.size() + required_active_auths.size() + required_posting_auths.size()) > 0, "at least one account must be specified")); GOLOS_CHECK_PARAM(id, GOLOS_CHECK_VALUE_MAX_SIZE(id, 32)); GOLOS_CHECK_PARAM(required_auths, { diff --git a/plugins/chain/include/golos/plugins/chain/plugin.hpp b/plugins/chain/include/golos/plugins/chain/plugin.hpp index 892834d3cc..357c645957 100644 --- a/plugins/chain/include/golos/plugins/chain/plugin.hpp +++ b/plugins/chain/include/golos/plugins/chain/plugin.hpp @@ -2,25 +2,19 @@ #include -#include #include -#include #include - -#include +#include #include -// for api -#include + +#include + namespace golos { namespace chain { struct database_fixture; -} } // namespace golos::chain +} } // golos::chain -namespace golos { - namespace plugins { - namespace chain { - - using golos::plugins::json_rpc::msg_pack; +namespace golos { namespace plugins { namespace chain { class plugin final : public appbase::plugin { public: @@ -30,9 +24,9 @@ namespace golos { ~plugin(); - constexpr const static char *plugin_name = "chain"; + constexpr const static char* plugin_name = "chain"; - static const std::string &name() { + static const std::string& name() { static std::string name = plugin_name; return name; } @@ -94,13 +88,10 @@ namespace golos { boost::signals2::signal on_sync; private: - class plugin_impl; - - std::unique_ptr my; + class impl; + std::unique_ptr my; - friend class golos::chain::database_fixture; // need to set skip_startup field + friend struct golos::chain::database_fixture; // need to set skip_startup field bool skip_startup = false; }; - } - } -} // golos::plugins::chain +} } } // golos::plugins::chain diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 693ab060de..9e14784b00 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -1,28 +1,26 @@ -#include -#include #include +#include +#include +#include +#include #include #include #include -#include -#include #include -namespace golos { -namespace plugins { -namespace chain { +namespace golos { namespace plugins { namespace chain { namespace bfs = boost::filesystem; + namespace bpo = boost::program_options; using fc::flat_map; using protocol::block_id_type; - class plugin::plugin_impl { + class plugin::impl final { public: - uint64_t shared_memory_size = 0; - boost::filesystem::path shared_memory_dir; + bfs::path shared_memory_dir; bool replay = false; bool replay_if_corrupted = true; bool force_replay = false; @@ -31,7 +29,7 @@ namespace chain { bool check_locks = false; bool validate_invariants = false; uint32_t flush_interval = 0; - flat_map loaded_checkpoints; + flat_map loaded_checkpoints; uint32_t allow_future_time = 5; @@ -45,6 +43,7 @@ namespace chain { size_t min_free_shared_memory_size; uint32_t clear_votes_before_block = 0; + uint32_t clear_votes_older_n_blocks = -1; bool enable_plugins_on_push_transaction; uint32_t block_num_check_free_size = 0; @@ -55,13 +54,11 @@ namespace chain { bool single_write_thread = false; - golos::chain::database::store_metadata_modes store_account_metadata; - + golos::chain::database::store_metadata_modes store_account_metadata; std::vector accounts_to_store_metadata; - bool store_memo_in_savings_withdraws = true; - plugin_impl() { + impl() { // get default settings read_wait_micro = db.read_wait_micro(); max_read_wait_retries = db.max_read_wait_retries(); @@ -71,28 +68,36 @@ namespace chain { } // HELPERS - golos::chain::database &database() { - return db; - } - boost::asio::io_service& io_service() { return appbase::app().get_io_service(); } - constexpr const static char *plugin_name = "chain_api"; - static const std::string &name() { - static std::string name = plugin_name; - return name; - } - void check_time_in_block(const protocol::signed_block &block); bool accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip); void accept_transaction(const protocol::signed_transaction &trx); void wipe_db(const bfs::path &data_dir, bool wipe_block_log); void replay_db(const bfs::path &data_dir, bool force_replay); + + void on_block (const protocol::signed_block& b); }; - void plugin::plugin_impl::check_time_in_block(const protocol::signed_block &block) { + + void plugin::impl::on_block(const protocol::signed_block& b) { + auto n = b.block_num(); + bool del_any = n < clear_votes_before_block; + const auto now = db.head_block_time(); // don't make one constant from now and ttl because of overflow + const auto ttl = uint64_t(clear_votes_older_n_blocks) * STEEMIT_BLOCK_INTERVAL; + + const auto& idx = db.get_index().indices().get(); + auto itr = idx.begin(); + while (itr != idx.end() && itr->num_changes == -1 && (del_any || now - itr->last_update > fc::seconds(ttl))) { + const auto& vote = *itr; + ++itr; + db.remove(vote); + } + } + + void plugin::impl::check_time_in_block(const protocol::signed_block &block) { time_point_sec now = fc::time_point::now(); uint64_t max_accept_time = now.sec_since_epoch(); @@ -100,7 +105,7 @@ namespace chain { FC_ASSERT(block.timestamp.sec_since_epoch() <= max_accept_time); } - bool plugin::plugin_impl::accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip) { + bool plugin::impl::accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip) { if (currently_syncing && block.block_num() % 10000 == 0) { ilog("Syncing Blockchain --- Got block: #${n} time: ${t} producer: ${p}", ("t", block.timestamp)("n", block.block_num())("p", block.witness)); @@ -127,7 +132,7 @@ namespace chain { } } - void plugin::plugin_impl::wipe_db(const bfs::path &data_dir, bool wipe_block_log) { + void plugin::impl::wipe_db(const bfs::path &data_dir, bool wipe_block_log) { if (wipe_block_log) { ilog("Wiping blockchain with block log."); } else { @@ -138,7 +143,7 @@ namespace chain { db.open(data_dir, shared_memory_dir, STEEMIT_INIT_SUPPLY, shared_memory_size, chainbase::database::read_write/*, validate_invariants*/ ); }; - void plugin::plugin_impl::replay_db(const bfs::path &data_dir, bool force_replay) { + void plugin::impl::replay_db(const bfs::path &data_dir, bool force_replay) { auto head_block_log = db.get_block_log().head(); force_replay |= head_block_log && db.revision() >= head_block_log->block_num(); @@ -152,7 +157,7 @@ namespace chain { db.reindex(data_dir, shared_memory_dir, from_block_num, shared_memory_size); }; - void plugin::plugin_impl::accept_transaction(const protocol::signed_transaction &trx) { + void plugin::impl::accept_transaction(const protocol::signed_transaction &trx) { uint32_t skip = db.validate_transaction(trx, db.skip_apply_transaction); if (single_write_thread) { @@ -187,91 +192,98 @@ namespace chain { return my->db; } - void plugin::set_program_options(boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) { + void plugin::set_program_options(bpo::options_description& cli, bpo::options_description& cfg) { cfg.add_options() ( - "shared-file-dir", boost::program_options::value()->default_value("blockchain"), + "shared-file-dir", bpo::value()->default_value("blockchain"), "the location of the chain shared memory files (absolute path or relative to application data dir)" ) ( - "shared-file-size", boost::program_options::value()->default_value("2G"), + "shared-file-size", bpo::value()->default_value("2G"), "Start size of the shared memory file. Default: 2G" ) ( - "inc-shared-file-size", boost::program_options::value()->default_value("2G"), + "inc-shared-file-size", bpo::value()->default_value("2G"), "Increasing size on reaching limit of free space in shared memory file (see min-free-shared-file-size). Default: 2G" ) ( - "min-free-shared-file-size", boost::program_options::value()->default_value("500M"), + "min-free-shared-file-size", bpo::value()->default_value("500M"), "Minimum free space in shared memory file (see inc-shared-file-size). Default: 500M" ) ( - "block-num-check-free-size", boost::program_options::value()->default_value(1000), + "block-num-check-free-size", bpo::value()->default_value(1000), "Check free space in shared memory each N blocks. Default: 1000 (each 3000 seconds)." ) ( - "checkpoint", boost::program_options::value>()->composing(), + "checkpoint", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints." ) ( - "flush-state-interval", boost::program_options::value(), + "flush-state-interval", bpo::value(), "flush shared memory changes to disk every N blocks" ) ( - "read-wait-micro", boost::program_options::value(), + "read-wait-micro", bpo::value(), "maximum microseconds for trying to get read lock" ) ( - "max-read-wait-retries", boost::program_options::value(), + "max-read-wait-retries", bpo::value(), "maximum number of retries to get read lock" ) ( - "write-wait-micro", boost::program_options::value(), + "write-wait-micro", bpo::value(), "maximum microseconds for trying to get write lock" ) ( - "max-write-wait-retries", boost::program_options::value(), + "max-write-wait-retries", bpo::value(), "maximum number of retries to get write lock" ) ( - "single-write-thread", boost::program_options::value()->default_value(false), + "single-write-thread", bpo::value()->default_value(false), "push blocks and transactions from one thread" ) ( - "clear-votes-before-block", boost::program_options::value()->default_value(0), + "clear-votes-before-block", bpo::value()->default_value(0), "remove votes before defined block, should speedup initial synchronization" ) ( - "skip-virtual-ops", boost::program_options::value()->default_value(false), + "clear-votes-older-n-blocks", bpo::value()->default_value(0xFFFFFFFF), + "if set, remove votes older than specified number of blocks. " + "-1 = do not remove; 0 = remove after cashout; any other value N - remove votes older than N blocks. " + "note: votes don't removed before post cashout" + ) ( + "skip-virtual-ops", bpo::value()->default_value(false), "virtual operations will not be passed to the plugins, helps to save some memory" ) ( - "enable-plugins-on-push-transaction", boost::program_options::value()->default_value(true), + "enable-plugins-on-push-transaction", bpo::value()->default_value(true), "enable calling of plugins for operations on push_transaction" ) ( - "replay-if-corrupted", boost::program_options::bool_switch()->default_value(true), + "replay-if-corrupted", bpo::bool_switch()->default_value(true), "replay all blocks if shared memory is corrupted" ) ( - "store-account-metadata", boost::program_options::value(), + "store-account-metadata", bpo::value(), "store account metadata for all accounts if true, for no one if else, otherwise for specified in store-account-metadata-list" ) ( - "store-account-metadata-list", boost::program_options::value(), + "store-account-metadata-list", bpo::value(), "names of accounts to store metadata" ) ( - "store-memo-in-savings-withdraws", boost::program_options::bool_switch()->default_value(true), + "store-memo-in-savings-withdraws", bpo::bool_switch()->default_value(true), "store memo for all savings withdraws" ); cli.add_options() ( - "replay-blockchain", boost::program_options::bool_switch()->default_value(false), + "replay-blockchain", bpo::bool_switch()->default_value(false), "clear chain database and replay all blocks" ) ( - "force-replay-blockchain", boost::program_options::bool_switch()->default_value(false), + "force-replay-blockchain", bpo::bool_switch()->default_value(false), "force clear chain database and replay all blocks" ) ( - "resync-blockchain", boost::program_options::bool_switch()->default_value(false), + "resync-blockchain", bpo::bool_switch()->default_value(false), "clear chain database and block log" ) ( - "check-locks", boost::program_options::bool_switch()->default_value(false), + "check-locks", bpo::bool_switch()->default_value(false), "Check correctness of chainbase locking" ) ( - "validate-database-invariants", boost::program_options::bool_switch()->default_value(false), + "validate-database-invariants", bpo::bool_switch()->default_value(false), "Validate all supply invariants check out" ); } - void plugin::plugin_initialize(const boost::program_options::variables_map &options) { + void plugin::plugin_initialize(const bpo::variables_map& options) { + my.reset(new impl()); - my.reset(new plugin_impl()); + my->db.applied_block.connect([&](const protocol::signed_block& b) { + my->on_block(b); + }); - auto sfd = options.at("shared-file-dir").as(); + auto sfd = options.at("shared-file-dir").as(); if (sfd.is_relative()) { my->shared_memory_dir = appbase::app().data_dir() / sfd; } else { @@ -302,6 +314,7 @@ namespace chain { my->inc_shared_memory_size = fc::parse_size(options.at("inc-shared-file-size").as()); my->min_free_shared_memory_size = fc::parse_size(options.at("min-free-shared-file-size").as()); my->clear_votes_before_block = options.at("clear-votes-before-block").as(); + my->clear_votes_older_n_blocks = options.at("clear-votes-older-n-blocks").as(); my->skip_virtual_ops = options.at("skip-virtual-ops").as(); if (options.count("block-num-check-free-size")) { @@ -373,7 +386,6 @@ namespace chain { my->db.set_inc_shared_memory_size(my->inc_shared_memory_size); my->db.set_min_free_shared_memory_size(my->min_free_shared_memory_size); - my->db.set_clear_votes(my->clear_votes_before_block); my->db.set_store_account_metadata(my->store_account_metadata); @@ -381,7 +393,7 @@ namespace chain { my->db.set_store_memo_in_savings_withdraws(my->store_memo_in_savings_withdraws); - if(my->skip_virtual_ops) { + if (my->skip_virtual_ops) { my->db.set_skip_virtual_ops(); } @@ -400,13 +412,13 @@ namespace chain { if (my->replay) { my->replay_db(data_dir, my->force_replay); } - } catch (const golos::chain::database_revision_exception &) { + } catch (const golos::chain::database_revision_exception&) { if (my->replay_if_corrupted) { wlog("Error opening database, attempting to replay blockchain."); my->force_replay |= my->db.revision() >= my->db.head_block_num(); try { my->replay_db(data_dir, my->force_replay); - } catch (const golos::chain::block_log_exception &) { + } catch (const golos::chain::block_log_exception&) { wlog("Error opening block log. Having to resync from network..."); my->wipe_db(data_dir, true); } @@ -420,7 +432,7 @@ namespace chain { wlog("Error opening database, attempting to replay blockchain."); try { my->replay_db(data_dir, true); - } catch (const golos::chain::block_log_exception &) { + } catch (const golos::chain::block_log_exception&) { wlog("Error opening block log. Having to resync from network..."); my->wipe_db(data_dir, true); } @@ -464,6 +476,4 @@ namespace chain { my->check_time_in_block(block); } -} -} -} // namespace steem::plugis::chain::chain_apis +} } } // golos::plugins::chain diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 4b0291533a..459131309f 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -117,7 +117,7 @@ namespace golos { namespace plugins { namespace social_network { discussion get_content(std::string author, std::string permlink, uint32_t limit) const; discussion get_discussion(const comment_object& c, uint32_t vote_limit) const ; - + void set_depth_parameters(const content_depth_params& params); // Looks for a comment_operation, fills the comment_content state objects. @@ -154,7 +154,7 @@ namespace golos { namespace plugins { namespace social_network { const comment_content_object* social_network::impl::find_comment_content(const comment_id_type& comment) const { return db.find(comment); } - + const comment_content_object* social_network::find_comment_content(const comment_id_type& comment) const { return pimpl->find_comment_content(comment); } @@ -262,7 +262,7 @@ namespace golos { namespace plugins { namespace social_network { // Set depth null if needed (this parameter is given in config) if (dp.set_null_after_update) { con.block_number = db.head_block_num(); - } + } }); } else { @@ -287,7 +287,7 @@ namespace golos { namespace plugins { namespace social_network { }); } } - + }; void social_network::impl::pre_operation(const operation_notification& o) { try { diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 40360c4ce5..4b5dbdedf4 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -268,7 +268,6 @@ namespace golos { namespace chain { fund("sam", 8000); vest("sam", 8000); - db->set_clear_votes(0xFFFFFFFF); signed_transaction tx; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 250e5a2921..54f96b1cd9 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -497,7 +497,7 @@ namespace golos { namespace chain { << std::endl; } } - + ch_plugin = &appbase::app().register_plugin(); db_plugin = &appbase::app().register_plugin(); sn_plugin = &appbase::app().register_plugin(); @@ -524,10 +524,10 @@ namespace golos { namespace chain { golos::plugins::debug_node::plugin, golos::plugins::social_network::social_network, Plugins... - >( args.size(), const_cast(args.data()) ); - + >(args.size(), const_cast(args.data())); + db_plugin->set_logging(false); - + db = &ch_plugin->db(); BOOST_REQUIRE(db); } diff --git a/tests/plugin_tests/account_history.cpp b/tests/plugin_tests/account_history.cpp index 5739e1d5f3..394a7ac403 100644 --- a/tests/plugin_tests/account_history.cpp +++ b/tests/plugin_tests/account_history.cpp @@ -13,7 +13,7 @@ using golos::plugins::json_rpc::msg_pack; struct account_history_fixture : public golos::chain::add_operations_database_fixture { - typedef std::map> checked_accounts_map; ///< pair { [block], [accaunt names] } + typedef std::map> checked_accounts_map; ///< pair { [block], [account names] } checked_accounts_map check(const account_name_set& names) { uint32_t head_block_num = db->head_block_num(); diff --git a/tests/plugin_tests/chain.cpp b/tests/plugin_tests/chain.cpp new file mode 100644 index 0000000000..9061240623 --- /dev/null +++ b/tests/plugin_tests/chain.cpp @@ -0,0 +1,297 @@ +#include +#include + +#include "database_fixture.hpp" +#include "helpers.hpp" + +#include +#include +#include + +using golos::logic_exception; +using golos::missing_object; +using golos::protocol::comment_operation; +using golos::protocol::vote_operation; +using golos::protocol::tx_invalid_operation; +using golos::protocol::public_key_type; +using golos::protocol::signed_transaction; +using golos::protocol::custom_binary_operation; +using golos::chain::account_id_type; +using golos::chain::make_comment_id; + +using golos::chain::account_name_set; + +using namespace golos::plugins::chain; + + +struct chain_fixture : public golos::chain::database_fixture { + + void initialize(const Options& opts = {}) { + database_fixture::initialize(opts); + open_database(); + startup(); + } + + fc::ecc::private_key vote_key; + uint32_t current_voter = 0; + static const uint32_t cashout_blocks = STEEMIT_CASHOUT_WINDOW_SECONDS / STEEMIT_BLOCK_INTERVAL; + + void generate_voters(uint32_t n) { + fc::ecc::private_key private_key = generate_private_key("test"); + fc::ecc::private_key post_key = generate_private_key("test_post"); + vote_key = post_key; + for (auto i = 0; i < n; i++) { + const auto name = "voter" + std::to_string(i); + GOLOS_CHECK_NO_THROW(account_create(name, private_key.get_public_key(), post_key.get_public_key())); + } + generate_block(); + validate_database(); + } + + void vote_sequence(const std::string& author, const std::string& permlink, uint32_t n_votes, uint32_t interval = 0) { + uint32_t end = current_voter + n_votes; + for (; current_voter < end; current_voter++) { + const auto name = "voter" + std::to_string(current_voter); + vote_operation op; + op.voter = name; + op.author = author; + op.permlink = permlink; + op.weight = STEEMIT_100_PERCENT; + signed_transaction tx; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, vote_key, op)); + if (interval > 0) { + generate_blocks(interval); + } + } + validate_database(); + } + + void post(const std::string& permlink = "post", const std::string& parent_permlink = "test") { + ACTOR(alice); + comment_operation op; + op.author = "alice"; + op.permlink = permlink; + op.parent_author = parent_permlink == "test" ? "" : "alice"; + op.parent_permlink = parent_permlink; + op.title = "foo"; + op.body = "bar"; + signed_transaction tx; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); + ilog("Generate: " + tx.id().str() + " comment_operation"); + validate_database(); + } + + uint32_t count_stored_votes() { + const auto n = db->get_index().indices().size(); + ilog("block: ${b}, votes in db: ${n}", ("b",db->head_block_num())("n",n)); + return n; + } +}; + + +BOOST_FIXTURE_TEST_SUITE(chain_plugin, chain_fixture) + +BOOST_AUTO_TEST_SUITE(clear_votes) + +BOOST_AUTO_TEST_CASE(clear_votes_default) { + BOOST_TEST_MESSAGE("Testing: clear_votes_default"); + initialize(); + generate_voters(10); + post(); + BOOST_TEST_MESSAGE("--- vote 9 times and check votes stored"); + vote_sequence("alice", "post", 5); + auto interval = cashout_blocks / 5; + vote_sequence("alice", "post", 4, interval); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block before cashout and check 9 votes stored"); + generate_blocks(interval - 1); + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK(post.mode != golos::chain::archived); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to cashout block and check 9 votes stored"); + generate_blocks(1); + { + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK_EQUAL(post.mode, golos::chain::archived); + } + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 2 * cashout time forward and check 9 votes stored"); + generate_blocks(cashout_blocks * 2); + BOOST_CHECK_EQUAL(9, count_stored_votes()); +} + +BOOST_AUTO_TEST_CASE(clear_votes_before_block) { + BOOST_TEST_MESSAGE("Testing: clear_votes_before_block"); + int before_block = 4 + cashout_blocks * 2; + initialize({ + {"clear-votes-before-block", std::to_string(before_block)}, + }); + + generate_voters(15); + post(); + BOOST_TEST_MESSAGE("--- vote 9 times and check votes stored"); + vote_sequence("alice", "post", 5); + auto interval = cashout_blocks / 5; + vote_sequence("alice", "post", 4, interval); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block before cashout and check 9 votes stored"); + generate_blocks(interval - 1); + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK(post.mode != golos::chain::archived); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to cashout block and check votes removed"); + generate_blocks(1); + { + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK_EQUAL(post.mode, golos::chain::archived); + } + BOOST_CHECK_EQUAL(0, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to just before 'clear-votes-before-block', vote and check 1 vote stored"); + generate_blocks(cashout_blocks - 1); + vote_sequence("alice", "post", 1); + BOOST_CHECK_EQUAL(1, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- check, vote removed in the next block"); + generate_blocks(1); + BOOST_CHECK_EQUAL(0, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- vote 5 times and check 5 votes stored"); + vote_sequence("alice", "post", 5, 10); + BOOST_CHECK_EQUAL(5, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to future and check 5 votes still stored"); + generate_blocks(cashout_blocks); + BOOST_CHECK_EQUAL(5, count_stored_votes()); +} + +BOOST_AUTO_TEST_CASE(clear_votes_before_cashout_block) { + BOOST_TEST_MESSAGE("Testing: clear_votes_before_cashout_block"); + int before_block = cashout_blocks / 2; + initialize({ + {"clear-votes-before-block", std::to_string(before_block)}, + }); + + generate_voters(10); + post(); + BOOST_TEST_MESSAGE("--- vote 9 times and check votes stored"); + vote_sequence("alice", "post", 5); + auto interval = cashout_blocks / 5; + vote_sequence("alice", "post", 4, interval); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block before cashout and check 9 votes stored"); + generate_blocks(interval - 1); + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK(post.mode != golos::chain::archived); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to cashout block and check 9 votes still stored"); + generate_blocks(1); + { + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK_EQUAL(post.mode, golos::chain::archived); + } + BOOST_CHECK_EQUAL(9, count_stored_votes()); +} + +BOOST_AUTO_TEST_CASE(clear_votes_older_n_larger_cashout) { + BOOST_TEST_MESSAGE("Testing: clear_votes_older_n_larger_cashout"); + int n_blocks = cashout_blocks * 2; + initialize({ + {"clear-votes-older-n-blocks", std::to_string(n_blocks)}, + }); + + generate_voters(15); + post(); + BOOST_TEST_MESSAGE("--- vote 9 times and check votes stored"); + vote_sequence("alice", "post", 5); + auto interval = cashout_blocks / 5; + vote_sequence("alice", "post", 4, interval); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block before cashout and check 9 votes stored"); + generate_blocks(interval - 1); + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK(post.mode != golos::chain::archived); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to cashout block and check 9 votes still stored"); + generate_blocks(1); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + { + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK_EQUAL(post.mode, golos::chain::archived); + } + + BOOST_TEST_MESSAGE("--- go to block just before 'clear_votes_older_n', vote and check 10 votes stored"); + generate_blocks(cashout_blocks); + vote_sequence("alice", "post", 1); + BOOST_CHECK_EQUAL(10, count_stored_votes()); + + // 6 = 5 instant created and 1 from first interval + BOOST_TEST_MESSAGE("--- go to block just after 'clear_votes_older_n' and check 6 votes removed"); + generate_blocks(1); + BOOST_CHECK_EQUAL(4, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- vote 5 times and check 9 votes stored"); + vote_sequence("alice", "post", 4, 10); + vote_sequence("alice", "post", 1); + BOOST_CHECK_EQUAL(9, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 'clear_votes_older_n' blocks forward and check 1 vote stored"); + generate_blocks(n_blocks); + BOOST_CHECK_EQUAL(1, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block forward and check all votes removed"); + generate_blocks(1); + BOOST_CHECK_EQUAL(0, count_stored_votes()); +} + +BOOST_AUTO_TEST_CASE(clear_votes_older_n_smaller_cashout) { + BOOST_TEST_MESSAGE("Testing: clear_votes_older_n_smaller_cashout"); + int n_blocks = cashout_blocks / 4; + initialize({ + {"clear-votes-older-n-blocks", std::to_string(n_blocks)}, + }); + + generate_voters(15); + post(); + BOOST_TEST_MESSAGE("--- vote 10 times and check votes stored"); + vote_sequence("alice", "post", 5); + auto interval = cashout_blocks / 5; + vote_sequence("alice", "post", 4, interval); + vote_sequence("alice", "post", 1); + BOOST_CHECK_EQUAL(10, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to 1 block before cashout and check 10 votes stored"); + generate_blocks(interval - 1); + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK(post.mode != golos::chain::archived); + BOOST_CHECK_EQUAL(10, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go to cashout block and check 8 votes removed"); + generate_blocks(1); + BOOST_CHECK_EQUAL(1, count_stored_votes()); + { + const auto& post = db->get_comment("alice", std::string("post")); + BOOST_CHECK_EQUAL(post.mode, golos::chain::archived); + } + + BOOST_TEST_MESSAGE("--- go forward just before last vote should be removed and check it stored"); + generate_blocks(n_blocks - interval); + BOOST_CHECK_EQUAL(1, count_stored_votes()); + + BOOST_TEST_MESSAGE("--- go 1 block forward and check all votes removed"); + generate_blocks(1); + BOOST_CHECK_EQUAL(0, count_stored_votes()); +} + +BOOST_AUTO_TEST_SUITE_END() // clear_votes + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/plugin_tests/operation_history.cpp b/tests/plugin_tests/operation_history.cpp index 72dcf7a5ed..ef82754560 100644 --- a/tests/plugin_tests/operation_history.cpp +++ b/tests/plugin_tests/operation_history.cpp @@ -60,8 +60,8 @@ BOOST_AUTO_TEST_CASE(operation_history_blocks) { const uint32_t HISTORY_BLOCKS = 2; BOOST_TEST_MESSAGE("Testing: operation_history_blocks"); initialize({ - {"history-blocks",std::to_string(HISTORY_BLOCKS)}, - {"history-whitelist-ops",OPERATIONS} + {"history-blocks",std::to_string(HISTORY_BLOCKS)}, + {"history-whitelist-ops",OPERATIONS} }); auto _added_ops = add_operations(); diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 4bc6b5fc9d..3317bb8e05 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -187,8 +187,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) vest("sam", 8000); fund("dave", 5000); vest("dave", 5000); - - db->set_clear_votes(0xFFFFFFFF); price exchange_rate(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); set_price_feed(exchange_rate); @@ -358,15 +356,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(bob_author_reward.permlink == "test"); BOOST_REQUIRE(bob_author_reward.sbd_payout == bob_comment_reward.sbd_payout()); BOOST_REQUIRE(bob_author_reward.vesting_payout == bob_comment_reward.vesting_payout()); - - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment.id, alice_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment.id, bob_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment.id, sam_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment.id, dave_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment.id, alice_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment.id, bob_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment.id, sam_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment.id, dave_account.id)) == vote_idx.end()); + // "removing old votes" tests removed from here, tested in chain.cpp now validate_database(); BOOST_TEST_MESSAGE("Testing no payout when less than $0.02"); @@ -448,15 +438,6 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(sam_sbd_balance == sam_account.sbd_balance); BOOST_REQUIRE(dave_vest_shares == dave_account.vesting_shares); BOOST_REQUIRE(dave_sbd_balance == dave_account.sbd_balance); - - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment1.id, alice_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment1.id, bob_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment1.id, sam_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(alice_comment1.id, dave_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment1.id, alice_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment1.id, bob_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment1.id, sam_account.id)) == vote_idx.end()); - BOOST_REQUIRE(vote_idx.find(std::make_tuple(bob_comment1.id, dave_account.id)) == vote_idx.end()); validate_database(); } FC_LOG_AND_RETHROW() From 942e6f22b13ddf157251d6486da1402e179d0f4f Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 30 Jul 2018 13:32:22 +0300 Subject: [PATCH 187/250] Add chain plugin test to CMakeList and clean code #801 --- tests/CMakeLists.txt | 1 + tests/plugin_tests/chain.cpp | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2c18996706..ce2972acf9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,6 +35,7 @@ file(GLOB PLUGIN_TESTS "plugin_tests/market_history.cpp" "plugin_tests/plugin_ops.cpp" "plugin_tests/json_rpc.cpp" + "plugin_tests/chain.cpp" "plugin_tests/operation_history.cpp" "plugin_tests/account_history.cpp" "plugin_tests/follow.cpp") diff --git a/tests/plugin_tests/chain.cpp b/tests/plugin_tests/chain.cpp index 9061240623..7f3755e677 100644 --- a/tests/plugin_tests/chain.cpp +++ b/tests/plugin_tests/chain.cpp @@ -8,17 +8,11 @@ #include #include -using golos::logic_exception; -using golos::missing_object; using golos::protocol::comment_operation; using golos::protocol::vote_operation; -using golos::protocol::tx_invalid_operation; using golos::protocol::public_key_type; using golos::protocol::signed_transaction; -using golos::protocol::custom_binary_operation; using golos::chain::account_id_type; -using golos::chain::make_comment_id; - using golos::chain::account_name_set; using namespace golos::plugins::chain; @@ -77,13 +71,11 @@ struct chain_fixture : public golos::chain::database_fixture { op.body = "bar"; signed_transaction tx; GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, alice_private_key, op)); - ilog("Generate: " + tx.id().str() + " comment_operation"); validate_database(); } uint32_t count_stored_votes() { const auto n = db->get_index().indices().size(); - ilog("block: ${b}, votes in db: ${n}", ("b",db->head_block_num())("n",n)); return n; } }; From 64a8939a99cfd629ce59347016667e2eaf0f3491 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Wed, 25 Jul 2018 09:42:12 +0300 Subject: [PATCH 188/250] Add comment_last_update_object to social_network-plugin #828 --- libraries/api/comment_api_object.cpp | 59 --- libraries/api/discussion_helper.cpp | 19 +- .../include/golos/api/comment_api_object.hpp | 4 +- .../include/golos/api/discussion_helper.hpp | 2 +- .../include/golos/chain/comment_object.hpp | 25 +- libraries/chain/steem_evaluator.cpp | 10 +- plugins/follow/plugin.cpp | 2 +- plugins/mongo_db/CMakeLists.txt | 1 + plugins/mongo_db/mongo_db_state.cpp | 24 +- .../social_network/comment_content_object.hpp | 57 --- .../plugins/social_network/social_network.hpp | 4 +- .../social_network/social_network_types.hpp | 113 ++++++ plugins/social_network/social_network.cpp | 357 ++++++++++++------ plugins/tags/CMakeLists.txt | 1 + .../golos/plugins/tags/tag_visitor.hpp | 4 + .../include/golos/plugins/tags/tags_sort.hpp | 14 +- plugins/tags/plugin.cpp | 60 ++- plugins/tags/tag_visitor.cpp | 25 +- tests/tests/operation_tests.cpp | 28 +- 19 files changed, 493 insertions(+), 316 deletions(-) delete mode 100644 libraries/api/comment_api_object.cpp delete mode 100644 plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp create mode 100644 plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp diff --git a/libraries/api/comment_api_object.cpp b/libraries/api/comment_api_object.cpp deleted file mode 100644 index 927e72fd30..0000000000 --- a/libraries/api/comment_api_object.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -namespace golos { namespace api { - - using namespace golos::chain; - - comment_api_object::comment_api_object(const golos::chain::comment_object &o, const golos::chain::database &db) - : id(o.id), - parent_author(o.parent_author), - parent_permlink(to_string(o.parent_permlink)), - author(o.author), - permlink(to_string(o.permlink)), - last_update(o.last_update), - created(o.created), - active(o.active), - last_payout(o.last_payout), - depth(o.depth), - children(o.children), - children_rshares2(o.children_rshares2), - net_rshares(o.net_rshares), - abs_rshares(o.abs_rshares), - vote_rshares(o.vote_rshares), - children_abs_rshares(o.children_abs_rshares), - cashout_time(o.cashout_time), - max_cashout_time(o.max_cashout_time), - total_vote_weight(o.total_vote_weight), - reward_weight(o.reward_weight), - total_payout_value(o.total_payout_value), - curator_payout_value(o.curator_payout_value), - author_rewards(o.author_rewards), - net_votes(o.net_votes), - mode(o.mode), - root_comment(o.root_comment), - max_accepted_payout(o.max_accepted_payout), - percent_steem_dollars(o.percent_steem_dollars), - allow_replies(o.allow_replies), - allow_votes(o.allow_votes), - allow_curation_rewards(o.allow_curation_rewards) { - - for (auto& route : o.beneficiaries) { - beneficiaries.push_back(route); - } -#ifndef IS_LOW_MEM - auto& content = db.get_comment_content(o.id); - - title = to_string(content.title); - body = to_string(content.body); - json_metadata = to_string(content.json_metadata); -#endif - if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { - category = to_string(o.parent_permlink); - } else { - category = to_string(db.get_comment(o.root_comment).parent_permlink); - } - } - - comment_api_object::comment_api_object() = default; - -} } // golos::api diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 747b5d2cb2..e34856a7b3 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -22,11 +22,11 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function fill_comment_content) + std::function fill_comment_info) : database_(db), fill_reputation_(fill_reputation), fill_promoted_(fill_promoted), - fill_comment_content_(fill_comment_content) { + fill_comment_info_(fill_comment_info) { } ~impl() = default; @@ -61,7 +61,7 @@ namespace golos { namespace api { golos::chain::database& database_; std::function&)> fill_reputation_; std::function fill_promoted_; - std::function fill_comment_content_; + std::function fill_comment_info_; }; // create_comment_api_object @@ -89,9 +89,7 @@ namespace golos { namespace api { d.parent_permlink = to_string(o.parent_permlink); d.author = o.author; d.permlink = to_string(o.permlink); - d.last_update = o.last_update; d.created = o.created; - d.active = o.active; d.last_payout = o.last_payout; d.depth = o.depth; d.children = o.children; @@ -120,8 +118,8 @@ namespace golos { namespace api { d.beneficiaries.push_back(route); } - if (fill_comment_content_) { - fill_comment_content_(database(), o, d); + if (fill_comment_info_) { + fill_comment_info_(database(), o, d); } if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { @@ -176,6 +174,7 @@ namespace golos { namespace api { ) const { pimpl->select_active_votes(result, total_count, author, permlink, limit); } + // // set_pending_payout void discussion_helper::impl::set_pending_payout(discussion& d) const { @@ -246,6 +245,8 @@ namespace golos { namespace api { discussion discussion_helper::impl::create_discussion(const std::string& author) const { auto dis = discussion(); fill_reputation_(database_, author, dis.author_reputation); + dis.active = time_point_sec::min(); + dis.last_update = time_point_sec::min(); return dis; } @@ -267,9 +268,9 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function fill_comment_content + std::function fill_comment_info ) { - pimpl = std::make_unique(db, fill_reputation, fill_promoted, fill_comment_content); + pimpl = std::make_unique(db, fill_reputation, fill_promoted, fill_comment_info); } discussion_helper::~discussion_helper() = default; diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index 248a151b83..acd8b6c752 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -23,9 +23,9 @@ namespace golos { namespace api { std::string category; - time_point_sec last_update; + fc::optional last_update; time_point_sec created; - time_point_sec active; + fc::optional active; time_point_sec last_payout; uint8_t depth = 0; diff --git a/libraries/api/include/golos/api/discussion_helper.hpp b/libraries/api/include/golos/api/discussion_helper.hpp index 2035d46559..e7058aa3c5 100644 --- a/libraries/api/include/golos/api/discussion_helper.hpp +++ b/libraries/api/include/golos/api/discussion_helper.hpp @@ -17,7 +17,7 @@ namespace golos { namespace api { golos::chain::database& db, std::function&)> fill_reputation, std::function fill_promoted, - std::function fill_comment_content + std::function fill_comment_info ); ~discussion_helper(); diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index 62758c0706..39fff117f2 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -59,9 +59,7 @@ namespace golos { account_name_type author; shared_string permlink; - time_point_sec last_update; time_point_sec created; - time_point_sec active; ///< the last time this post was "touched" by voting or reply time_point_sec last_payout; uint16_t depth = 0; ///< used to track max nested depth @@ -184,8 +182,6 @@ namespace golos { struct by_permlink; /// author, perm struct by_root; struct by_parent; - struct by_last_update; /// parent_auth, last_update - struct by_author_last_update; /** * @ingroup object_index @@ -194,7 +190,6 @@ namespace golos { comment_object, indexed_by< - /// CONSENUSS INDICIES - used by evaluators ordered_unique < tag , member>, ordered_unique < @@ -219,25 +214,7 @@ namespace golos { member , member, member>, - composite_key_compare , strcmp_less, std::less> > - /// NON_CONSENSUS INDICIES - used by APIs -#ifndef IS_LOW_MEM - , - ordered_unique < - tag, - composite_key, - member, - member>, - composite_key_compare , std::greater, std::less>>, - ordered_unique < - tag, - composite_key, - member, - member>, - composite_key_compare , std::greater, std::less>> -#endif + composite_key_compare , strcmp_less, std::less> > >, allocator > diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 329c0b4db7..3c8d5c5ce0 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -444,11 +444,9 @@ namespace golos { namespace chain { if (_db.has_hardfork(STEEMIT_HARDFORK_0_6__80) && comment.parent_author != STEEMIT_ROOT_POST_PARENT) { auto parent = &_db.get_comment(comment.parent_author, comment.parent_permlink); - auto now = _db.head_block_time(); while (parent) { _db.modify(*parent, [&](comment_object &p) { p.children--; - p.active = now; }); if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); @@ -659,9 +657,7 @@ namespace golos { namespace chain { com.author = o.author; from_string(com.permlink, o.permlink); - com.last_update = _db.head_block_time(); - com.created = com.last_update; - com.active = com.last_update; + com.created = _db.head_block_time(); com.last_payout = fc::time_point_sec::min(); com.max_cashout_time = fc::time_point_sec::maximum(); com.reward_weight = reward_weight; @@ -689,11 +685,9 @@ namespace golos { namespace chain { }); - auto now = _db.head_block_time(); while (parent) { _db.modify(*parent, [&](comment_object &p) { p.children++; - p.active = now; }); if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { parent = &_db.get_comment(parent->parent_author, parent->parent_permlink); @@ -719,8 +713,6 @@ namespace golos { namespace chain { } _db.modify(comment, [&](comment_object &com) { - com.last_update = _db.head_block_time(); - com.active = com.last_update; strcmp_equal equal; GOLOS_CHECK_LOGIC(com.parent_author == (parent ? o.parent_author : account_name_type()), diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index b05fd5826e..86febf794d 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -300,7 +300,7 @@ namespace golos { database_, follow::fill_account_reputation, nullptr, - golos::plugins::social_network::fill_comment_content + golos::plugins::social_network::fill_comment_info ); } diff --git a/plugins/mongo_db/CMakeLists.txt b/plugins/mongo_db/CMakeLists.txt index a74b1af60e..85a2e820e4 100644 --- a/plugins/mongo_db/CMakeLists.txt +++ b/plugins/mongo_db/CMakeLists.txt @@ -60,6 +60,7 @@ if(ENABLE_MONGO_PLUGIN) golos_chain golos::chain_plugin golos::follow + golos::social_network appbase fc ${LIBBSONCXX_LIBRARIES} diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index f7897f7d1a..c40f880e45 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -70,7 +71,6 @@ namespace mongo_db { format_value(body, "author", auth); format_value(body, "permlink", perm); format_value(body, "abs_rshares", comment.abs_rshares); - format_value(body, "active", comment.active); format_value(body, "allow_curation_rewards", comment.allow_curation_rewards); format_value(body, "allow_replies", comment.allow_replies); @@ -85,7 +85,6 @@ namespace mongo_db { format_value(body, "curator_payout", comment.curator_payout_value); format_value(body, "depth", comment.depth); format_value(body, "last_payout", comment.last_payout); - format_value(body, "last_update", comment.last_update); format_value(body, "max_accepted_payout", comment.max_accepted_payout); format_value(body, "max_cashout_time", comment.max_cashout_time); format_value(body, "net_rshares", comment.net_rshares); @@ -127,11 +126,24 @@ namespace mongo_db { format_value(body, "mode", comment_mode); - auto& content = db_.get_comment_content(comment_id_type(comment.id)); + if (db_.has_index()) { + const auto& con_idx = db_.get_index().indices().get(); + auto con_itr = con_idx.find(comment.id); + if (con_itr != con_idx.end()) { + format_value(body, "title", con_itr->title); + format_value(body, "body", con_itr->body); + format_value(body, "json_metadata", con_itr->json_metadata); + } + } - format_value(body, "title", content.title); - format_value(body, "body", content.body); - format_value(body, "json_metadata", content.json_metadata); + if (db_.has_index()) { + const auto& clu_idx = db_.get_index().indices().get(); + auto clu_itr = clu_idx.find(comment.id); + if (clu_itr != clu_idx.end()) { + format_value(body, "active", clu_itr->active); + format_value(body, "last_update", clu_itr->last_update); + } + } std::string category, root_oid; if (comment.parent_author == STEEMIT_ROOT_POST_PARENT) { diff --git a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp b/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp deleted file mode 100644 index bd9f5e8892..0000000000 --- a/plugins/social_network/include/golos/plugins/social_network/comment_content_object.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -namespace golos { namespace plugins { namespace social_network { - using namespace golos::chain; - - #ifndef SOCIAL_NETWORK_SPACE_ID - #define SOCIAL_NETWORK_SPACE_ID 10 - #endif - - enum social_network_types { - comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) - }; - - - class comment_content_object - : public object { - public: - comment_content_object() = delete; - - template - comment_content_object(Constructor&& c, allocator a) - :title(a), body(a), json_metadata(a) { - c(*this); - } - - id_type id; - - comment_id_type comment; - - shared_string title; - shared_string body; - shared_string json_metadata; - - uint32_t block_number; - }; - - - using comment_content_id_type = object_id; - - struct by_comment; - struct by_block_number; - - typedef multi_index_container< - comment_content_object, - indexed_by< - ordered_unique, member>, - ordered_unique, member>, - ordered_non_unique, member>>, - allocator - > comment_content_index; -} } } - - -CHAINBASE_SET_INDEX_TYPE( - golos::plugins::social_network::comment_content_object, - golos::plugins::social_network::comment_content_index -) \ No newline at end of file diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp index 3dbe56c60e..f968d12353 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace golos { namespace plugins { namespace social_network { using plugins::json_rpc::msg_pack; @@ -67,7 +67,7 @@ namespace golos { namespace plugins { namespace social_network { }; // Callback which is needed for correct work of discussion_helper - void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); + void fill_comment_info(const golos::chain::database& db, const comment_object& co, comment_api_object& cao); std::string get_json_metadata(const golos::chain::database& db, const comment_object&); } } } // golos::plugins::social_network diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp new file mode 100644 index 0000000000..27532eb094 --- /dev/null +++ b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp @@ -0,0 +1,113 @@ +#pragma once + +namespace golos { namespace plugins { namespace social_network { + using namespace golos::chain; + + #ifndef SOCIAL_NETWORK_SPACE_ID + #define SOCIAL_NETWORK_SPACE_ID 10 + #endif + + enum social_network_types { + comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8), + comment_last_update_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 + }; + + + class comment_content_object + : public object { + public: + comment_content_object() = delete; + + template + comment_content_object(Constructor&& c, allocator a) + :title(a), body(a), json_metadata(a) { + c(*this); + } + + id_type id; + + comment_id_type comment; + + shared_string title; + shared_string body; + shared_string json_metadata; + + uint32_t block_number; + }; + + + using comment_content_id_type = object_id; + + struct by_comment; + struct by_block_number; + + using comment_content_index = multi_index_container< + comment_content_object, + indexed_by< + ordered_unique, member>, + ordered_unique, member>, + ordered_non_unique, member>>, + allocator + >; + + class comment_last_update_object: public object { + public: + comment_last_update_object() = delete; + + template + comment_last_update_object(Constructor&& c, allocator a) { + c(*this); + } + + id_type id; + + comment_id_type comment; + account_name_type parent_author; + account_name_type author; + time_point_sec last_update; + time_point_sec active; ///< the last time this post was "touched" by voting or reply + + uint32_t block_number; + }; + + using comment_last_update_id_type = object_id; + + struct by_last_update; /// parent_auth, last_update + struct by_author_last_update; + + using comment_last_update_index = multi_index_container< + comment_last_update_object, + indexed_by< + ordered_unique, member>, + ordered_unique, member>, + ordered_unique< + tag, + composite_key, + member, + member>, + composite_key_compare, std::greater, std::less>>, + ordered_unique< + tag, + composite_key, + member, + member>, + composite_key_compare, std::greater, std::less>>, + ordered_non_unique< + tag, + member> + >, + allocator + >; +} } } + + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::social_network::comment_content_object, + golos::plugins::social_network::comment_content_index +) + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::social_network::comment_last_update_object, + golos::plugins::social_network::comment_last_update_index) \ No newline at end of file diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index f5d82fcdd7..7164b40fe4 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -22,9 +22,9 @@ #endif -// Depth of comment_content information storage history. -struct content_depth_params { - content_depth_params() { +// Depth of comment information storage history. +struct comment_depth_params { + comment_depth_params() { } bool miss_content() const { @@ -34,10 +34,14 @@ struct content_depth_params { has_comment_json_metadata_depth && !comment_json_metadata_depth; } - bool need_clear() const { + bool need_clear_content() const { return has_comment_title_depth || has_comment_body_depth || has_comment_json_metadata_depth; } + bool need_clear_last_update() const { + return has_comment_last_update_depth; + } + bool should_delete_whole_content_object(const uint32_t delta) const { return (has_comment_title_depth && delta > comment_title_depth) && @@ -52,14 +56,22 @@ struct content_depth_params { (has_comment_json_metadata_depth && delta > comment_json_metadata_depth); } + bool should_delete_last_update_object(const uint32_t delta) const { + if (!has_comment_last_update_depth) { + return false; + } + return delta > comment_last_update_depth; + } uint32_t comment_title_depth; uint32_t comment_body_depth; uint32_t comment_json_metadata_depth; + uint32_t comment_last_update_depth; bool has_comment_title_depth = false; bool has_comment_body_depth = false; bool has_comment_json_metadata_depth = false; + bool has_comment_last_update_depth = false; bool set_null_after_update = false; }; @@ -67,12 +79,13 @@ struct content_depth_params { namespace golos { namespace plugins { namespace social_network { using golos::plugins::tags::fill_promoted; using golos::api::discussion_helper; + using golos::plugins::social_network::comment_last_update_index; using boost::locale::conv::utf_to_utf; struct social_network::impl final { impl(): db(appbase::app().get_plugin().db()) { - helper = std::make_unique(db, follow::fill_account_reputation, fill_promoted, fill_comment_content); + helper = std::make_unique(db, follow::fill_account_reputation, fill_promoted, fill_comment_info); } ~impl() = default; @@ -101,9 +114,9 @@ namespace golos { namespace plugins { namespace social_network { discussion get_content(std::string author, std::string permlink, uint32_t limit) const; - discussion get_discussion(const comment_object& c, uint32_t vote_limit) const ; + discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; - void set_depth_parameters(const content_depth_params& params); + void set_depth_parameters(const comment_depth_params& params); // Looks for a comment_operation, fills the comment_content state objects. void pre_operation(const operation_notification& o); @@ -112,16 +125,19 @@ namespace golos { namespace plugins { namespace social_network { void on_block(const signed_block& b); - comment_api_object create_comment_api_object(const comment_object& o) const ; + comment_api_object create_comment_api_object(const comment_object& o) const; + + const comment_content_object& get_comment_content(const comment_id_type& comment) const; - const comment_content_object& get_comment_content(const comment_id_type& comment) const ; + const comment_content_object* find_comment_content(const comment_id_type& comment) const; - const comment_content_object* find_comment_content(const comment_id_type& comment) const ; + bool set_comment_update(const comment_object& comment, time_point_sec active, bool set_last_update) const; + void activate_parent_comments(const comment_object& comment) const; golos::chain::database& db; std::unique_ptr helper; - content_depth_params depth_parameters; + comment_depth_params depth_parameters; }; const comment_content_object& social_network::impl::get_comment_content(const comment_id_type& comment) const { @@ -155,6 +171,46 @@ namespace golos { namespace plugins { namespace social_network { helper->select_active_votes(result, total_count, author, permlink, limit); } + bool social_network::impl::set_comment_update(const comment_object& comment, time_point_sec active, bool set_last_update) const { + const auto& clu_idx = db.get_index().indices().get(); + auto clu_itr = clu_idx.find(comment.id); + if (clu_itr != clu_idx.end()) { + db.modify(*clu_itr, [&](comment_last_update_object& clu) { + clu.active = active; + if (set_last_update) { + clu.last_update = clu.active; + } + }); + return true; + } else { + db.create([&](comment_last_update_object& clu) { + clu.comment = comment.id; + clu.author = comment.author; + clu.parent_author = comment.parent_author; + clu.active = active; + if (set_last_update) { + clu.last_update = clu.active; + } + }); + return false; + } + } + + void social_network::impl::activate_parent_comments(const comment_object& comment) const { + if (db.has_hardfork(STEEMIT_HARDFORK_0_6__80) && comment.parent_author != STEEMIT_ROOT_POST_PARENT) { + auto parent = &db.get_comment(comment.parent_author, comment.parent_permlink); + auto now = db.head_block_time(); + while (parent) { + set_comment_update(*parent, now, false); + if (parent->parent_author != STEEMIT_ROOT_POST_PARENT) { + parent = &db.get_comment(parent->parent_author, parent->parent_permlink); + } else { + parent = nullptr; + } + } + } + } + template struct delete_visitor { using result_type = void; @@ -177,6 +233,14 @@ namespace golos { namespace plugins { namespace social_network { } impl.db.remove(*content); + + if (impl.db.template has_index()) { + if (comment.net_rshares > 0) { + return; + } + + impl.activate_parent_comments(comment); + } } }; @@ -186,7 +250,7 @@ namespace golos { namespace plugins { namespace social_network { TImpl& impl; golos::chain::database& db; - content_depth_params& depth_parameters; + comment_depth_params& depth_parameters; operation_visitor(TImpl& p): impl(p), db(p.db), depth_parameters(p.depth_parameters) { } @@ -204,72 +268,73 @@ namespace golos { namespace plugins { namespace social_network { } void operator()(const golos::protocol::comment_operation& o) const { - const auto& dp = depth_parameters; - if (dp.miss_content()) { - return; - } - const auto& comment = db.get_comment(o.author, o.permlink); - const auto comment_content = impl.find_comment_content(comment.id); - - if ( comment_content != nullptr) { - // Edit case - db.modify(*comment_content, [&]( comment_content_object& con ) { - if (o.title.size() && (!dp.has_comment_title_depth || dp.comment_title_depth > 0)) { - from_string(con.title, o.title); - } - if (o.json_metadata.size()) { - if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && - fc::is_utf8(o.json_metadata) - ) { - from_string(con.json_metadata, o.json_metadata ); + const auto& dp = depth_parameters; + if (!dp.miss_content()) { + const auto comment_content = impl.find_comment_content(comment.id); + if ( comment_content != nullptr) { + // Edit case + db.modify(*comment_content, [&]( comment_content_object& con ) { + if (o.title.size() && (!dp.has_comment_title_depth || dp.comment_title_depth > 0)) { + from_string(con.title, o.title); } - } - if (o.body.size() && (!dp.has_comment_body_depth || dp.comment_body_depth > 0)) { - try { - diff_match_patch dmp; - auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); - if (patch.size()) { - auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); - auto patched_body = wstring_to_utf8(result.first); - if(!fc::is_utf8(patched_body)) { - from_string(con.body, fc::prune_invalid_utf8(patched_body)); - } else { - from_string(con.body, patched_body); + if (o.json_metadata.size()) { + if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && + fc::is_utf8(o.json_metadata) + ) { + from_string(con.json_metadata, o.json_metadata ); + } + } + if (o.body.size() && (!dp.has_comment_body_depth || dp.comment_body_depth > 0)) { + try { + diff_match_patch dmp; + auto patch = dmp.patch_fromText(utf8_to_wstring(o.body)); + if (patch.size()) { + auto result = dmp.patch_apply(patch, utf8_to_wstring(to_string(con.body))); + auto patched_body = wstring_to_utf8(result.first); + if(!fc::is_utf8(patched_body)) { + from_string(con.body, fc::prune_invalid_utf8(patched_body)); + } else { + from_string(con.body, patched_body); + } + } else { // replace + from_string(con.body, o.body); } - } else { // replace + } catch ( ... ) { from_string(con.body, o.body); } - } catch ( ... ) { + } + // Set depth null if needed (this parameter is given in config) + if (dp.set_null_after_update) { + con.block_number = db.head_block_num(); + } + }); + } else { + // Creation case + db.create([&](comment_content_object& con) { + con.comment = comment.id; + if (!dp.has_comment_title_depth || dp.comment_title_depth > 0) { + from_string(con.title, o.title); + } + + if ((!dp.has_comment_body_depth || dp.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { from_string(con.body, o.body); } - } - // Set depth null if needed (this parameter is given in config) - if (dp.set_null_after_update) { + if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && + fc::is_utf8(o.json_metadata) + ) { + from_string(con.json_metadata, o.json_metadata); + } con.block_number = db.head_block_num(); - } - }); - - } else { - // Creation case - db.create([&](comment_content_object& con) { - con.comment = comment.id; - if (!dp.has_comment_title_depth || dp.comment_title_depth > 0) { - from_string(con.title, o.title); - } - - if ((!dp.has_comment_body_depth || dp.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { - from_string(con.body, o.body); - } - - if ((!dp.has_comment_json_metadata_depth || dp.comment_json_metadata_depth > 0) && - fc::is_utf8(o.json_metadata) - ) { - from_string(con.json_metadata, o.json_metadata); - } + }); + } + } - con.block_number = db.head_block_num(); - }); + if (db.has_index()) { + auto now = db.head_block_time(); + if (!impl.set_comment_update(comment, now, true)) { // If create case + impl.activate_parent_comments(comment); + } } } @@ -285,44 +350,63 @@ namespace golos { namespace plugins { namespace social_network { o.op.visit(ovisit); } FC_CAPTURE_AND_RETHROW() } + void social_network::impl::on_block(const signed_block& b) { try { const auto& dp = depth_parameters; - if (!dp.need_clear()) { - return; - } + if (dp.need_clear_content()) { + const auto& content_idx = db.get_index().indices().get(); - const auto& idx = db.get_index().indices().get(); + auto head_block_num = db.head_block_num(); + for (auto itr = content_idx.begin(); itr != content_idx.end();) { + auto& content = *itr; + ++itr; - for (auto itr = idx.begin(); itr != idx.end();) { - auto& content = *itr; - ++itr; + auto& comment = db.get_comment(content.comment); - auto& comment = db.get(content.comment); + auto delta = head_block_num - content.block_number; + if (comment.mode == archived && dp.should_delete_part_of_content_object(delta)) { + if (dp.should_delete_whole_content_object(delta)) { + db.remove(content); + continue; + } - auto delta = db.head_block_num() - content.block_number; - if (comment.mode == archived && dp.should_delete_part_of_content_object(delta)) { - if (dp.should_delete_whole_content_object(delta)) { - db.remove(content); - continue; - } + db.modify(content, [&](comment_content_object& con) { + if (dp.has_comment_title_depth && delta > dp.comment_title_depth) { + con.title.clear(); + } - db.modify(content, [&](comment_content_object& con) { - if (dp.has_comment_title_depth && delta > dp.comment_title_depth) { - con.title.clear(); - } + if (dp.has_comment_body_depth && delta > dp.comment_body_depth) { + con.body.clear(); + } - if (dp.has_comment_body_depth && delta > dp.comment_body_depth) { - con.body.clear(); - } + if (dp.has_comment_json_metadata_depth && delta > dp.comment_json_metadata_depth) { + con.json_metadata.clear(); + } + }); - if (dp.has_comment_json_metadata_depth && delta > dp.comment_json_metadata_depth) { - con.json_metadata.clear(); - } - }); + } else { + break; + } + } + } - } else { - break; + if (dp.need_clear_last_update()) { + const auto& clu_idx = db.get_index().indices().get(); + + auto head_block_num = db.head_block_num(); + for (auto itr = clu_idx.begin(); itr != clu_idx.end();) { + auto& clu = *itr; + ++itr; + + auto& comment = db.get_comment(clu.comment); + + auto delta = head_block_num - clu.block_number; + if (comment.mode == archived && depth_parameters.should_delete_last_update_object(delta)) { + db.remove(clu); + } else { + break; + } } } } FC_CAPTURE_AND_RETHROW() } @@ -343,7 +427,7 @@ namespace golos { namespace plugins { namespace social_network { social_network::social_network() = default; void social_network::set_program_options( - boost::program_options::options_description& cfg, + boost::program_options::options_description& cli, boost::program_options::options_description& config_file_options ) { config_file_options.add_options() @@ -359,6 +443,9 @@ namespace golos { namespace plugins { namespace social_network { ) ( "set-content-storing-depth-null-after-update", boost::program_options::value()->default_value(false), "should content's depth be set to null after update" + ) ( + "comment-last-update-depth", boost::program_options::value()->default_value(std::numeric_limits::max()), + "mode of storing records of comment.active and comment.last_update: 4294967295 = store all, 0 = do not store, N = storing N blocks depth" ); } @@ -370,6 +457,17 @@ namespace golos { namespace plugins { namespace social_network { add_plugin_index(db); + comment_depth_params& params = pimpl->depth_parameters; + + auto comment_last_update_depth = options.at("comment-last-update-depth").as(); + if (comment_last_update_depth != 0) { + add_plugin_index(db); + if (comment_last_update_depth != std::numeric_limits::max()) { + params.comment_last_update_depth = comment_last_update_depth; + params.has_comment_last_update_depth = true; + } + } + db.pre_apply_operation.connect([&](const operation_notification &o) { pimpl->pre_operation(o); }); @@ -382,8 +480,6 @@ namespace golos { namespace plugins { namespace social_network { pimpl->on_block(b); }); - content_depth_params& params = pimpl->depth_parameters; - if (options.count("comment-title-depth")) { params.comment_title_depth = options.at("comment-title-depth").as(); params.has_comment_title_depth = true; @@ -554,9 +650,18 @@ namespace golos { namespace plugins { namespace social_network { uint32_t vote_limit ) const { std::vector result; -#ifndef IS_LOW_MEM - const auto& last_update_idx = db.get_index().indices().get(); - auto itr = last_update_idx.begin(); + + if (!db.has_index()) { + return result; + } + + // Method returns only comments which are created when config flag was true + + const auto& clu_index = db.get_index(); + const auto& clu_cmt_idx = clu_index.indices().get(); + const auto& clu_idx = clu_index.indices().get(); + + auto itr = clu_idx.begin(); const account_name_type* parent_author = &start_parent_author; if (start_permlink.size()) { @@ -564,19 +669,23 @@ namespace golos { namespace plugins { namespace social_network { if (nullptr == comment) { return result; } - itr = last_update_idx.iterator_to(*comment); + auto clu_itr = clu_cmt_idx.find(comment->id); + if (clu_itr == clu_cmt_idx.end()) { + return result; + } + itr = clu_idx.iterator_to(*clu_itr); parent_author = &comment->parent_author; } else if (start_parent_author.size()) { - itr = last_update_idx.lower_bound(start_parent_author); + itr = clu_idx.lower_bound(start_parent_author); } result.reserve(limit); - while (itr != last_update_idx.end() && result.size() < limit && itr->parent_author == *parent_author) { - result.emplace_back(get_discussion(*itr, vote_limit)); + while (itr != clu_idx.end() && result.size() < limit && itr->parent_author == *parent_author) { + result.emplace_back(get_discussion(db.get_comment(itr->comment), vote_limit)); ++itr; } -#endif + return result; } @@ -599,20 +708,30 @@ namespace golos { namespace plugins { namespace social_network { }); } - void fill_comment_content(const golos::chain::database& db, const comment_object& co, comment_api_object& con) { - if (!db.has_index()) { - return; - } - const auto content = db.find(co.id); - if (content != nullptr) { - con.title = to_string(content->title); - con.body = to_string(content->body); - con.json_metadata = to_string(content->json_metadata); + void fill_comment_info(const golos::chain::database& db, const comment_object& co, comment_api_object& con) { + if (db.has_index()) { + const auto content = db.find(co.id); + if (content != nullptr) { + con.title = to_string(content->title); + con.body = to_string(content->body); + con.json_metadata = to_string(content->json_metadata); + } + + const auto root_content = db.find(co.root_comment); + if (root_content != nullptr) { + con.root_title = to_string(root_content->title); + } } - const auto root_content = db.find(co.root_comment); - if (root_content != nullptr) { - con.root_title = to_string(root_content->title); + if (db.has_index()) { + const auto last_update = db.find(co.id); + if (last_update != nullptr) { + con.active = last_update->active; + con.last_update = last_update->last_update; + } else { + con.active = time_point_sec::min(); + con.last_update = time_point_sec::min(); + } } } diff --git a/plugins/tags/CMakeLists.txt b/plugins/tags/CMakeLists.txt index 6a4f68bd73..6150650e40 100644 --- a/plugins/tags/CMakeLists.txt +++ b/plugins/tags/CMakeLists.txt @@ -38,6 +38,7 @@ target_link_libraries( golos::network golos::follow golos::api + golos::social_network appbase ) diff --git a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp index 56b2fa2cef..032ae45871 100644 --- a/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp +++ b/plugins/tags/include/golos/plugins/tags/tag_visitor.hpp @@ -11,6 +11,8 @@ namespace golos { namespace plugins { namespace tags { comment_metadata get_metadata(const std::string& json_metadata); + struct comment_date { time_point_sec active; time_point_sec last_update; }; + struct operation_visitor { operation_visitor(database& db); using result_type = void; @@ -25,6 +27,8 @@ namespace golos { namespace plugins { namespace tags { const tag_stats_object& get_stats(const tag_object&) const; + comment_date get_comment_last_update(const comment_object& comment) const; + void update_tag(const tag_object&, const comment_object&, double hot, double trending) const; void create_tag(const std::string&, const tag_type, const comment_object&, double hot, double trending) const; diff --git a/plugins/tags/include/golos/plugins/tags/tags_sort.hpp b/plugins/tags/include/golos/plugins/tags/tags_sort.hpp index 155c418d13..5e11d43f6f 100644 --- a/plugins/tags/include/golos/plugins/tags/tags_sort.hpp +++ b/plugins/tags/include/golos/plugins/tags/tags_sort.hpp @@ -50,9 +50,12 @@ namespace golos { namespace plugins { namespace tags { namespace sort { struct by_active { bool operator()(const discussion& first, const discussion& second) const { - if (std::greater()(first.active, second.active)) { + if (!first.active.valid() || !second.active.valid()) { + return false; + } + if (std::greater()(*first.active, *second.active)) { return true; - } else if (std::equal_to()(first.active, second.active)) { + } else if (std::equal_to()(*first.active, *second.active)) { return std::less()(first.id, second.id); } return false; @@ -61,9 +64,12 @@ namespace golos { namespace plugins { namespace tags { namespace sort { struct by_updated { bool operator()(const discussion& first, const discussion& second) const { - if (std::greater()(first.last_update, second.last_update)) { + if (!first.last_update.valid() || !second.last_update.valid()) { + return false; + } + if (std::greater()(*first.last_update, *second.last_update)) { return true; - } else if (std::equal_to()(first.last_update, second.last_update)) { + } else if (std::equal_to()(*first.last_update, *second.last_update)) { return std::less()(first.id, second.id); } return false; diff --git a/plugins/tags/plugin.cpp b/plugins/tags/plugin.cpp index 05cd43b19a..6aa8a1adf8 100644 --- a/plugins/tags/plugin.cpp +++ b/plugins/tags/plugin.cpp @@ -11,10 +11,13 @@ #include #include #include +#include namespace golos { namespace plugins { namespace tags { + using golos::plugins::social_network::comment_last_update_index; + using golos::chain::feed_history_object; using golos::api::discussion_helper; @@ -24,7 +27,7 @@ namespace golos { namespace plugins { namespace tags { database_, follow::fill_account_reputation, fill_promoted, - social_network::fill_comment_content); + social_network::fill_comment_info); } ~impl() {} @@ -596,10 +599,17 @@ namespace golos { namespace plugins { namespace tags { GOLOS_CHECK_VALUE(!!query.start_author, "Must get comments for specific authors")); auto& db = pimpl->database(); + + if (!db.has_index()) { + return result; + } + return db.with_weak_read_lock([&]() { - const auto &idx = db.get_index().indices().get(); - auto itr = idx.lower_bound(*query.start_author); - if (itr == idx.end()) { + const auto& clu_cmt_idx = db.get_index().indices().get(); + const auto& clu_idx = db.get_index().indices().get(); + + auto itr = clu_idx.lower_bound(*query.start_author); + if (itr == clu_idx.end()) { return result; } @@ -609,7 +619,12 @@ namespace golos { namespace plugins { namespace tags { if (litr == lidx.end()) { return result; } - itr = idx.iterator_to(*litr); + auto clu_itr = clu_cmt_idx.find(litr->id); + if (clu_itr == clu_cmt_idx.end()) { + return result; + } else { + itr = clu_idx.iterator_to(*clu_itr); + } } if (!pimpl->filter_query(query)) { @@ -618,15 +633,16 @@ namespace golos { namespace plugins { namespace tags { result.reserve(query.limit); - for (; itr != idx.end() && itr->author == *query.start_author && result.size() < query.limit; ++itr) { + for (; itr != clu_idx.end() && itr->author == *query.start_author && result.size() < query.limit; ++itr) { if (itr->parent_author.size() > 0) { discussion p; - pimpl->fill_comment_api_object(db.get(itr->root_comment), p); + auto& comment = db.get_comment(itr->comment); + pimpl->fill_comment_api_object(db.get_comment(comment.root_comment), p); if (!query.is_good_tags(p) || !query.is_good_author(p.author)) { continue; } discussion d; - pimpl->fill_comment_api_object(*itr, d); + pimpl->fill_comment_api_object(comment, d); result.push_back(std::move(d)); pimpl->fill_discussion(result.back(), query); } @@ -683,6 +699,10 @@ namespace golos { namespace plugins { namespace tags { ); query.prepare(); query.validate(); + auto& db = pimpl->database(); + if (!db.has_index()) { + return std::vector(); + } return pimpl->select_ordered_discussions( query, [&](const discussion& d) -> bool { @@ -858,25 +878,33 @@ namespace golos { namespace plugins { namespace tags { auto& db = pimpl->database(); + if (!db.has_index()) { + return result; + } + return db.with_weak_read_lock([&]() { try { uint32_t count = 0; - const auto& didx = db.get_index().indices().get(); + const auto& clu_cmt_idx = db.get_index().indices().get(); + const auto& clu_idx = db.get_index().indices().get(); - auto itr = didx.lower_bound(std::make_tuple(author, before_date)); + auto itr = clu_idx.lower_bound(std::make_tuple(author, before_date)); if (start_permlink.size()) { - const auto& comment = db.get_comment(author, start_permlink); - if (comment.last_update < before_date) { - itr = didx.iterator_to(comment); + const auto comment = db.find_comment(author, start_permlink); + if (comment == nullptr) { + return result; + } + auto clu_itr = clu_cmt_idx.find(comment->id); + if (clu_itr != clu_cmt_idx.end() && clu_itr->last_update < before_date) { + itr = clu_idx.iterator_to(*clu_itr); } } - while (itr != didx.end() && itr->author == author && count < limit) { + for (; itr != clu_idx.end() && itr->author == author && count < limit; ++itr) { if (itr->parent_author.size() == 0) { - result.push_back(pimpl->get_discussion(*itr, vote_limit)); + result.push_back(pimpl->get_discussion(db.get_comment(itr->comment), vote_limit)); ++count; } - ++itr; } return result; diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index eea10c99b6..e2944ac184 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -4,6 +4,8 @@ namespace golos { namespace plugins { namespace tags { + using golos::plugins::social_network::comment_last_update_index; + comment_metadata get_metadata(const std::string& json_metadata) { comment_metadata meta; @@ -120,13 +122,28 @@ namespace golos { namespace plugins { namespace tags { db_.remove(tag); } + comment_date operation_visitor::get_comment_last_update(const comment_object& comment) const { + comment_date result; + if (db_.has_index()) { + const auto& clu_idx = db_.get_index().indices().get(); + auto clu_itr = clu_idx.find(comment.id); + if (clu_itr != clu_idx.end()) { + result.active = clu_itr->active; + result.last_update = clu_itr->last_update; + return result; + } + } + return result; + } + void operation_visitor::update_tag( const tag_object& current, const comment_object& comment, double hot, double trending ) const { auto cashout_time = db_.calculate_discussion_payout_time(comment); remove_stats(current); + db_.modify(current, [&](tag_object& obj) { - obj.active = comment.active; + obj.active = get_comment_last_update(comment).active; obj.cashout = cashout_time; obj.children = comment.children; obj.net_rshares = comment.net_rshares.value; @@ -151,14 +168,16 @@ namespace golos { namespace plugins { namespace tags { parent = db_.get_comment(comment.parent_author, comment.parent_permlink).id; } + auto com_date = get_comment_last_update(comment); + const auto& tag_obj = db_.create([&](tag_object& obj) { obj.name = name; obj.type = type; obj.comment = comment.id; obj.parent = parent; obj.created = comment.created; - obj.active = comment.active; - obj.updated = comment.last_update; + obj.active = com_date.active; + obj.updated = com_date.last_update; obj.cashout = comment.cashout_time; obj.net_votes = comment.net_votes; obj.children = comment.children; diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 1a8dd079b3..0a55e0b444 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -526,6 +526,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) ACTORS((alice)(bob)(sam)) generate_blocks(60 / STEEMIT_BLOCK_INTERVAL); + BOOST_CHECK(db->has_index()); + + const auto& clu_idx = db->get_index().indices().get(); + comment_operation op; op.author = "alice"; op.permlink = "lorem"; @@ -549,7 +553,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(alice_comment.author, op.author); BOOST_CHECK_EQUAL(to_string(alice_comment.permlink), op.permlink); BOOST_CHECK_EQUAL(to_string(alice_comment.parent_permlink), op.parent_permlink); - BOOST_CHECK_EQUAL(alice_comment.last_update, db->head_block_time()); + + auto alice_clu_itr = clu_idx.find(alice_comment.id); + BOOST_CHECK(alice_clu_itr != clu_idx.end()); + BOOST_CHECK_EQUAL(alice_clu_itr->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(alice_comment.created, db->head_block_time()); BOOST_CHECK_EQUAL(alice_comment.net_rshares.value, 0); BOOST_CHECK_EQUAL(alice_comment.abs_rshares.value, 0); @@ -591,7 +599,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(to_string(bob_comment.permlink), op.permlink); BOOST_CHECK_EQUAL(bob_comment.parent_author, op.parent_author); BOOST_CHECK_EQUAL(to_string(bob_comment.parent_permlink), op.parent_permlink); - BOOST_CHECK_EQUAL(bob_comment.last_update, db->head_block_time()); + + auto bob_clu_itr = clu_idx.find(bob_comment.id); + BOOST_CHECK(bob_clu_itr != clu_idx.end()); + BOOST_CHECK_EQUAL(bob_clu_itr->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(bob_comment.created, db->head_block_time()); BOOST_CHECK_EQUAL(bob_comment.net_rshares.value, 0); BOOST_CHECK_EQUAL(bob_comment.abs_rshares.value, 0); @@ -618,7 +630,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(to_string(sam_comment.permlink), op.permlink); BOOST_CHECK_EQUAL(sam_comment.parent_author, op.parent_author); BOOST_CHECK_EQUAL(to_string(sam_comment.parent_permlink), op.parent_permlink); - BOOST_CHECK_EQUAL(sam_comment.last_update, db->head_block_time()); + + auto sam_clu_itr = clu_idx.find(sam_comment.id); + BOOST_CHECK(sam_clu_itr != clu_idx.end()); + BOOST_CHECK_EQUAL(sam_clu_itr->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(sam_comment.created, db->head_block_time()); BOOST_CHECK_EQUAL(sam_comment.net_rshares.value, 0); BOOST_CHECK_EQUAL(sam_comment.abs_rshares.value, 0); @@ -666,7 +682,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(to_string(mod_sam_comment.permlink), op.permlink); BOOST_CHECK_EQUAL(mod_sam_comment.parent_author, op.parent_author); BOOST_CHECK_EQUAL(to_string(mod_sam_comment.parent_permlink), op.parent_permlink); - BOOST_CHECK_EQUAL(mod_sam_comment.last_update, db->head_block_time()); + + auto mod_sam_clu_itr = clu_idx.find(mod_sam_comment.id); + BOOST_CHECK(mod_sam_clu_itr != clu_idx.end()); + BOOST_CHECK_EQUAL(mod_sam_clu_itr->last_update, db->head_block_time()); + BOOST_CHECK_EQUAL(mod_sam_comment.created, created); BOOST_CHECK_EQUAL(mod_sam_comment.cashout_time, mod_sam_comment.created + STEEMIT_CASHOUT_WINDOW_SECONDS); validate_database(); From a20c7b61dc8a4a25b17a2bc461222b8c8871a9b3 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Mon, 30 Jul 2018 20:52:48 +0700 Subject: [PATCH 189/250] Refactor errors: cli_wallet (review fixes) #804 --- libraries/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 477d69abe5..953613f733 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1804,9 +1804,9 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st { WALLET_CHECK_UNLOCKED(); - auto account = get_account(account_name); GOLOS_CHECK_PARAM(threshold, GOLOS_CHECK_VALUE(threshold != 0, "Authority is implicitly satisfied")); + auto account = get_account(account_name); account_update_operation op; op.account = account_name; op.memo_key = account.memo_key; From 9b65e87ec8b52b59f662c28139743dbcb5176134 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 31 Jul 2018 00:45:34 +0700 Subject: [PATCH 190/250] Refactor errors: database and protocol library (review fixes) #792 --- libraries/chain/block_log.cpp | 40 +++++++++++------ libraries/chain/database.cpp | 29 +++++++++---- libraries/protocol/asset.cpp | 4 +- .../include/golos/protocol/exceptions.hpp | 43 ++++++++++++++++--- libraries/protocol/transaction.cpp | 10 ++--- 5 files changed, 89 insertions(+), 37 deletions(-) diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index 6b5bc11908..751d6b7335 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,11 @@ namespace golos { namespace chain { uint64_t get_uint64(const boost::iostreams::mapped_file& mapped_file, std::size_t pos) const { uint64_t value; - FC_ASSERT(get_mapped_size(mapped_file) >= pos + sizeof(value)); + auto file_size = get_mapped_size(mapped_file); + GOLOS_CHECK_DATABASE(pos + sizeof(value) <= file_size, + database_corrupted::reading_data_beyond_end_of_file, + "Reading data beyond end of file", + ("pos", pos)("size", sizeof(value))("file_size", file_size)); auto* ptr = mapped_file.data() + pos; value = *reinterpret_cast(ptr); @@ -52,10 +57,13 @@ namespace golos { namespace chain { uint64_t get_last_uint64(const boost::iostreams::mapped_file& mapped_file) const { uint64_t value; - auto size = get_mapped_size(mapped_file); - FC_ASSERT(size >= sizeof(value)); + auto file_size = get_mapped_size(mapped_file); + GOLOS_CHECK_DATABASE(sizeof(value) <= file_size, + database_corrupted::reading_data_beyond_end_of_file, + "Reading data beyond end of file", + ("size", sizeof(value))("file_size", file_size)); - auto* ptr = mapped_file.data() + size - sizeof(value); + auto* ptr = mapped_file.data() + file_size - sizeof(value); value = *reinterpret_cast(ptr); return value; } @@ -72,7 +80,10 @@ namespace golos { namespace chain { uint64_t read_block(uint64_t pos, signed_block& block) const { const auto file_size = get_mapped_size(block_mapped_file); - FC_ASSERT(file_size > pos); + GOLOS_CHECK_DATABASE(pos < file_size, + database_corrupted::reading_data_beyond_end_of_file, + "Reading data beyond end of file", + ("pos", pos)("file_size", file_size)); const auto* ptr = block_mapped_file.data() + pos; const auto available_size = file_size - pos; @@ -82,7 +93,11 @@ namespace golos { namespace chain { fc::raw::unpack(ds, block); const auto end_pos = pos + ds.tellp(); - FC_ASSERT(get_uint64(block_mapped_file, end_pos) == pos); + const auto block_pos = get_uint64(block_mapped_file, end_pos); + GOLOS_CHECK_DATABASE(block_pos == pos, + database_corrupted::wrong_position_marker_was_read, + "Wrong position makers was read (read ${block_pos}, expected ${expected})", + ("block_pos", block_pos)("expected", pos)); return end_pos + sizeof(uint64_t); } @@ -195,8 +210,8 @@ namespace golos { namespace chain { uint64_t append(const signed_block& b, const std::vector& data) { try { const auto index_pos = get_mapped_size(index_mapped_file); - FC_ASSERT( - index_pos == sizeof(uint64_t) * (b.block_num() - 1), + GOLOS_CHECK_DATABASE(index_pos == sizeof(uint64_t) * (b.block_num() - 1), + database_corrupted::append_index_file_at_wrong_position, "Append to index file occuring at wrong position.", ("position", index_pos) ("expected", (b.block_num() - 1) * sizeof(uint64_t))); @@ -274,11 +289,10 @@ namespace golos { namespace chain { if (pos != npos) { signed_block block; my->read_block(pos, block); - FC_ASSERT( - block.block_num() == block_num, - "Wrong block was read from block log (${returned} != ${expected}).", - ("returned", block.block_num()) - ("expected", block_num)); + GOLOS_CHECK_DATABASE(block.block_num() == block_num, + database_corrupted::wrong_block_num_was_read, + "Wrong block was read from block log (read ${block_num}, expected ${expected}).", + ("block_num", block.block_num())("expected", block_num)); result = std::move(block); } return result; diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 400b14c5d6..853930e9ad 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1077,7 +1077,9 @@ namespace golos { namespace chain { */ void database::push_transaction(const signed_transaction &trx, uint32_t skip) { try { - FC_ASSERT(fc::raw::pack_size(trx) <= (get_dynamic_global_properties().maximum_block_size - 256)); + GOLOS_ASSERT(fc::raw::pack_size(trx) <= (get_dynamic_global_properties().maximum_block_size - 256), + golos::protocol::tx_too_long, "Transaction data is too long. Maximum transaction size ${max} bytes", + ("max",get_dynamic_global_properties().maximum_block_size - 256)); with_weak_write_lock([&]() { detail::with_producing(*this, [&]() { _push_transaction(trx, skip); @@ -3335,25 +3337,34 @@ namespace golos { namespace chain { const auto &tapos_block_summary = get_block_summary(trx.ref_block_num); //Verify TaPoS block summary has correct ID prefix, // and that this block's time is not past the expiration - FC_ASSERT( - trx.ref_block_prefix == tapos_block_summary.block_id._hash[1], "", + GOLOS_ASSERT(trx.ref_block_prefix == tapos_block_summary.block_id._hash[1], + tx_invalid_field, "Transaction field ${field} has invalid value", + ("field","ref_block_prefix") ("trx.ref_block_prefix", trx.ref_block_prefix) ("tapos_block_summary", tapos_block_summary.block_id._hash[1])); } fc::time_point_sec now = head_block_time(); + fc::time_point_sec maximum = now + fc::seconds(STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - FC_ASSERT( - trx.expiration <= now + fc::seconds(STEEMIT_MAX_TIME_UNTIL_EXPIRATION), "", - ("trx.expiration", trx.expiration)("now", now) - ("max_til_exp", STEEMIT_MAX_TIME_UNTIL_EXPIRATION)); + GOLOS_ASSERT(trx.expiration <= maximum, + tx_invalid_field, "Transaction field ${field} has invalid value", + ("field", "expiration") + ("trx.expiration", trx.expiration) + ("now", now)("maximum", maximum)); // Simple solution to pending trx bug when now == trx.expiration if (is_producing() || has_hardfork(STEEMIT_HARDFORK_0_9)) { - FC_ASSERT(now < trx.expiration, "", ("now", now)("trx.exp", trx.expiration)); + GOLOS_ASSERT(now < trx.expiration, tx_expired, + "Transaction is expired. Now ${now}, expired ${expired}", + ("now", now)("expired", trx.expiration-1) + ("trx.expiration", trx.expiration)); } - FC_ASSERT(now <= trx.expiration, "", ("now", now)("trx.exp", trx.expiration)); + GOLOS_ASSERT(now <= trx.expiration, tx_expired, + "Transaction is expired. Now ${now}, expired ${expired}", + ("now", now)("expired", trx.expiration) + ("trx.expiration", trx.expiration)); } } diff --git a/libraries/protocol/asset.cpp b/libraries/protocol/asset.cpp index 4eb8ab4707..fb812ab878 100644 --- a/libraries/protocol/asset.cpp +++ b/libraries/protocol/asset.cpp @@ -78,7 +78,7 @@ namespace golos { auto intpart = s.substr(0, dot_pos); auto fractpart = "1" + s.substr( dot_pos + 1, space_pos - dot_pos - 1); - GOLOS_CHECK_VALUE(fractpart.size() - 1 < 15, "Asset fraction part is too length"); + GOLOS_CHECK_VALUE(fractpart.size() - 1 < 15, "Asset fraction part is too long"); result.set_decimals(fractpart.size() - 1); result.amount = fc::to_int64(intpart); @@ -94,7 +94,7 @@ namespace golos { size_t symbol_size = symbol.size(); if (symbol_size > 0) { - GOLOS_CHECK_VALUE(symbol_size <= 6, "Asset symbol is too length"); + GOLOS_CHECK_VALUE(symbol_size <= 6, "Asset symbol is too long"); memcpy(sy + 1, symbol.c_str(), symbol_size); } diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 7f779def5e..68f24abab8 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -55,6 +55,9 @@ #define GOLOS_CHECK_LOGIC(expr, TYPE, MSG, ...) \ GOLOS_ASSERT(expr, golos::logic_exception, MSG, ("errid", TYPE)("namespace",golos::get_logic_error_namespace())__VA_ARGS__) +#define GOLOS_CHECK_DATABASE(expr, TYPE, MSG, ...) \ + GOLOS_ASSERT(expr, golos::database_corrupted, MSG, ("errid", TYPE)__VA_ARGS__) + // TODO Remove after done refactor errors in plugins #791 // This macros is obsolete and replaced with PLUGIN_API_VALIDATE_ARGS @@ -286,7 +289,7 @@ namespace golos { delegation_limited_by_voting_power, cannot_delegate_below_minimum, - //proposals + //proposals and transactions proposal_depth_too_high, tx_with_both_posting_active_ops, @@ -336,9 +339,6 @@ namespace golos { // database logic account_exceeded_bandwidth_per_vestring_share, - - // protocol logic - cannot_mix_posting_and_active_owner_autority_operation, }; }; @@ -358,6 +358,19 @@ namespace golos { limit_too_large, invalid_value, 4020100, "Exceeded limit value"); + class database_corrupted : public internal_error { + GOLOS_DECLARE_DERIVED_EXCEPTION_BODY( + database_corrupted, internal_error, + 4030000, "Database corrupted"); + public: + enum error_types { + wrong_block_num_was_read, + wrong_position_marker_was_read, + append_index_file_at_wrong_position, + reading_data_beyond_end_of_file, + }; + }; + } // golos @@ -435,6 +448,18 @@ namespace golos { namespace protocol { tx_duplicate_transaction, transaction_exception, 3080000, "duplicate transaction"); + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_too_long, transaction_exception, + 3090000, "transaction too long"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_expired, transaction_exception, + 3100000, "expired transaction"); + + GOLOS_DECLARE_DERIVED_EXCEPTION( + tx_invalid_field, transaction_exception, + 3110000, "invalid transaction field"); + } } // golos::protocol @@ -574,9 +599,6 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, // database logic (account_exceeded_bandwidth_per_vestring_share) - - // protocol logic - (cannot_mix_posting_and_active_owner_autority_operation) ); FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, @@ -585,3 +607,10 @@ FC_REFLECT_ENUM(golos::bandwidth_exception::bandwidth_types, (vote_bandwidth) (change_owner_authority_bandwidth) ); + +FC_REFLECT_ENUM(golos::database_corrupted::error_types, + (wrong_block_num_was_read) + (wrong_position_marker_was_read) + (append_index_file_at_wrong_position) + (reading_data_beyond_end_of_file) +); diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index bd917309d5..5ff4d4fb6d 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -136,9 +136,8 @@ namespace golos { if (required_posting.size()) { GOLOS_CHECK_LOGIC( required_active.size() == 0 && required_owner.size() == 0 && other.size() == 0, - logic_exception::cannot_mix_posting_and_active_owner_autority_operation, - "Transactions with operations required posting authority cannot be combined " - "with transactions requiring active or owner authority"); + logic_exception::tx_with_both_posting_active_ops, + "Can't combine operations required posting authority and active or owner authority"); sign_state s(sigs, get_posting, avail); s.max_recursion = max_recursion_depth; @@ -271,9 +270,8 @@ namespace golos { GOLOS_CHECK_LOGIC( required_active.size() == 0 && required_owner.size() == 0, - logic_exception::cannot_mix_posting_and_active_owner_autority_operation, - "Transactions with operations required posting authority cannot be combined " - "with transactions requiring active or owner authority"); + logic_exception::tx_with_both_posting_active_ops, + "Can't combine operations required posting authority and active or owner authority"); for (auto &posting : required_posting) { s.check_authority(posting); } From b7e99dbaf98ec5f2582e336b151827d2deb2d71a Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 30 Jul 2018 21:35:03 +0300 Subject: [PATCH 191/250] Fix bad pointer in reading cli arguments in tests + code style #801 --- plugins/chain/plugin.cpp | 48 +++++------ plugins/follow/follow_evaluators.cpp | 2 +- plugins/operation_history/plugin.cpp | 4 +- tests/common/database_fixture.cpp | 38 +++------ tests/common/database_fixture.hpp | 27 +++--- tests/plugin_tests/chain.cpp | 2 +- tests/plugin_tests/operation_history.cpp | 103 ++++++++++++----------- 7 files changed, 105 insertions(+), 119 deletions(-) diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index 9e14784b00..315e413699 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -43,7 +43,7 @@ namespace golos { namespace plugins { namespace chain { size_t min_free_shared_memory_size; uint32_t clear_votes_before_block = 0; - uint32_t clear_votes_older_n_blocks = -1; + uint32_t clear_votes_older_n_blocks = 0xFFFFFFFF; bool enable_plugins_on_push_transaction; uint32_t block_num_check_free_size = 0; @@ -72,13 +72,13 @@ namespace golos { namespace plugins { namespace chain { return appbase::app().get_io_service(); } - void check_time_in_block(const protocol::signed_block &block); - bool accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip); - void accept_transaction(const protocol::signed_transaction &trx); - void wipe_db(const bfs::path &data_dir, bool wipe_block_log); - void replay_db(const bfs::path &data_dir, bool force_replay); + void check_time_in_block(const protocol::signed_block& block); + bool accept_block(const protocol::signed_block& block, bool currently_syncing, uint32_t skip); + void accept_transaction(const protocol::signed_transaction& trx); + void wipe_db(const bfs::path& data_dir, bool wipe_block_log); + void replay_db(const bfs::path& data_dir, bool force_replay); - void on_block (const protocol::signed_block& b); + void on_block (const protocol::signed_block& b); }; @@ -97,7 +97,7 @@ namespace golos { namespace plugins { namespace chain { } } - void plugin::impl::check_time_in_block(const protocol::signed_block &block) { + void plugin::impl::check_time_in_block(const protocol::signed_block& block) { time_point_sec now = fc::time_point::now(); uint64_t max_accept_time = now.sec_since_epoch(); @@ -105,10 +105,10 @@ namespace golos { namespace plugins { namespace chain { FC_ASSERT(block.timestamp.sec_since_epoch() <= max_accept_time); } - bool plugin::impl::accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip) { + bool plugin::impl::accept_block(const protocol::signed_block& block, bool currently_syncing, uint32_t skip) { if (currently_syncing && block.block_num() % 10000 == 0) { ilog("Syncing Blockchain --- Got block: #${n} time: ${t} producer: ${p}", - ("t", block.timestamp)("n", block.block_num())("p", block.witness)); + ("t", block.timestamp)("n", block.block_num())("p", block.witness)); } check_time_in_block(block); @@ -122,7 +122,7 @@ namespace golos { namespace plugins { namespace chain { io_service().post([&]{ try { promise.set_value(db.push_block(block, skip)); - } catch(...) { + } catch (...) { promise.set_exception(std::current_exception()); } }); @@ -132,7 +132,7 @@ namespace golos { namespace plugins { namespace chain { } } - void plugin::impl::wipe_db(const bfs::path &data_dir, bool wipe_block_log) { + void plugin::impl::wipe_db(const bfs::path& data_dir, bool wipe_block_log) { if (wipe_block_log) { ilog("Wiping blockchain with block log."); } else { @@ -140,10 +140,10 @@ namespace golos { namespace plugins { namespace chain { } db.wipe(data_dir, shared_memory_dir, wipe_block_log); - db.open(data_dir, shared_memory_dir, STEEMIT_INIT_SUPPLY, shared_memory_size, chainbase::database::read_write/*, validate_invariants*/ ); + db.open(data_dir, shared_memory_dir, STEEMIT_INIT_SUPPLY, shared_memory_size, chainbase::database::read_write/*, validate_invariants*/); }; - void plugin::impl::replay_db(const bfs::path &data_dir, bool force_replay) { + void plugin::impl::replay_db(const bfs::path& data_dir, bool force_replay) { auto head_block_log = db.get_block_log().head(); force_replay |= head_block_log && db.revision() >= head_block_log->block_num(); @@ -157,7 +157,7 @@ namespace golos { namespace plugins { namespace chain { db.reindex(data_dir, shared_memory_dir, from_block_num, shared_memory_size); }; - void plugin::impl::accept_transaction(const protocol::signed_transaction &trx) { + void plugin::impl::accept_transaction(const protocol::signed_transaction& trx) { uint32_t skip = db.validate_transaction(trx, db.skip_apply_transaction); if (single_write_thread) { @@ -168,7 +168,7 @@ namespace golos { namespace plugins { namespace chain { try { db.push_transaction(trx, skip); promise.set_value(true); - } catch(...) { + } catch (...) { promise.set_exception(std::current_exception()); } }); @@ -184,11 +184,11 @@ namespace golos { namespace plugins { namespace chain { plugin::~plugin() { } - golos::chain::database &plugin::db() { + golos::chain::database& plugin::db() { return my->db; } - const golos::chain::database &plugin::db() const { + const golos::chain::database& plugin::db() const { return my->db; } @@ -336,7 +336,7 @@ namespace golos { namespace plugins { namespace chain { if (options.count("checkpoint")) { auto cps = options.at("checkpoint").as>(); my->loaded_checkpoints.reserve(cps.size()); - for (const auto &cp : cps) { + for (const auto& cp : cps) { auto item = fc::json::from_string(cp).as>(); my->loaded_checkpoints[item.first] = item.second; } @@ -405,7 +405,7 @@ namespace golos { namespace plugins { namespace chain { try { ilog("Opening shared memory from ${path}", ("path", my->shared_memory_dir.generic_string())); - my->db.open(data_dir, my->shared_memory_dir, STEEMIT_INIT_SUPPLY, my->shared_memory_size, chainbase::database::read_write/*, my->validate_invariants*/ ); + my->db.open(data_dir, my->shared_memory_dir, STEEMIT_INIT_SUPPLY, my->shared_memory_size, chainbase::database::read_write/*, my->validate_invariants*/); auto head_block_log = my->db.get_block_log().head(); my->replay |= head_block_log && my->db.revision() != head_block_log->block_num(); @@ -453,15 +453,15 @@ namespace golos { namespace plugins { namespace chain { ilog("database closed successfully"); } - bool plugin::accept_block(const protocol::signed_block &block, bool currently_syncing, uint32_t skip) { + bool plugin::accept_block(const protocol::signed_block& block, bool currently_syncing, uint32_t skip) { return my->accept_block(block, currently_syncing, skip); } - void plugin::accept_transaction(const protocol::signed_transaction &trx) { + void plugin::accept_transaction(const protocol::signed_transaction& trx) { my->accept_transaction(trx); } - bool plugin::block_is_on_preferred_chain(const protocol::block_id_type &block_id) { + bool plugin::block_is_on_preferred_chain(const protocol::block_id_type& block_id) { // If it's not known, it's not preferred. if (!db().is_known_block(block_id)) { return false; @@ -472,7 +472,7 @@ namespace golos { namespace plugins { namespace chain { return db().get_block_id_for_num(protocol::block_header::num_from_id(block_id)) == block_id; } - void plugin::check_time_in_block(const protocol::signed_block &block) { + void plugin::check_time_in_block(const protocol::signed_block& block) { my->check_time_in_block(block); } diff --git a/plugins/follow/follow_evaluators.cpp b/plugins/follow/follow_evaluators.cpp index d49a429ae1..becc386b65 100644 --- a/plugins/follow/follow_evaluators.cpp +++ b/plugins/follow/follow_evaluators.cpp @@ -41,7 +41,7 @@ namespace golos { } if (what & (1 << ignore)) - PLUGIN_CHECK_LOGIC(!(what & (1 << blog)), + PLUGIN_CHECK_LOGIC(!(what & (1 << blog)), logic_errors::cannot_follow_and_ignore_simultaneously, "Cannot follow blog and ignore author at the same time"); diff --git a/plugins/operation_history/plugin.cpp b/plugins/operation_history/plugin.cpp index 44ee9cbb5e..03852ee1ac 100644 --- a/plugins/operation_history/plugin.cpp +++ b/plugins/operation_history/plugin.cpp @@ -192,11 +192,11 @@ namespace golos { namespace plugins { namespace operation_history { "Defines a list of operations which will be explicitly ignored." ) ( "history-start-block", - boost::program_options::value()->composing(), + boost::program_options::value(), "Defines starting block from which recording stats." ) ( "history-blocks", - boost::program_options::value()->composing(), + boost::program_options::value(), "Defines depth of history for recording stats." ); } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 4b5dbdedf4..6432d3844a 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -257,8 +257,8 @@ namespace golos { namespace chain { } }; - add_operations_database_fixture::Operations add_operations_database_fixture::add_operations() try { - Operations _added_ops; + add_operations_database_fixture::operations_map add_operations_database_fixture::add_operations() { try { + operations_map _added_ops; ACTORS((alice)(bob)(sam)) fund("alice", 10000); @@ -268,9 +268,6 @@ namespace golos { namespace chain { fund("sam", 8000); vest("sam", 8000); - - signed_transaction tx; - comment_operation com; com.author = "bob"; com.permlink = "test"; @@ -278,21 +275,18 @@ namespace golos { namespace chain { com.parent_permlink = "test"; com.title = "foo"; com.body = "bar"; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(com); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + signed_transaction tx; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, com)); generate_block(); _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "comment_operation")); ilog("Generate: " + tx.id().str() + " comment_operation"); - tx.operations.clear(); - tx.signatures.clear(); + tx.clear(); vote_operation vote; vote.voter = "alice"; vote.author = "bob"; vote.permlink = "test"; - vote.weight = -1; ///< Nessary for the posiblity of delet_comment_operation. + vote.weight = -1; // Necessary to allow delete_comment_operation tx.operations.push_back(vote); vote.voter = "bob"; tx.operations.push_back(vote); @@ -301,45 +295,33 @@ namespace golos { namespace chain { tx.sign(alice_private_key, db->get_chain_id()); tx.sign(bob_private_key, db->get_chain_id()); tx.sign(sam_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + GOLOS_CHECK_NO_THROW(db->push_transaction(tx, 0)); generate_block(); _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "vote_operation")); ilog("Generate: " + tx.id().str() + " vote_operation"); - tx.operations.clear(); - tx.signatures.clear(); delete_comment_operation dco; dco.author = "bob"; dco.permlink = "test"; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(dco); - tx.sign(bob_private_key, db->get_chain_id()); - db->push_transaction(tx, 0); + GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, bob_private_key, dco)); generate_block(); _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "delete_comment_operation")); ilog("Generate: " + tx.id().str() + " delete_comment_operation"); - tx.operations.clear(); - tx.signatures.clear(); account_create_operation aco; aco.new_account_name = "dave"; aco.creator = STEEMIT_INIT_MINER_NAME; aco.owner = authority(1, init_account_pub_key, 1); aco.active = aco.owner; - tx.set_expiration(db->head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION); - tx.operations.push_back(aco); - tx.sign(init_account_priv_key, db->get_chain_id()); - db->push_transaction(tx, 0); + GOLOS_CHECK_NO_THROW(push_tx_with_ops(tx, init_account_priv_key, aco)); generate_block(); _added_ops.insert(std::make_pair(tx.id().str(), STEEM_NAMESPACE_PREFIX + "account_create_operation")); ilog("Generate: " + tx.id().str() + " account_create_operation"); - tx.operations.clear(); - tx.signatures.clear(); validate_database(); return _added_ops; - } FC_LOG_AND_RETHROW(); + } FC_LOG_AND_RETHROW(); } fc::ecc::private_key database_fixture::generate_private_key(string seed) { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 54f96b1cd9..d96554fec8 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -476,13 +476,13 @@ namespace golos { namespace chain { string generate_anon_acct_name(); template - Plugin *find_plugin() { + Plugin* find_plugin() { return dynamic_cast(appbase::app().find_plugin()); } - typedef std::map Options; + using plugin_options = std::map; template - void initialize(const Options& opts = {}) { + void initialize(const plugin_options& opts = {}) { int argc = boost::unit_test::framework::master_test_suite().argc; char** argv = boost::unit_test::framework::master_test_suite().argv; @@ -506,13 +506,16 @@ namespace golos { namespace chain { ch_plugin->skip_startup = true; - std::vector args; std::vector args_data; - args.push_back(argv[0]); + // fill all elements first to avoid c_str() pointers stay valid for (const auto& opt: opts) { - args_data.push_back(std::string("--")+opt.first); - args.push_back(args_data.back().c_str()); - args.push_back(opt.second.c_str()); + args_data.push_back(std::string("--") + opt.first); + args_data.push_back(opt.second); + } + std::vector args; + args.push_back(argv[0]); + for (const auto& arg: args_data) { + args.push_back(arg.c_str()); } for (int i = 1; i < argc; i++) { args.push_back(argv[i]); @@ -670,18 +673,18 @@ namespace golos { namespace chain { }; struct add_operations_database_fixture : public database_fixture { - typedef golos::plugins::operation_history::plugin operation_history_plugin; - typedef std::map Operations; + using operation_history_plugin = golos::plugins::operation_history::plugin; + using operations_map = std::map; template - void initialize(const Options& opts = {}) { + void initialize(const plugin_options& opts = {}) { database_fixture::initialize(opts); oh_plugin = find_plugin(); open_database(); startup(); } - Operations add_operations(); + operations_map add_operations(); operation_history_plugin* oh_plugin = nullptr; }; diff --git a/tests/plugin_tests/chain.cpp b/tests/plugin_tests/chain.cpp index 7f3755e677..729a74700d 100644 --- a/tests/plugin_tests/chain.cpp +++ b/tests/plugin_tests/chain.cpp @@ -20,7 +20,7 @@ using namespace golos::plugins::chain; struct chain_fixture : public golos::chain::database_fixture { - void initialize(const Options& opts = {}) { + void initialize(const plugin_options& opts = {}) { database_fixture::initialize(opts); open_database(); startup(); diff --git a/tests/plugin_tests/operation_history.cpp b/tests/plugin_tests/operation_history.cpp index ef82754560..4eebd9de69 100644 --- a/tests/plugin_tests/operation_history.cpp +++ b/tests/plugin_tests/operation_history.cpp @@ -1,15 +1,14 @@ -#include -#include - #include -#include #include "database_fixture.hpp" -#include "comment_reward.hpp" + +#include +#include using golos::chain::add_operations_database_fixture; using golos::plugins::operation_history::applied_operation; using golos::plugins::json_rpc::msg_pack; +using golos::protocol::account_create_operation; static const std::string OPERATIONS = "account_create_operation,delete_comment_operation,vote,comment"; @@ -21,36 +20,36 @@ struct operation_visitor { } }; -void log_applied_options(const applied_operation &opts) { +void log_applied_options(const applied_operation& ops) { std::stringstream ss; - ss << "[" << opts.block << "] "; - ss << opts.trx_id.str() << " : "; /// golos::protocol::transaction_id_type + ss << "[" << ops.block << "] "; + ss << ops.trx_id.str() << " : "; /// golos::protocol::transaction_id_type operation_visitor ovisit; - std::string op_name = opts.op.visit(ovisit); + std::string op_name = ops.op.visit(ovisit); ss << "\"" << op_name << "\""; /// golos::protocol::operation ilog(ss.str()); } struct operation_history_fixture : public add_operations_database_fixture { - Operations check_operations() { + operations_map check_operations() { uint32_t head_block_num = db->head_block_num(); ilog("Check history operations, block num is " + std::to_string(head_block_num)); - Operations _founded_ops; + operations_map _found_ops; operation_visitor ovisit; - for (uint32_t i = 0; i <= head_block_num; ++i) { + for (uint32_t i = 1; i <= head_block_num; ++i) { msg_pack mo; mo.args = std::vector({fc::variant(i), fc::variant(false)}); auto ops = oh_plugin->get_ops_in_block(mo); - for (auto o : ops) { - auto iter = _founded_ops.find(o.trx_id.str()); - if (iter == _founded_ops.end()) { - _founded_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); + for (const auto& o : ops) { + auto itr = _found_ops.find(o.trx_id.str()); + if (itr == _found_ops.end()) { + _found_ops.insert(std::make_pair(o.trx_id.str(), o.op.visit(ovisit))); log_applied_options(o); } } } - return _founded_ops; + return _found_ops; } }; @@ -60,21 +59,23 @@ BOOST_AUTO_TEST_CASE(operation_history_blocks) { const uint32_t HISTORY_BLOCKS = 2; BOOST_TEST_MESSAGE("Testing: operation_history_blocks"); initialize({ - {"history-blocks",std::to_string(HISTORY_BLOCKS)}, - {"history-whitelist-ops",OPERATIONS} + {"history-blocks", std::to_string(HISTORY_BLOCKS)}, + {"history-whitelist-ops", OPERATIONS} }); auto _added_ops = add_operations(); - auto _founded_ops = check_operations(); + auto _found_ops = check_operations(); + + elog("---"); size_t _checked_ops_count = 0; - for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { - auto iter = _added_ops.find(it->first); - bool is_found = (iter != _added_ops.end()); + for (auto it = _found_ops.begin(); it != _found_ops.end(); ++it) { + auto itr = _added_ops.find(it->first); + bool is_found = itr != _added_ops.end(); BOOST_CHECK(is_found); if (is_found) { - BOOST_CHECK_EQUAL(iter->second, it->second); - if (iter->second == it->second) { + BOOST_CHECK_EQUAL(itr->second, it->second); + if (itr->second == it->second) { ++_checked_ops_count; } } else { @@ -89,20 +90,20 @@ BOOST_AUTO_TEST_CASE(black_options_postfix) { initialize({{"history-blacklist-ops", OPERATIONS}}); auto _added_ops = add_operations(); - auto _founded_ops = check_operations(); + auto _found_ops = check_operations(); - size_t _chacked_ops_count = 0; - for (const auto &co : _added_ops) { - auto iter = _founded_ops.find(co.first); - bool is_not_found = (iter == _founded_ops.end()); + size_t _checked_ops_count = 0; + for (const auto& co : _added_ops) { + auto itr = _found_ops.find(co.first); + bool is_not_found = itr == _found_ops.end(); BOOST_CHECK(is_not_found); if (is_not_found) { - ++_chacked_ops_count; + ++_checked_ops_count; } else { BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is found"); } } - BOOST_CHECK_EQUAL(_chacked_ops_count, _added_ops.size()); + BOOST_CHECK_EQUAL(_checked_ops_count, _added_ops.size()); } BOOST_AUTO_TEST_CASE(white_options_postfix) { @@ -110,45 +111,45 @@ BOOST_AUTO_TEST_CASE(white_options_postfix) { initialize({{"history-whitelist-ops", OPERATIONS}}); auto _added_ops = add_operations(); - auto _founded_ops = check_operations(); + auto _found_ops = check_operations(); - size_t _chacked_ops_count = 0; - for (const auto &co : _added_ops) { - auto iter = _founded_ops.find(co.first); - bool is_found = (iter != _founded_ops.end()); + size_t _checked_ops_count = 0; + for (const auto& co : _added_ops) { + auto itr = _found_ops.find(co.first); + bool is_found = itr != _found_ops.end(); BOOST_CHECK(is_found); if (is_found) { - BOOST_CHECK_EQUAL(iter->second, co.second); - if (iter->second == co.second) { - ++_chacked_ops_count; + BOOST_CHECK_EQUAL(itr->second, co.second); + if (itr->second == co.second) { + ++_checked_ops_count; } } else { BOOST_TEST_MESSAGE("Operation \"" + co.second + "\" by \"" + co.first + "\" is not found"); } } - BOOST_CHECK_EQUAL(_chacked_ops_count, _added_ops.size()); + BOOST_CHECK_EQUAL(_checked_ops_count, _added_ops.size()); } BOOST_AUTO_TEST_CASE(short_operation_history_blocks) { BOOST_TEST_MESSAGE("Testing: short_operation_history_blocks"); - initialize({{"history-whitelist-ops","account_create_operation,delete_comment,comment"}}); + initialize({{"history-whitelist-ops", "account_create_operation,delete_comment,comment"}}); auto _added_ops = add_operations(); - auto _founded_ops = check_operations(); + auto _found_ops = check_operations(); - size_t _chacked_ops_count = 0; - for (auto it = _founded_ops.begin(); it != _founded_ops.end(); ++it) { - auto iter = _added_ops.find(it->first); - bool is_found = (iter != _added_ops.end()); + size_t _checked_ops_count = 0; + for (auto it = _found_ops.begin(); it != _found_ops.end(); ++it) { + auto itr = _added_ops.find(it->first); + bool is_found = (itr != _added_ops.end()); if (is_found) { BOOST_TEST_MESSAGE("Found operation \"" + it->second + "\" by \"" + it->first + "\""); - BOOST_CHECK_EQUAL(iter->second, it->second); - if (iter->second == it->second) { - ++_chacked_ops_count; + BOOST_CHECK_EQUAL(itr->second, it->second); + if (itr->second == it->second) { + ++_checked_ops_count; } } } - BOOST_CHECK_EQUAL(_chacked_ops_count, 3); + BOOST_CHECK_EQUAL(_checked_ops_count, 3); } BOOST_AUTO_TEST_SUITE_END() From 41b16d8679cb9f313356eaa29364ce423f807818 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 30 Jul 2018 23:04:49 +0300 Subject: [PATCH 192/250] Fix typo #801 --- tests/common/database_fixture.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index d96554fec8..57a76eaafd 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -507,7 +507,7 @@ namespace golos { namespace chain { ch_plugin->skip_startup = true; std::vector args_data; - // fill all elements first to avoid c_str() pointers stay valid + // fill all elements first so c_str() pointers stay valid for (const auto& opt: opts) { args_data.push_back(std::string("--") + opt.first); args_data.push_back(opt.second); From 1e94bfe8a92fd9896823561d973d5cdb7039b008 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 14:59:59 +0700 Subject: [PATCH 193/250] Add posibility to edit private messages. #807 --- .../wallet/include/golos/wallet/wallet.hpp | 16 ++++ libraries/wallet/wallet.cpp | 91 +++++++++++-------- .../private_message_api_objects.hpp | 4 +- .../private_message_objects.hpp | 15 ++- .../private_message_operations.hpp | 3 +- .../private_message_api_objects.cpp | 1 + .../private_message_plugin.cpp | 45 ++++++--- 7 files changed, 124 insertions(+), 51 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 8278e04b15..186e69bbed 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1182,6 +1182,7 @@ namespace golos { namespace wallet { * @return Contact */ contact_api_object get_private_contact(const std::string& owner, const std::string& contact); + /** * Send an encrypted private message from one account to other * @@ -1194,6 +1195,20 @@ namespace golos { namespace wallet { annotated_signed_transaction send_private_message( const std::string& from, const std::string& to, const message_body& message, bool broadcast); + /** + * Edit an encrypted private message from one account to other + * + * @param from account from which you send message + * @param to account to which you send message + * @param nonce of sended message + * @param message to send + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction edit_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, + const message_body& message, bool broadcast); + message_body try_decrypt_message(const message_api_object& mo); }; @@ -1318,6 +1333,7 @@ FC_API( golos::wallet::wallet_api, (get_private_contact) (add_private_contact) (send_private_message) + (edit_private_message) ) FC_REFLECT((golos::wallet::memo_data), (from)(to)(nonce)(check)(encrypted)) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index ba88f2f559..85910fc555 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1054,6 +1054,49 @@ namespace golos { namespace wallet { return it->second; } + annotated_signed_transaction send_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, const bool update, + const message_body& message, bool broadcast + ) { + FC_ASSERT(!is_locked()); + + auto from_account = get_account(from); + auto to_account = get_account(to); + auto shared_secret = get_private_key(from_account.memo_key).get_shared_secret(to_account.memo_key); + + fc::sha512::encoder enc; + fc::raw::pack(enc, nonce); + fc::raw::pack(enc, shared_secret); + auto encrypt_key = enc.result(); + + auto msg_json = fc::json::to_string(message); + auto msg_data = std::vector(msg_json.begin(), msg_json.end()); + + private_message_operation op; + + op.from = from; + op.from_memo_key = from_account.memo_key; + op.to = to; + op.to_memo_key = to_account.memo_key; + op.nonce = nonce; + op.update = update; + op.encrypted_message = fc::aes_encrypt(encrypt_key, msg_data); + op.checksum = fc::sha256::hash(encrypt_key)._hash[0]; + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(from); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return sign_transaction(trx, broadcast); + } + string _wallet_filename; wallet_data _wallet; golos::protocol::chain_id_type steem_chain_id; @@ -1082,6 +1125,8 @@ namespace golos { namespace wallet { const string _wallet_filename_extension = ".wallet"; }; + + } } } // golos::wallet::detail @@ -2673,46 +2718,18 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->_remote_private_message->get_contact_info(owner, contact); } + annotated_signed_transaction wallet_api::edit_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, + const message_body& message, bool broadcast + ) { + return my->send_private_message(from, to, nonce, true, message, broadcast); + } + annotated_signed_transaction wallet_api::send_private_message( const std::string& from, const std::string& to, const message_body& message, bool broadcast ) { - FC_ASSERT(!is_locked()); - - auto from_account = get_account(from); - auto to_account = get_account(to); - auto shared_secret = my->get_private_key(from_account.memo_key).get_shared_secret(to_account.memo_key); - auto sent_time = fc::time_point::now().time_since_epoch().count(); - - fc::sha512::encoder enc; - fc::raw::pack(enc, sent_time); - fc::raw::pack(enc, shared_secret); - auto encrypt_key = enc.result(); - - auto msg_json = fc::json::to_string(message); - auto msg_data = std::vector(msg_json.begin(), msg_json.end()); - - private_message_operation op; - - op.from = from; - op.from_memo_key = from_account.memo_key; - op.to = to; - op.to_memo_key = to_account.memo_key; - op.nonce = sent_time; - op.encrypted_message = fc::aes_encrypt(encrypt_key, msg_data); - op.checksum = fc::sha256::hash(encrypt_key)._hash[0]; - - private_message_plugin_operation pop = op; - - custom_json_operation jop; - jop.id = "private_message"; - jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(from); - - signed_transaction trx; - trx.operations.push_back(jop); - trx.validate(); - - return my->sign_transaction(trx, broadcast); + auto nonce = fc::time_point::now().time_since_epoch().count(); + return my->send_private_message(from, to, nonce, false, message, broadcast); } message_body wallet_api::try_decrypt_message(const message_api_object& mo) { diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index ac23ef9927..eeba734a03 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -20,6 +20,7 @@ namespace golos { namespace plugins { namespace private_message { uint64_t nonce = 0; public_key_type from_memo_key; public_key_type to_memo_key; + time_point_sec create_time; time_point_sec receive_time; uint32_t checksum = 0; time_point_sec read_time; @@ -96,7 +97,8 @@ namespace golos { namespace plugins { namespace private_message { FC_REFLECT( (golos::plugins::private_message::message_api_object), - (from)(to)(from_memo_key)(to_memo_key)(nonce)(receive_time)(read_time)(checksum)(encrypted_message)) + (from)(to)(from_memo_key)(to_memo_key)(nonce) + (create_time)(receive_time)(read_time)(checksum)(encrypted_message)) FC_REFLECT( (golos::plugins::private_message::settings_api_object), diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index b48bcb67c8..cef3ebe870 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -40,9 +40,10 @@ namespace golos { namespace plugins { namespace private_message { account_name_type from; account_name_type to; - uint64_t nonce = 0; /// used as seed to secret generation + uint64_t nonce; /// used as seed to secret generation public_key_type from_memo_key; public_key_type to_memo_key; + time_point_sec create_time; time_point_sec receive_time; /// time received by blockchain uint32_t checksum = 0; time_point_sec read_time; @@ -53,6 +54,7 @@ namespace golos { namespace plugins { namespace private_message { struct by_to_date; struct by_from_date; + struct by_nonce; struct by_owner; struct by_contact; @@ -73,6 +75,17 @@ namespace golos { namespace plugins { namespace private_message { string_less, std::greater, std::less>>, + ordered_unique< + tag, + composite_key< + message_object, + member, + member, + member>, + composite_key_compare< + string_less, + string_less, + std::less>>, ordered_unique< tag, composite_key< diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp index 149390ea72..a44ac4b334 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -13,6 +13,7 @@ namespace golos { namespace plugins { namespace private_message { public_key_type from_memo_key; public_key_type to_memo_key; uint32_t checksum = 0; + bool update = false; std::vector encrypted_message; void validate() const; @@ -57,7 +58,7 @@ namespace golos { namespace plugins { namespace private_message { FC_REFLECT( (golos::plugins::private_message::private_message_operation), - (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(encrypted_message)) + (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(update)(encrypted_message)) FC_REFLECT( (golos::plugins::private_message::private_settings_operation), diff --git a/plugins/private_message/private_message_api_objects.cpp b/plugins/private_message/private_message_api_objects.cpp index a4f3cee137..2b0edb1211 100644 --- a/plugins/private_message/private_message_api_objects.cpp +++ b/plugins/private_message/private_message_api_objects.cpp @@ -9,6 +9,7 @@ namespace golos { namespace plugins { namespace private_message { nonce(o.nonce), from_memo_key(o.from_memo_key), to_memo_key(o.to_memo_key), + create_time(o.create_time), receive_time(o.receive_time), checksum(o.checksum), read_time(o.read_time), diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index e36b4a5b1b..83f1aabd45 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -195,15 +195,15 @@ namespace golos { namespace plugins { namespace private_message { return; } - auto& idx = d.get_index().indices().get(); - auto gitr = idx.find(std::make_tuple(pm.to, pm.from)); + auto& cidx = d.get_index().indices().get(); + auto citr = cidx.find(std::make_tuple(pm.to, pm.from)); auto& tidx = d.get_index().indices().get(); auto titr = tidx.find(pm.to); GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); - GOLOS_CHECK_LOGIC(gitr == idx.end() || gitr->type != ignored, + GOLOS_CHECK_LOGIC(citr == idx.end() || citr->type != ignored, logic_errors::sender_in_ignore_list, "Sender is in the ignore list of recipient"); GOLOS_CHECK_LOGIC(titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, @@ -211,10 +211,22 @@ namespace golos { namespace plugins { namespace private_message { "Recipient accepts messages only from his contact list"); }); - d.create([&](message_object& pmo) { - pmo.from = pm.from; - pmo.to = pm.to; - pmo.nonce = pm.nonce; + auto& idx = d.get_index().indices().get(); + auto itr = idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); + + GOLOS_CHECK_OP_PARAM(pm, nonce, { + if (pm.update) { + GOLOS_ASSERT( + itr != idx.end(), golos::missing_object, "Private message doesn't exist", + ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + } else { + GOLOS_ASSERT( + itr == idx.end(), golos::object_already_exist, "Private message already exist", + ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + } + }); + + auto set_message = [&](message_object& pmo) { pmo.from_memo_key = pm.from_memo_key; pmo.to_memo_key = pm.to_memo_key; pmo.checksum = pm.checksum; @@ -224,7 +236,19 @@ namespace golos { namespace plugins { namespace private_message { std::copy( pm.encrypted_message.begin(), pm.encrypted_message.end(), pmo.encrypted_message.begin()); - }); + }; + + if (itr == idx.end()) { + d.create([&](message_object& pmo) { + pmo.from = pm.from; + pmo.to = pm.to; + pmo.nonce = pm.nonce; + pmo.create_time = d.head_block_time(); + set_message(pmo); + }); + } else { + d.modify(*itr, set_message); + } // Ok, now update contact lists and counters in them @@ -264,11 +288,10 @@ namespace golos { namespace plugins { namespace private_message { }; // Add contact list if it doesn't exist or update it if it exits - auto modify_contact = [&](auto& owner, auto& contact, auto type, const bool is_send) { bool is_new_contact; - auto itr = idx.find(std::make_tuple(owner, contact)); - if (idx.end() != itr) { + auto itr = cidx.find(std::make_tuple(owner, contact)); + if (cidx.end() != itr) { d.modify(*itr, [&](auto& plo) { inc_counters(plo.size, is_send); }); From 2dd0890cdf87c7a71eb13db721f08ce7ad4f0062 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:00:08 +0700 Subject: [PATCH 194/250] Add deleting of private messages. #807 --- .../wallet/include/golos/wallet/wallet.hpp | 28 ++- libraries/wallet/wallet.cpp | 137 +++++++--- .../private_message_api_objects.hpp | 18 +- .../private_message_evaluators.hpp | 28 ++- .../private_message_exceptions.hpp | 2 + .../private_message_objects.hpp | 32 ++- .../private_message_operations.hpp | 24 +- .../private_message_operations.cpp | 30 ++- .../private_message_plugin.cpp | 238 +++++++++++++----- 9 files changed, 401 insertions(+), 136 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 186e69bbed..b5dcb60916 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1209,7 +1209,31 @@ namespace golos { namespace wallet { const std::string& from, const std::string& to, const uint64_t nonce, const message_body& message, bool broadcast); - message_body try_decrypt_message(const message_api_object& mo); + /** + * Delete encrypted private message + * + * @param from account from which you send message + * @param to account to which you send message + * @param nonce of sended message + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction delete_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast); + + /** + * Delete encrypted private messages by date range + * + * @param from account from which you send message + * @param to account to which you send message + * @param from_date begin of date range + * @param to_date begin of date range + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction delete_private_messages( + const std::string& from, const std::string& to, + const std::string& from_date, const std::string& to_date, bool broadcast); }; struct plain_keys { @@ -1334,6 +1358,8 @@ FC_API( golos::wallet::wallet_api, (add_private_contact) (send_private_message) (edit_private_message) + (delete_private_message) + (delete_private_messages) ) FC_REFLECT((golos::wallet::memo_data), (from)(to)(nonce)(check)(encrypted)) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 85910fc555..64f6173a10 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1054,6 +1054,53 @@ namespace golos { namespace wallet { return it->second; } + message_body try_decrypt_message(const message_api_object& mo) { + message_body result; + + fc::sha512 shared_secret; + + auto it = _keys.find(mo.from_memo_key); + if (it == _keys.end()) { + it = _keys.find(mo.to_memo_key); + if (it ==_keys.end()) { + wlog("unable to find keys"); + return result; + } + auto priv_key = wif_to_key(it->second); + if (!priv_key) { + return result; + } + shared_secret = priv_key->get_shared_secret(mo.from_memo_key); + } else { + auto priv_key = wif_to_key(it->second); + if (!priv_key) { + return result; + } + shared_secret = priv_key->get_shared_secret(mo.to_memo_key); + } + + fc::sha512::encoder enc; + fc::raw::pack(enc, mo.nonce); + fc::raw::pack(enc, shared_secret); + auto encrypt_key = enc.result(); + + uint32_t check = fc::sha256::hash(encrypt_key)._hash[0]; + + if (mo.checksum != check) { + wlog("wrong checksum"); + return result; + } + + auto decrypt_data = fc::aes_decrypt(encrypt_key, mo.encrypted_message); + auto msg_json = std::string(decrypt_data.begin(), decrypt_data.end()); + try { + result = fc::json::from_string(msg_json).as(); + } catch (...) { + result.body = msg_json; + } + return result; + } + annotated_signed_transaction send_private_message( const std::string& from, const std::string& to, const uint64_t nonce, const bool update, const message_body& message, bool broadcast @@ -2622,7 +2669,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st result.reserve(remote_result.size()); for (const auto& item : remote_result) { result.emplace_back(item); - message_body tmp = try_decrypt_message(item); + message_body tmp = my->try_decrypt_message(item); result.back().message = std::move(tmp); } return result; @@ -2638,7 +2685,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st result.reserve(remote_result.size()); for (const auto& item : remote_result) { result.emplace_back(item); - message_body tmp = try_decrypt_message(item); + message_body tmp = my->try_decrypt_message(item); result.back().message = std::move(tmp); } return result; @@ -2732,51 +2779,59 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->send_private_message(from, to, nonce, false, message, broadcast); } - message_body wallet_api::try_decrypt_message(const message_api_object& mo) { - message_body result; + annotated_signed_transaction wallet_api::delete_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast + ) { + FC_ASSERT(!is_locked()); + FC_ASSERT(nonce != 0); - fc::sha512 shared_secret; + private_delete_message_operation op; + op.from = from; + op.to = to; + op.nonce = nonce; + op.from_date = time_point_sec::min(); + op.to_date = time_point_sec::min(); - auto it = my->_keys.find(mo.from_memo_key); - if (it == my->_keys.end()) { - it = my->_keys.find(mo.to_memo_key); - if (it == my->_keys.end()) { - wlog("unable to find keys"); - return result; - } - auto priv_key = wif_to_key(it->second); - if (!priv_key) { - return result; - } - shared_secret = priv_key->get_shared_secret(mo.from_memo_key); - } else { - auto priv_key = wif_to_key(it->second); - if (!priv_key) { - return result; - } - shared_secret = priv_key->get_shared_secret(mo.to_memo_key); - } + private_message_plugin_operation pop = op; - fc::sha512::encoder enc; - fc::raw::pack(enc, mo.nonce); - fc::raw::pack(enc, shared_secret); - auto encrypt_key = enc.result(); + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(from); - uint32_t check = fc::sha256::hash(encrypt_key)._hash[0]; + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); - if (mo.checksum != check) { - wlog("wrong checksum"); - return result; - } + return my->sign_transaction(trx, broadcast); + } - auto decrypt_data = fc::aes_decrypt(encrypt_key, mo.encrypted_message); - auto msg_json = std::string(decrypt_data.begin(), decrypt_data.end()); - try { - result = fc::json::from_string(msg_json).as(); - } catch (...) { - result.body = msg_json; - } - return result; + annotated_signed_transaction wallet_api::delete_private_messages( + const std::string& from, const std::string& to, + const std::string& from_date, const std::string& to_date, + bool broadcast + ) { + FC_ASSERT(!is_locked()); + + private_delete_message_operation op; + op.from = from; + op.to = to; + op.nonce = 0; + op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point_sec::min()).time(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(from); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); } annotated_signed_transaction wallet_api::follow( diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index eeba734a03..b24a715c0b 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -37,13 +37,13 @@ namespace golos { namespace plugins { namespace private_message { }; struct contact_size_info { - fc::safe total_send_messages = 0; - fc::safe unread_send_messages = 0; - fc::safe total_recv_messages = 0; - fc::safe unread_recv_messages = 0; + uint32_t total_send_messages = 0; + uint32_t unread_send_messages = 0; + uint32_t total_recv_messages = 0; + uint32_t unread_recv_messages = 0; bool empty() const { - return !total_send_messages.value && !total_recv_messages.value; + return !total_send_messages && !total_recv_messages; } contact_size_info& operator-=(const contact_size_info& s) { @@ -61,6 +61,14 @@ namespace golos { namespace plugins { namespace private_message { unread_recv_messages += s.unread_send_messages; return *this; } + + bool operator==(const contact_size_info& s) const { + return + total_send_messages == s.total_send_messages && + unread_send_messages == s.unread_send_messages && + total_recv_messages == s.total_recv_messages && + unread_recv_messages == s.unread_recv_messages; + } }; struct contacts_size_info final: public contact_size_info { diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index 7c245fdcf9..2e4dea2aa8 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -22,14 +22,30 @@ namespace golos { namespace plugins { namespace private_message { private_message_evaluator(database& db, private_message_plugin* plugin) : evaluator_impl(db), - plugin_(plugin) - {} + plugin_(plugin) { + } void do_apply(const private_message_operation& o); private_message_plugin* plugin_; }; + class private_delete_message_evaluator: + public evaluator_impl + { + public: + using operation_type = private_delete_message_operation; + + private_delete_message_evaluator(database& db, private_message_plugin* plugin) + : evaluator_impl(db), + plugin_(plugin) { + } + + void do_apply(const private_delete_message_operation& o); + + private_message_plugin* plugin_; + }; + class private_settings_evaluator: public evaluator_impl { @@ -38,8 +54,8 @@ namespace golos { namespace plugins { namespace private_message { private_settings_evaluator(database& db, private_message_plugin* plugin) : evaluator_impl(db), - plugin_(plugin) - {} + plugin_(plugin) { + } void do_apply(const private_settings_operation& o); @@ -54,8 +70,8 @@ namespace golos { namespace plugins { namespace private_message { private_contact_evaluator(database& db, private_message_plugin* plugin) : evaluator_impl(db), - plugin_(plugin) - {} + plugin_(plugin) { + } void do_apply(const private_contact_operation& o); diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index 07e2b60075..d609f29c1f 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -14,6 +14,7 @@ namespace golos { namespace plugins { namespace private_message { recepient_ignores_messages_from_undefined_contact, add_undefined_contact, contact_has_same_type, + invalid_size, }; }; @@ -34,4 +35,5 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (recepient_ignores_messages_from_undefined_contact) (add_undefined_contact) (contact_has_same_type) + (invalid_size) ); \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index cef3ebe870..4e0a70123a 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -54,6 +54,7 @@ namespace golos { namespace plugins { namespace private_message { struct by_to_date; struct by_from_date; + struct by_from_to_date; struct by_nonce; struct by_owner; struct by_contact; @@ -69,34 +70,47 @@ namespace golos { namespace plugins { namespace private_message { composite_key< message_object, member, - member, + member, member>, composite_key_compare< string_less, std::greater, std::less>>, ordered_unique< - tag, + tag, composite_key< message_object, member, - member, - member>, + member, + member>, composite_key_compare< string_less, - string_less, - std::less>>, + std::greater, + std::less>>, ordered_unique< - tag, + tag, composite_key< message_object, member, - member, + member, + member, member>, composite_key_compare< + string_less, string_less, std::greater, - std::less>>>, + std::less>>, + ordered_unique< + tag, + composite_key< + message_object, + member, + member, + member>, + composite_key_compare< + string_less, + string_less, + std::less>>>, allocator>; /** diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp index a44ac4b334..c948fdbc36 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -9,10 +9,10 @@ namespace golos { namespace plugins { namespace private_message { struct private_message_operation: public base_operation { account_name_type from; account_name_type to; - uint64_t nonce = 0; /// used as seed to secret generation + uint64_t nonce; public_key_type from_memo_key; public_key_type to_memo_key; - uint32_t checksum = 0; + uint32_t checksum; bool update = false; std::vector encrypted_message; @@ -20,6 +20,17 @@ namespace golos { namespace plugins { namespace private_message { void get_required_posting_authorities(flat_set& a) const; }; + struct private_delete_message_operation: public base_operation { + account_name_type from; + account_name_type to; + uint64_t nonce = 0; + time_point_sec from_date; + time_point_sec to_date; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + struct private_settings_operation: public base_operation { account_name_type owner; bool ignore_messages_from_undefined_contact = false; @@ -37,12 +48,12 @@ namespace golos { namespace plugins { namespace private_message { ignored = 3, }; - constexpr auto private_contact_type_size = ignored + 1; + constexpr auto private_contact_type_size = static_cast(ignored + 1); struct private_contact_operation: public base_operation { account_name_type owner; account_name_type contact; - private_contact_type type; + private_contact_type type = pinned; std::string json_metadata; void validate() const; @@ -51,6 +62,7 @@ namespace golos { namespace plugins { namespace private_message { using private_message_plugin_operation = fc::static_variant< private_message_operation, + private_delete_message_operation, private_settings_operation, private_contact_operation>; @@ -60,6 +72,10 @@ FC_REFLECT( (golos::plugins::private_message::private_message_operation), (from)(to)(nonce)(from_memo_key)(to_memo_key)(checksum)(update)(encrypted_message)) +FC_REFLECT( + (golos::plugins::private_message::private_delete_message_operation), + (from)(to)(nonce)(from_date)(to_date)) + FC_REFLECT( (golos::plugins::private_message::private_settings_operation), (owner)(ignore_messages_from_undefined_contact)) diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index a642f08a08..09a3d4b778 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -7,7 +7,7 @@ namespace golos { namespace plugins { namespace private_message { - static inline void validate_account_name(const string &name) { + static inline void validate_account_name(const string& name) { GOLOS_CHECK_VALUE(is_valid_account_name(name), "Account name ${name} is invalid", ("name", name)); } @@ -24,6 +24,7 @@ namespace golos { namespace plugins { namespace private_message { return false; } + void private_settings_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(owner); } @@ -62,12 +63,37 @@ namespace golos { namespace plugins { namespace private_message { }); } - void private_message_operation::get_required_posting_authorities(flat_set& a) const { a.insert(from); } + void private_delete_message_operation::validate() const { + GOLOS_CHECK_PARAM(to, { + if (to.size()) { + validate_account_name(to); + GOLOS_CHECK_VALUE(to != from, "You cannot delete messages to yourself"); + } + }); + + GOLOS_CHECK_PARAM(from_date, { + GOLOS_CHECK_VALUE(from_date <= to_date, "from_date can't be greater then to_time"); + }); + + GOLOS_CHECK_PARAM(nonce, { + if (nonce != 0) { + GOLOS_CHECK_VALUE(to.size(), "to and nonce should be set both"); + GOLOS_CHECK_VALUE(from_date == time_point_sec::min(), "nonce and from_date can't be used together"); + GOLOS_CHECK_VALUE(to_date == time_point_sec::min(), "nonce and to_date can't be used together"); + } + }); + } + + void private_delete_message_operation::get_required_posting_authorities(flat_set& a) const { + a.insert(from); + } + + void private_contact_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(contact); GOLOS_CHECK_PARAM_ACCOUNT(owner); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 83f1aabd45..5e90d15205 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -37,6 +37,7 @@ namespace golos { namespace plugins { namespace private_message { >(db_); custom_operation_interpreter_->register_evaluator(&plugin); + custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); @@ -155,13 +156,16 @@ namespace golos { namespace plugins { namespace private_message { contacts_size_api_object result; const auto& idx = db_.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(owner, undefined)); + auto etr = idx.upper_bound(std::make_tuple(owner, private_contact_type_size)); + + for (; etr != itr; ++itr) { + result.size[itr->type] = itr->size; + } for (uint8_t i = undefined; i < private_contact_type_size; ++i) { auto t = static_cast(i); - auto itr = idx.find(std::make_tuple(owner, t)); - if (idx.end() != itr) { - result.size[t] = itr->size; - } else { + if (!result.size.count(t)) { result.size[t] = contacts_size_info(); } } @@ -195,33 +199,31 @@ namespace golos { namespace plugins { namespace private_message { return; } - auto& cidx = d.get_index().indices().get(); - auto citr = cidx.find(std::make_tuple(pm.to, pm.from)); + auto& contact_idx = d.get_index().indices().get(); + auto contact_itr = contact_idx.find(std::make_tuple(pm.to, pm.from)); - auto& tidx = d.get_index().indices().get(); - auto titr = tidx.find(pm.to); + auto& cfg_idx = d.get_index().indices().get(); + auto cfg_itr = cfg_idx.find(pm.to); GOLOS_CHECK_OP_PARAM(pm, to, { d.get_account(pm.to); - GOLOS_CHECK_LOGIC(citr == idx.end() || citr->type != ignored, + GOLOS_CHECK_LOGIC(contact_itr == contact_idx.end() || contact_itr->type != ignored, logic_errors::sender_in_ignore_list, "Sender is in the ignore list of recipient"); - GOLOS_CHECK_LOGIC(titr == tidx.end() || !titr->ignore_messages_from_undefined_contact, + GOLOS_CHECK_LOGIC(cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_undefined_contact, logic_errors::recepient_ignores_messages_from_undefined_contact, "Recipient accepts messages only from his contact list"); }); - auto& idx = d.get_index().indices().get(); - auto itr = idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); + auto& id_idx = d.get_index().indices().get(); + auto id_itr = id_idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); GOLOS_CHECK_OP_PARAM(pm, nonce, { if (pm.update) { - GOLOS_ASSERT( - itr != idx.end(), golos::missing_object, "Private message doesn't exist", + GOLOS_ASSERT(id_itr != id_idx.end(), golos::missing_object, "Private message doesn't exist", ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); } else { - GOLOS_ASSERT( - itr == idx.end(), golos::object_already_exist, "Private message already exist", + GOLOS_ASSERT(id_itr == id_idx.end(), golos::object_already_exist, "Private message already exist", ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); } }); @@ -238,7 +240,7 @@ namespace golos { namespace plugins { namespace private_message { pmo.encrypted_message.begin()); }; - if (itr == idx.end()) { + if (id_itr == id_idx.end()) { d.create([&](message_object& pmo) { pmo.from = pm.from; pmo.to = pm.to; @@ -247,12 +249,11 @@ namespace golos { namespace plugins { namespace private_message { set_message(pmo); }); } else { - d.modify(*itr, set_message); + d.modify(*id_itr, set_message); } // Ok, now update contact lists and counters in them - - auto& sidx = d.get_index().indices().get(); + auto& size_idx = d.get_index().indices().get(); // Increment counters depends on side of communication auto inc_counters = [&](auto& o, const bool is_send) { @@ -266,43 +267,42 @@ namespace golos { namespace plugins { namespace private_message { }; // Update global counters by type of contact - auto modify_size = [&](auto& owner, auto type, const bool is_new_contact, const bool is_send) { - auto modify_counters = [&](auto& plso) { - inc_counters(plso.size, is_send); + auto modify_counters = [&](auto& pcso) { + inc_counters(pcso.size, is_send); if (is_new_contact) { - plso.size.total_contacts++; + pcso.size.total_contacts++; } }; - auto itr = sidx.find(std::make_tuple(owner, type)); - if (sidx.end() == itr) { - d.create([&](auto& plso){ - plso.owner = owner; - plso.type = type; - modify_counters(plso); + auto size_itr = size_idx.find(std::make_tuple(owner, type)); + if (size_idx.end() == size_itr) { + d.create([&](auto& pcso){ + pcso.owner = owner; + pcso.type = type; + modify_counters(pcso); }); } else { - d.modify(*itr, modify_counters); + d.modify(*size_itr, modify_counters); } }; // Add contact list if it doesn't exist or update it if it exits auto modify_contact = [&](auto& owner, auto& contact, auto type, const bool is_send) { bool is_new_contact; - auto itr = cidx.find(std::make_tuple(owner, contact)); - if (cidx.end() != itr) { - d.modify(*itr, [&](auto& plo) { - inc_counters(plo.size, is_send); + auto contact_itr = contact_idx.find(std::make_tuple(owner, contact)); + if (contact_idx.end() != contact_itr) { + d.modify(*contact_itr, [&](auto& pco) { + inc_counters(pco.size, is_send); }); is_new_contact = false; - type = itr->type; + type = contact_itr->type; } else { - d.create([&](auto& plo) { - plo.owner = owner; - plo.contact = contact; - plo.type = type; - inc_counters(plo.size, is_send); + d.create([&](auto& pco) { + pco.owner = owner; + pco.contact = contact; + pco.type = type; + inc_counters(pco.size, is_send); }); is_new_contact = true; } @@ -313,6 +313,108 @@ namespace golos { namespace plugins { namespace private_message { modify_contact(pm.to, pm.from, undefined, false); } + void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { + database& d = db(); + + GOLOS_CHECK_OP_PARAM(pdm, to, { + if (pdm.to.size()) { + d.get_account(pdm.to); + } + }); + + fc::flat_map, contact_size_info> stat_map; + + auto update_stat = [&](const message_object& m) { + auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; + auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; + if (m.read_time != time_point_sec::min()) { + send_stat.unread_send_messages--; + recv_stat.unread_recv_messages--; + } + send_stat.total_send_messages--; + recv_stat.total_recv_messages--; + }; + + auto remove_range = [&](auto itr, auto etr) { + while (itr != etr) { + auto& m = (*itr); + ++itr; + update_stat(m); + d.remove(m); + } + }; + + if (pdm.nonce != 0) { + auto& id_idx = d.get_index().indices().get(); + auto id_itr = id_idx.find(std::make_tuple(pdm.from, pdm.to, pdm.nonce)); + + GOLOS_CHECK_OP_PARAM(pdm, nonce, { + GOLOS_ASSERT(id_itr != id_idx.end(), golos::missing_object, "Private message doesn't exist", + ("from", pdm.from)("to", pdm.to)("nonce", pdm.nonce)); + }); + + update_stat(*id_itr); + d.remove(*id_itr); + } else if (pdm.to.size()) { + auto& to_idx = d.get_index().indices().get(); + auto to_itr = to_idx.lower_bound(std::make_tuple(pdm.from, pdm.to, pdm.to_date)); + auto to_etr = to_idx.upper_bound(std::make_tuple(pdm.from, pdm.to, pdm.from_date)); + + GOLOS_CHECK_OP_PARAM(pdm, to, { + GOLOS_ASSERT(to_itr != to_etr, golos::missing_object, + "No private messages to account in requested range", + ("from", pdm.from)("to", pdm.to)("from_date", pdm.from_date)("to_time", pdm.to_date)); + }); + + remove_range(to_itr, to_etr); + } else { + auto& date_idx = d.get_index().indices().get(); + auto date_itr = date_idx.lower_bound(std::make_tuple(pdm.from, pdm.to_date)); + auto date_etr = date_idx.upper_bound(std::make_tuple(pdm.from, pdm.from_date)); + + GOLOS_CHECK_OP_PARAM(pdm, from_date, { + GOLOS_ASSERT(date_itr != date_etr, golos::missing_object, + "No private messages in requested range", + ("from", pdm.from)("from_date", pdm.from_date)("to_date", pdm.to_date)); + }); + + remove_range(date_itr, date_etr); + } + + auto& contact_idx = d.get_index().indices().get(); + auto& size_idx = d.get_index().indices().get(); + + for (const auto& stat_info: stat_map) { + const auto& owner = std::get<0>(stat_info.first); + const auto& size = stat_info.second; + auto contact_itr = contact_idx.find(stat_info.first); + auto size_itr = size_idx.find(owner); + + GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr && size_idx.end() != size_itr, + logic_errors::invalid_size, + "Invalid size"); + + if (contact_itr->size == size && contact_itr->type == undefined) { + d.remove(*contact_itr); + if (size_itr->size.total_contacts == 1) { + d.remove(*size_itr); + } else { + d.modify(*size_itr, [&](auto& pcso) { + pcso.size.total_contacts--; + pcso.size -= size; + }); + } + } else { + d.modify(*contact_itr, [&](auto& pco) { + pco.size -= size; + }); + d.modify(*size_itr, [&](auto& pcso){ + pcso.size -= size; + }); + } + } + } + void private_settings_evaluator::do_apply(const private_settings_operation& ps) { database& d = db(); @@ -331,37 +433,37 @@ namespace golos { namespace plugins { namespace private_message { } } - void private_contact_evaluator::do_apply(const private_contact_operation& pl) { + void private_contact_evaluator::do_apply(const private_contact_operation& pc) { database& d = db(); - if (!plugin_->is_tracked_account(pl.owner) && !plugin_->is_tracked_account(pl.contact)) { + if (!plugin_->is_tracked_account(pc.owner) && !plugin_->is_tracked_account(pc.contact)) { return; } auto& contact_idx = d.get_index().indices().get(); - auto contact_itr = contact_idx.find(std::make_tuple(pl.owner, pl.contact)); + auto contact_itr = contact_idx.find(std::make_tuple(pc.owner, pc.contact)); - GOLOS_CHECK_OP_PARAM(pl, contact, { - d.get_account(pl.contact); + GOLOS_CHECK_OP_PARAM(pc, contact, { + d.get_account(pc.contact); if (d.is_producing()) { - GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pl.type != undefined, + GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pc.type != undefined, logic_errors::add_undefined_contact, "Can't add undefined contact"); std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); - GOLOS_CHECK_LOGIC(contact_itr->type != pl.type || pl.json_metadata != json_metadata, + GOLOS_CHECK_LOGIC(contact_itr->type != pc.type || pc.json_metadata != json_metadata, logic_errors::contact_has_same_type, "Contact has the same type"); } }); auto& owner_idx = d.get_index().indices().get(); - auto dst_itr = owner_idx.find(std::make_tuple(pl.owner, pl.type)); + auto dst_itr = owner_idx.find(std::make_tuple(pc.owner, pc.type)); if (contact_idx.end() != contact_itr) { - auto src_itr = owner_idx.find(std::make_tuple(pl.owner, contact_itr->type)); - if (contact_itr->type != pl.type) { + auto src_itr = owner_idx.find(std::make_tuple(pc.owner, contact_itr->type)); + if (contact_itr->type != pc.type) { // last contact if (src_itr->size.total_contacts == 1) { d.remove(*src_itr); @@ -373,7 +475,7 @@ namespace golos { namespace plugins { namespace private_message { } // has messages or type is not undefined - if (!contact_itr->size.empty() || pl.type != undefined) { + if (!contact_itr->size.empty() || pc.type != undefined) { auto modify_counters = [&](auto& dst) { dst.size.total_contacts++; dst.size += contact_itr->size; @@ -381,8 +483,8 @@ namespace golos { namespace plugins { namespace private_message { if (owner_idx.end() == dst_itr) { d.create([&](auto& dst) { - dst.owner = pl.owner; - dst.type = pl.type; + dst.owner = pc.owner; + dst.type = pc.type; modify_counters(dst); }); } else { @@ -392,31 +494,31 @@ namespace golos { namespace plugins { namespace private_message { } // contact is undefined and no messages - if (pl.type == undefined && contact_itr->size.empty()) { + if (pc.type == undefined && contact_itr->size.empty()) { d.remove(*contact_itr); } else { d.modify(*contact_itr, [&](auto& plo) { - plo.type = pl.type; - from_string(plo.json_metadata, pl.json_metadata); + plo.type = pc.type; + from_string(plo.json_metadata, pc.json_metadata); }); } - } else if (pl.type != undefined) { + } else if (pc.type != undefined) { d.create([&](auto& plo){ - plo.owner = pl.owner; - plo.contact = pl.contact; - plo.type = pl.type; - from_string(plo.json_metadata, pl.json_metadata); + plo.owner = pc.owner; + plo.contact = pc.contact; + plo.type = pc.type; + from_string(plo.json_metadata, pc.json_metadata); }); if (owner_idx.end() == dst_itr) { - d.create([&](auto& plso) { - plso.owner = pl.owner; - plso.type = pl.type; - plso.size.total_contacts = 1; + d.create([&](auto& pcso) { + pcso.owner = pc.owner; + pcso.type = pc.type; + pcso.size.total_contacts = 1; }); } else { - d.modify(*dst_itr, [&](auto& plso) { - plso.size.total_contacts++; + d.modify(*dst_itr, [&](auto& pcso) { + pcso.size.total_contacts++; }); } } From c840eb39a330c9f85ceb49436a135bbe2fc48de0 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:00:14 +0700 Subject: [PATCH 195/250] Add marking of private message with read time. #807 --- .../wallet/include/golos/wallet/wallet.hpp | 28 +++ libraries/wallet/wallet.cpp | 55 ++++++ .../private_message_api_objects.hpp | 4 + .../private_message_evaluators.hpp | 16 ++ .../private_message_exceptions.hpp | 2 + .../private_message_operations.hpp | 16 ++ .../private_message_operations.cpp | 26 +++ .../private_message_plugin.cpp | 186 ++++++++++++------ 8 files changed, 274 insertions(+), 59 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index b5dcb60916..2768b225b5 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1234,6 +1234,32 @@ namespace golos { namespace wallet { annotated_signed_transaction delete_private_messages( const std::string& from, const std::string& to, const std::string& from_date, const std::string& to_date, bool broadcast); + + /** + * Mark encrypted private message with read time + * + * @param from account from which you send message + * @param to account to which you send message + * @param nonce of sended message + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction mark_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast); + + /** + * Mark encrypted private messages with read time by date range + * + * @param from account from which you send message + * @param to account to which you send message + * @param from_date begin of date range + * @param to_date begin of date range + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction mark_private_messages( + const std::string& from, const std::string& to, + const std::string& from_date, const std::string& to_date, bool broadcast); }; struct plain_keys { @@ -1360,6 +1386,8 @@ FC_API( golos::wallet::wallet_api, (edit_private_message) (delete_private_message) (delete_private_messages) + (mark_private_message) + (mark_private_messages) ) FC_REFLECT((golos::wallet::memo_data), (from)(to)(nonce)(check)(encrypted)) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 64f6173a10..8e5bb8df16 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2834,6 +2834,61 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction(trx, broadcast); } + annotated_signed_transaction wallet_api::mark_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast + ) { + FC_ASSERT(!is_locked()); + FC_ASSERT(nonce != 0); + + private_mark_message_operation op; + op.from = from; + op.to = to; + op.nonce = nonce; + op.from_date = time_point_sec::min(); + op.to_date = time_point_sec::min(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + + annotated_signed_transaction wallet_api::mark_private_messages( + const std::string& from, const std::string& to, + const std::string& from_date, const std::string& to_date, + bool broadcast + ) { + FC_ASSERT(!is_locked()); + + private_mark_message_operation op; + op.from = from; + op.to = to; + op.nonce = 0; + op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point_sec::min()).time(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + annotated_signed_transaction wallet_api::follow( const string& follower, const string& following, diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index b24a715c0b..731d94590a 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -69,6 +69,10 @@ namespace golos { namespace plugins { namespace private_message { total_recv_messages == s.total_recv_messages && unread_recv_messages == s.unread_recv_messages; } + + bool operator!=(const contact_size_info& s) const { + return !(this->operator==(s)); + } }; struct contacts_size_info final: public contact_size_info { diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index 2e4dea2aa8..94e1eae49a 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -46,6 +46,22 @@ namespace golos { namespace plugins { namespace private_message { private_message_plugin* plugin_; }; + class private_mark_message_evaluator: + public evaluator_impl + { + public: + using operation_type = private_mark_message_operation; + + private_mark_message_evaluator(database& db, private_message_plugin* plugin) + : evaluator_impl(db), + plugin_(plugin) { + } + + void do_apply(const private_mark_message_operation& o); + + private_message_plugin* plugin_; + }; + class private_settings_evaluator: public evaluator_impl { diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index d609f29c1f..a9a8268eea 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -14,6 +14,7 @@ namespace golos { namespace plugins { namespace private_message { recepient_ignores_messages_from_undefined_contact, add_undefined_contact, contact_has_same_type, + no_unread_messages, invalid_size, }; }; @@ -35,5 +36,6 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (recepient_ignores_messages_from_undefined_contact) (add_undefined_contact) (contact_has_same_type) + (no_unread_messages) (invalid_size) ); \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp index c948fdbc36..78d7ceda95 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -31,6 +31,17 @@ namespace golos { namespace plugins { namespace private_message { void get_required_posting_authorities(flat_set& a) const; }; + struct private_mark_message_operation: public base_operation { + account_name_type from; + account_name_type to; + uint64_t nonce = 0; + time_point_sec from_date; + time_point_sec to_date; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const; + }; + struct private_settings_operation: public base_operation { account_name_type owner; bool ignore_messages_from_undefined_contact = false; @@ -63,6 +74,7 @@ namespace golos { namespace plugins { namespace private_message { using private_message_plugin_operation = fc::static_variant< private_message_operation, private_delete_message_operation, + private_mark_message_operation, private_settings_operation, private_contact_operation>; @@ -76,6 +88,10 @@ FC_REFLECT( (golos::plugins::private_message::private_delete_message_operation), (from)(to)(nonce)(from_date)(to_date)) +FC_REFLECT( + (golos::plugins::private_message::private_mark_message_operation), + (from)(to)(nonce)(from_date)(to_date)) + FC_REFLECT( (golos::plugins::private_message::private_settings_operation), (owner)(ignore_messages_from_undefined_contact)) diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index 09a3d4b778..df1d07f111 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -94,6 +94,32 @@ namespace golos { namespace plugins { namespace private_message { } + void private_mark_message_operation::validate() const { + GOLOS_CHECK_PARAM(to, { + if (to.size()) { + validate_account_name(to); + GOLOS_CHECK_VALUE(to != from, "You cannot mark messages to yourself"); + } + }); + + GOLOS_CHECK_PARAM(from_date, { + GOLOS_CHECK_VALUE(from_date <= to_date, "from_date can't be greater then to_time"); + }); + + GOLOS_CHECK_PARAM(nonce, { + if (nonce != 0) { + GOLOS_CHECK_VALUE(to.size(), "to and nonce should be set both"); + GOLOS_CHECK_VALUE(from_date == time_point_sec::min(), "nonce and from_date can't be used together"); + GOLOS_CHECK_VALUE(to_date == time_point_sec::min(), "nonce and to_date can't be used together"); + } + }); + } + + void private_mark_message_operation::get_required_posting_authorities(flat_set& a) const { + a.insert(to); + } + + void private_contact_operation::validate() const { GOLOS_CHECK_PARAM_ACCOUNT(contact); GOLOS_CHECK_PARAM_ACCOUNT(owner); diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 5e90d15205..6eb04aadb4 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -38,6 +38,7 @@ namespace golos { namespace plugins { namespace private_message { custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); + custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); custom_operation_interpreter_->register_evaluator(&plugin); @@ -313,76 +314,81 @@ namespace golos { namespace plugins { namespace private_message { modify_contact(pm.to, pm.from, undefined, false); } - void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { - database& d = db(); - - GOLOS_CHECK_OP_PARAM(pdm, to, { - if (pdm.to.size()) { - d.get_account(pdm.to); - } - }); - + template < + typename Operation, + typename ProcessAction, + typename UpdateStat, + typename VerifyAction, + typename ContactAction> + void process_private_messages( + database& db, const Operation& po, + UpdateStat&& update_stat, ProcessAction&& process_action, + VerifyAction&& verify_action, ContactAction&& contact_action + ) { fc::flat_map, contact_size_info> stat_map; - auto update_stat = [&](const message_object& m) { - auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; - auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; - if (m.read_time != time_point_sec::min()) { - send_stat.unread_send_messages--; - recv_stat.unread_recv_messages--; - } - send_stat.total_send_messages--; - recv_stat.total_recv_messages--; - }; - - auto remove_range = [&](auto itr, auto etr) { + auto process_range = [&](auto itr, auto etr) { while (itr != etr) { auto& m = (*itr); ++itr; - update_stat(m); - d.remove(m); + update_stat(stat_map, m); + process_action(m); } }; - if (pdm.nonce != 0) { - auto& id_idx = d.get_index().indices().get(); - auto id_itr = id_idx.find(std::make_tuple(pdm.from, pdm.to, pdm.nonce)); + if (po.nonce != 0) { + auto& id_idx = db.get_index().indices().get(); + auto id_itr = id_idx.find(std::make_tuple(po.from, po.to, po.nonce)); - GOLOS_CHECK_OP_PARAM(pdm, nonce, { + GOLOS_CHECK_OP_PARAM(po, nonce, { GOLOS_ASSERT(id_itr != id_idx.end(), golos::missing_object, "Private message doesn't exist", - ("from", pdm.from)("to", pdm.to)("nonce", pdm.nonce)); + ("from", po.from)("to", po.to)("nonce", po.nonce)); }); - update_stat(*id_itr); - d.remove(*id_itr); - } else if (pdm.to.size()) { - auto& to_idx = d.get_index().indices().get(); - auto to_itr = to_idx.lower_bound(std::make_tuple(pdm.from, pdm.to, pdm.to_date)); - auto to_etr = to_idx.upper_bound(std::make_tuple(pdm.from, pdm.to, pdm.from_date)); + update_stat(stat_map, *id_itr); + process_action(*id_itr); + } else if (po.from.size() && po.to.size()) { + auto& to_idx = db.get_index().indices().get(); + auto to_itr = to_idx.lower_bound(std::make_tuple(po.from, po.to, po.to_date)); + auto to_etr = to_idx.upper_bound(std::make_tuple(po.from, po.to, po.from_date)); - GOLOS_CHECK_OP_PARAM(pdm, to, { + GOLOS_CHECK_OP_PARAM(po, to, { GOLOS_ASSERT(to_itr != to_etr, golos::missing_object, "No private messages to account in requested range", - ("from", pdm.from)("to", pdm.to)("from_date", pdm.from_date)("to_time", pdm.to_date)); + ("from", po.from)("to", po.to)("from_date", po.from_date)("to_time", po.to_date)); }); - remove_range(to_itr, to_etr); - } else { - auto& date_idx = d.get_index().indices().get(); - auto date_itr = date_idx.lower_bound(std::make_tuple(pdm.from, pdm.to_date)); - auto date_etr = date_idx.upper_bound(std::make_tuple(pdm.from, pdm.from_date)); + process_range(to_itr, to_etr); + } else if (po.from.size()) { + auto& date_idx = db.get_index().indices().get(); + auto date_itr = date_idx.lower_bound(std::make_tuple(po.from, po.to_date)); + auto date_etr = date_idx.upper_bound(std::make_tuple(po.from, po.from_date)); - GOLOS_CHECK_OP_PARAM(pdm, from_date, { + GOLOS_CHECK_OP_PARAM(po, from_date, { GOLOS_ASSERT(date_itr != date_etr, golos::missing_object, "No private messages in requested range", - ("from", pdm.from)("from_date", pdm.from_date)("to_date", pdm.to_date)); + ("from", po.from)("from_date", po.from_date)("to_date", po.to_date)); }); - remove_range(date_itr, date_etr); + process_range(date_itr, date_etr); + } else if (po.to.size()) { + auto& date_idx = db.get_index().indices().get(); + auto date_itr = date_idx.lower_bound(std::make_tuple(po.to, po.to_date)); + auto date_etr = date_idx.upper_bound(std::make_tuple(po.to, po.from_date)); + + GOLOS_CHECK_OP_PARAM(po, from_date, { + GOLOS_ASSERT(date_itr != date_etr, golos::missing_object, + "No private messages in requested range", + ("to", po.to)("from_date", po.from_date)("to_date", po.to_date)); + }); + + process_range(date_itr, date_etr); } - auto& contact_idx = d.get_index().indices().get(); - auto& size_idx = d.get_index().indices().get(); + verify_action(); + + auto& contact_idx = db.get_index().indices().get(); + auto& size_idx = db.get_index().indices().get(); for (const auto& stat_info: stat_map) { const auto& owner = std::get<0>(stat_info.first); @@ -393,26 +399,88 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr && size_idx.end() != size_itr, logic_errors::invalid_size, "Invalid size"); - - if (contact_itr->size == size && contact_itr->type == undefined) { - d.remove(*contact_itr); - if (size_itr->size.total_contacts == 1) { - d.remove(*size_itr); + + if (!contact_action(*contact_itr, *size_itr, size)) { + db.modify(*contact_itr, [&](auto& pco) { + pco.size -= size; + }); + db.modify(*size_itr, [&](auto& pcso){ + pcso.size -= size; + }); + } + } + } + + void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { + database& d = db(); + + process_private_messages( + d, pdm, + [&](auto& stat_map, const message_object& m) { + auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; + auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; + if (m.read_time == time_point_sec::min()) { + send_stat.unread_send_messages--; + recv_stat.unread_recv_messages--; + } + send_stat.total_send_messages--; + recv_stat.total_recv_messages--; + }, + [&](const message_object& m) { + d.remove(m); + }, + [&]() { + // nothing + }, + [&](const contact_object& co, const contact_size_object& so, const contact_size_info& size) -> bool { + if (co.size != size || co.type != undefined) { + return false; + } + d.remove(co); + if (so.size.total_contacts == 1) { + d.remove(so); } else { - d.modify(*size_itr, [&](auto& pcso) { + d.modify(so, [&](auto& pcso) { pcso.size.total_contacts--; pcso.size -= size; }); } - } else { - d.modify(*contact_itr, [&](auto& pco) { - pco.size -= size; - }); - d.modify(*size_itr, [&](auto& pcso){ - pcso.size -= size; + return true; + } + ); + } + + void private_mark_message_evaluator::do_apply(const private_mark_message_operation& pmm) { + database& d = db(); + + uint32_t total_marked_messages = 0; + auto now = d.head_block_time(); + + process_private_messages( + d, pmm, + [&](auto& stat_map, const message_object& m) { + auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; + auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; + if (m.read_time == time_point_sec::min()) { + send_stat.unread_send_messages--; + recv_stat.unread_recv_messages--; + total_marked_messages++; + } + }, + [&](const message_object& m) { + d.modify(m, [&](message_object& m){ + m.read_time = now; }); + }, + [&](){ + GOLOS_CHECK_LOGIC(total_marked_messages > 0, + logic_errors::no_unread_messages, + "No unread messages in requested range"); + }, + [&](const contact_object&, const contact_size_object&, const contact_size_info&) -> bool { + return false; } - } + ); } void private_settings_evaluator::do_apply(const private_settings_operation& ps) { From 2d631e0e3e5a29d68d9e7fdb1431b72387a7eb31 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:00:22 +0700 Subject: [PATCH 196/250] Add query for inbox of private messages. #807 --- .../include/golos/wallet/remote_node_api.hpp | 2 +- .../wallet/include/golos/wallet/wallet.hpp | 19 ++++++-- libraries/wallet/wallet.cpp | 17 +++++-- .../private_message_api_objects.hpp | 15 ++++++ .../private_message_plugin.cpp | 48 +++++++++++++------ 5 files changed, 79 insertions(+), 22 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 2651656b8d..014f71ed46 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -175,7 +175,7 @@ struct remote_market_history { * Class is used by wallet to send formatted API calls to market_history plugin on remote node. */ struct remote_private_message { - vector get_inbox(const std::string& to, time_point newest, uint16_t limit, uint32_t offset) const; + vector get_inbox(const std::string& to, const inbox_query&) const; vector get_outbox(const std::string& from, time_point newest, uint16_t limit, uint32_t offset) const; settings_api_object get_settings(const std::string& owner) const; contacts_size_api_object get_contacts_size(const std::string& owner) const; diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 2768b225b5..d225d06169 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -45,6 +45,14 @@ namespace golos { namespace wallet { fc::optional min_delegation; }; + struct private_inbox_query { + fc::flat_set select_from; + std::string start_date; + fc::optional unread_only; + fc::optional limit; + fc::optional offset; + }; + struct message_body { std::string subject; std::string body; @@ -1123,9 +1131,10 @@ namespace golos { namespace wallet { annotated_signed_transaction decline_voting_rights( string account, bool decline, bool broadcast ); - // Private message - vector get_inbox( - const std::string& to, const std::string& newest, uint16_t limit, std::uint32_t offset); + /** + * Select inbox private messages for `to` account + */ + vector get_inbox(const std::string& to, const private_inbox_query&); vector get_outbox( const std::string& from, const std::string& newest, uint16_t limit, std::uint32_t offset); @@ -1398,6 +1407,10 @@ FC_REFLECT( (posting_approvals_to_add)(posting_approvals_to_remove) (key_approvals_to_add)(key_approvals_to_remove)) +FC_REFLECT( + (golos::wallet::private_inbox_query), + (select_from)(start_date)(limit)(offset)(unread_only)) + FC_REFLECT((golos::wallet::optional_chain_props), (account_creation_fee)(maximum_block_size)(sbd_interest_rate) (create_account_min_golos_fee)(create_account_min_delegation) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 8e5bb8df16..45dead0111 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2660,12 +2660,23 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } vector wallet_api::get_inbox( - const std::string& to, const std::string& newest_str, uint16_t limit, std::uint32_t offset + const std::string& to, const private_inbox_query& query_template ) { WALLET_CHECK_UNLOCKED(); std::vector result; - auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); - auto remote_result = my->_remote_private_message->get_inbox(to, newest, limit, offset); + inbox_query query; + query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); + query.select_from = query_template.select_from; + if (query_template.unread_only) { + query.unread_only = *query_template.unread_only; + } + if (query_template.limit) { + query.limit = *query_template.limit; + } + if (query_template.offset) { + query.offset = *query_template.offset; + } + auto remote_result = my->_remote_private_message->get_inbox(to, query); result.reserve(remote_result.size()); for (const auto& item : remote_result) { result.emplace_back(item); diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 731d94590a..71fb044139 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -4,6 +4,7 @@ #include +#define PRIVATE_DEFAULT_LIMIT 100 namespace golos { namespace plugins { namespace private_message { @@ -105,6 +106,17 @@ namespace golos { namespace plugins { namespace private_message { fc::flat_map size; }; + /** + * Query for inbox messages + */ + struct inbox_query { + fc::flat_set select_from; + time_point_sec start_date = time_point_sec::min(); + bool unread_only = false; + uint16_t limit = PRIVATE_DEFAULT_LIMIT; + uint32_t offset = 0; + }; + } } } // golos::plugins::private_message FC_REFLECT( @@ -132,3 +144,6 @@ FC_REFLECT( (golos::plugins::private_message::contacts_size_api_object), (size)) +FC_REFLECT( + (golos::plugins::private_message::inbox_query), + (select_from)(start_date)(unread_only)(limit)(offset)) \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 6eb04aadb4..d0a9bec974 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -45,8 +45,7 @@ namespace golos { namespace plugins { namespace private_message { db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); } - std::vector get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset) const; + std::vector get_inbox(const std::string& to, const inbox_query&) const; std::vector get_outbox( const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; @@ -74,19 +73,32 @@ namespace golos { namespace plugins { namespace private_message { }; std::vector private_message_plugin::private_message_plugin_impl::get_inbox( - const std::string& to, time_point newest, uint16_t limit, std::uint32_t offset + const std::string& to, const inbox_query& query ) const { std::vector result; const auto& idx = db_.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(to, newest)); + auto itr = idx.lower_bound(std::make_tuple(to, query.start_date)); auto etr = idx.upper_bound(std::make_tuple(to, time_point::min())); + auto offset = query.offset; - for (; itr != etr && offset; ++itr, --offset); + auto filter = [&](const message_object& o) { + return + (query.select_from.empty() || query.select_from.count(o.from)) && + (!query.unread_only || o.read_time == time_point_sec::min()); + }; - result.reserve(limit); - for (; itr != etr && limit; ++itr, --limit) { - result.emplace_back(*itr); + for (; itr != etr && offset; ++itr) { + if (filter(*itr)){ + --offset; + } + } + + result.reserve(query.limit); + for (; itr != etr && result.size() < query.limit; ++itr) { + if (filter(*itr)) { + result.emplace_back(*itr); + } } return result; @@ -602,8 +614,8 @@ namespace golos { namespace plugins { namespace private_message { } void private_message_plugin::set_program_options( - boost::program_options::options_description &cli, - boost::program_options::options_description &cfg + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg ) { cfg.add_options() ("pm-account-range", @@ -663,15 +675,21 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API(private_message_plugin, get_inbox) { PLUGIN_API_VALIDATE_ARGS( (std::string, to) - (time_point, newest) - (uint16_t, limit) - (uint32_t, offset) + (inbox_query, query) ); - GOLOS_CHECK_LIMIT_PARAM(limit, 100); + GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); + + if (!query.limit) { + query.limit = PRIVATE_DEFAULT_LIMIT; + } + + if (query.start_date == time_point_sec::min()) { + query.start_date = my->db_.head_block_time(); + } return my->db_.with_weak_read_lock([&]() { - return my->get_inbox(to, newest, limit, offset); + return my->get_inbox(to, query); }); } From 8e4bfecaf2847df8eaa00e2fd7102db50e4194d8 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:00:36 +0700 Subject: [PATCH 197/250] Add query for outbox of private messages. #807 --- .../include/golos/wallet/remote_node_api.hpp | 2 +- .../wallet/include/golos/wallet/wallet.hpp | 21 +++++++-- libraries/wallet/wallet.cpp | 17 +++++-- .../private_message_api_objects.hpp | 17 ++++++- .../private_message_plugin.cpp | 44 +++++++++++++------ 5 files changed, 80 insertions(+), 21 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 014f71ed46..95ea0047dd 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -176,7 +176,7 @@ struct remote_market_history { */ struct remote_private_message { vector get_inbox(const std::string& to, const inbox_query&) const; - vector get_outbox(const std::string& from, time_point newest, uint16_t limit, uint32_t offset) const; + vector get_outbox(const std::string& from, const outbox_query&) const; settings_api_object get_settings(const std::string& owner) const; contacts_size_api_object get_contacts_size(const std::string& owner) const; contact_api_object get_contact_info(const std::string& owner, const std::string& contact) const; diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index d225d06169..25bef0500b 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -53,6 +53,14 @@ namespace golos { namespace wallet { fc::optional offset; }; + struct private_outbox_query { + fc::flat_set select_to; + std::string start_date; + fc::optional unread_only; + fc::optional limit; + fc::optional offset; + }; + struct message_body { std::string subject; std::string body; @@ -1134,9 +1142,12 @@ namespace golos { namespace wallet { /** * Select inbox private messages for `to` account */ - vector get_inbox(const std::string& to, const private_inbox_query&); - vector get_outbox( - const std::string& from, const std::string& newest, uint16_t limit, std::uint32_t offset); + vector get_inbox(const std::string& to, const private_inbox_query& query); + + /** + * Select outbox private messages for `to` account + */ + vector get_outbox(const std::string& from, const private_outbox_query& query); /** * Change settings for private messages @@ -1411,6 +1422,10 @@ FC_REFLECT( (golos::wallet::private_inbox_query), (select_from)(start_date)(limit)(offset)(unread_only)) +FC_REFLECT( + (golos::wallet::private_outbox_query), + (select_to)(start_date)(limit)(offset)(unread_only)) + FC_REFLECT((golos::wallet::optional_chain_props), (account_creation_fee)(maximum_block_size)(sbd_interest_rate) (create_account_min_golos_fee)(create_account_min_delegation) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 45dead0111..98e00e30d8 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2687,12 +2687,23 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st } vector wallet_api::get_outbox( - const std::string& from, const std::string& newest_str, uint16_t limit, std::uint32_t offset + const std::string& from, const private_outbox_query& query_template ) { WALLET_CHECK_UNLOCKED(); std::vector result; - auto newest = time_converter(newest_str, time_point::now(), time_point::now()).time(); - auto remote_result = my->_remote_private_message->get_outbox(from, newest, limit, offset); + outbox_query query; + query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); + query.select_to = query_template.select_to; + if (query_template.unread_only) { + query.unread_only = *query_template.unread_only; + } + if (query_template.limit) { + query.limit = *query_template.limit; + } + if (query_template.offset) { + query.offset = *query_template.offset; + } + auto remote_result = my->_remote_private_message->get_outbox(from, query); result.reserve(remote_result.size()); for (const auto& item : remote_result) { result.emplace_back(item); diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 71fb044139..0ac126c3b2 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -117,6 +117,17 @@ namespace golos { namespace plugins { namespace private_message { uint32_t offset = 0; }; + /** + * Query for outbox messages + */ + struct outbox_query { + fc::flat_set select_to; + time_point_sec start_date = time_point_sec::min(); + bool unread_only = false; + uint16_t limit = PRIVATE_DEFAULT_LIMIT; + uint32_t offset = 0; + }; + } } } // golos::plugins::private_message FC_REFLECT( @@ -146,4 +157,8 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::inbox_query), - (select_from)(start_date)(unread_only)(limit)(offset)) \ No newline at end of file + (select_from)(start_date)(unread_only)(limit)(offset)) + +FC_REFLECT( + (golos::plugins::private_message::outbox_query), + (select_to)(start_date)(unread_only)(limit)(offset)) \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index d0a9bec974..ed5eae203b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -47,8 +47,7 @@ namespace golos { namespace plugins { namespace private_message { std::vector get_inbox(const std::string& to, const inbox_query&) const; - std::vector get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset) const; + std::vector get_outbox(const std::string& from, const outbox_query&) const; settings_api_object get_settings(const std::string& owner) const; @@ -105,20 +104,33 @@ namespace golos { namespace plugins { namespace private_message { } std::vector private_message_plugin::private_message_plugin_impl::get_outbox( - const std::string& from, time_point newest, uint16_t limit, std::uint32_t offset + const std::string& from, const outbox_query& query ) const { std::vector result; const auto& idx = db_.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(from, newest)); + auto itr = idx.lower_bound(std::make_tuple(from, query.start_date)); auto etr = idx.upper_bound(std::make_tuple(from, time_point::min())); + auto offset = query.offset; - for (; itr != etr && offset; ++itr, --offset); + auto filter = [&](const message_object& o) { + return + (query.select_to.empty() || query.select_to.count(o.to)) && + (!query.unread_only || o.read_time == time_point_sec::min()); + }; - result.reserve(limit); - for (; itr != etr && limit; ++itr, --limit) { - result.emplace_back(*itr); + for (; itr != etr && offset; ++itr) { + if (filter(*itr)){ + --offset; + } + } + + result.reserve(query.limit); + for (; itr != etr && result.size() < query.limit; ++itr) { + if (filter(*itr)) { + result.emplace_back(*itr); + } } return result; @@ -696,15 +708,21 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API(private_message_plugin, get_outbox) { PLUGIN_API_VALIDATE_ARGS( (std::string, from) - (time_point, newest) - (uint16_t, limit) - (uint32_t, offset) + (outbox_query, query) ); - GOLOS_CHECK_LIMIT_PARAM(limit, 100); + GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); + + if (!query.limit) { + query.limit = PRIVATE_DEFAULT_LIMIT; + } + + if (query.start_date == time_point_sec::min()) { + query.start_date = my->db_.head_block_time(); + } return my->db_.with_weak_read_lock([&]() { - return my->get_outbox(from, newest, limit, offset); + return my->get_outbox(from, query); }); } From 6bac23ac4aecd3736abec0fe91f7d25d7f25141a Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:11 +0700 Subject: [PATCH 198/250] Add communication thread for private messages. #807 --- .../include/golos/wallet/remote_node_api.hpp | 2 + .../wallet/include/golos/wallet/wallet.hpp | 30 ++++++-- libraries/wallet/wallet.cpp | 30 +++++++- .../private_message_api_objects.hpp | 18 ++++- .../private_message_plugin.hpp | 2 + .../private_message_plugin.cpp | 77 +++++++++++++++++++ 6 files changed, 150 insertions(+), 9 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 95ea0047dd..40809cd794 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -177,6 +177,7 @@ struct remote_market_history { struct remote_private_message { vector get_inbox(const std::string& to, const inbox_query&) const; vector get_outbox(const std::string& from, const outbox_query&) const; + vector get_thread(const std::string& from, const std::string& to, const thread_query&) const; settings_api_object get_settings(const std::string& owner) const; contacts_size_api_object get_contacts_size(const std::string& owner) const; contact_api_object get_contact_info(const std::string& owner, const std::string& contact) const; @@ -328,6 +329,7 @@ FC_API( golos::wallet::remote_market_history, FC_API( golos::wallet::remote_private_message, (get_inbox) (get_outbox) + (get_thread) (get_settings) (get_contacts) (get_contacts_size) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 25bef0500b..1e460a077d 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -61,6 +61,13 @@ namespace golos { namespace wallet { fc::optional offset; }; + struct private_thread_query { + std::string start_date; + fc::optional unread_only; + fc::optional limit; + fc::optional offset; + }; + struct message_body { std::string subject; std::string body; @@ -1142,12 +1149,19 @@ namespace golos { namespace wallet { /** * Select inbox private messages for `to` account */ - vector get_inbox(const std::string& to, const private_inbox_query& query); + vector get_private_inbox(const std::string& to, const private_inbox_query& query); /** - * Select outbox private messages for `to` account + * Select outbox private messages for `from` account */ - vector get_outbox(const std::string& from, const private_outbox_query& query); + vector get_private_outbox( + const std::string& from, const private_outbox_query& query); + + /** + * Select thread private messages between `from ` and `to` accounts + */ + vector get_private_thread( + const std::string& from, const std::string& to, const private_thread_query& query); /** * Change settings for private messages @@ -1395,8 +1409,10 @@ FC_API( golos::wallet::wallet_api, (get_active_witnesses) (get_miner_queue) (get_transaction) - (get_inbox) - (get_outbox) + + (get_private_inbox) + (get_private_outbox) + (get_private_thread) (set_private_settings) (get_private_settings) (get_private_contacts) @@ -1426,6 +1442,10 @@ FC_REFLECT( (golos::wallet::private_outbox_query), (select_to)(start_date)(limit)(offset)(unread_only)) +FC_REFLECT( + (golos::wallet::private_thread_query), + (start_date)(limit)(offset)(unread_only)) + FC_REFLECT((golos::wallet::optional_chain_props), (account_creation_fee)(maximum_block_size)(sbd_interest_rate) (create_account_min_golos_fee)(create_account_min_delegation) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 98e00e30d8..5e23d82bf6 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2659,7 +2659,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->_remote_operation_history->get_transaction( id ); } - vector wallet_api::get_inbox( + vector wallet_api::get_private_inbox( const std::string& to, const private_inbox_query& query_template ) { WALLET_CHECK_UNLOCKED(); @@ -2686,7 +2686,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return result; } - vector wallet_api::get_outbox( + vector wallet_api::get_private_outbox( const std::string& from, const private_outbox_query& query_template ) { WALLET_CHECK_UNLOCKED(); @@ -2713,6 +2713,32 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return result; } + vector wallet_api::get_private_thread( + const std::string& from, const std::string& to, const private_thread_query& query_template + ) { + FC_ASSERT(!is_locked()); + std::vector result; + thread_query query; + query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); + if (query_template.unread_only) { + query.unread_only = *query_template.unread_only; + } + if (query_template.limit) { + query.limit = *query_template.limit; + } + if (query_template.offset) { + query.offset = *query_template.offset; + } + auto remote_result = my->_remote_private_message->get_thread(from, to, query); + result.reserve(remote_result.size()); + for (const auto& item : remote_result) { + result.emplace_back(item); + message_body tmp = my->try_decrypt_message(item); + result.back().message = std::move(tmp); + } + return result; + } + annotated_signed_transaction wallet_api::set_private_settings( const std::string& owner, const settings_api_object& s, bool broadcast ) { diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 0ac126c3b2..0708e8c35b 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -127,7 +127,17 @@ namespace golos { namespace plugins { namespace private_message { uint16_t limit = PRIVATE_DEFAULT_LIMIT; uint32_t offset = 0; }; - + + /** + * Query for thread messages + */ + struct thread_query { + time_point_sec start_date = time_point_sec::min(); + bool unread_only = false; + uint16_t limit = PRIVATE_DEFAULT_LIMIT; + uint32_t offset = 0; + }; + } } } // golos::plugins::private_message FC_REFLECT( @@ -161,4 +171,8 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::outbox_query), - (select_to)(start_date)(unread_only)(limit)(offset)) \ No newline at end of file + (select_to)(start_date)(unread_only)(limit)(offset)) + +FC_REFLECT( + (golos::plugins::private_message::thread_query), + (start_date)(unread_only)(limit)(offset)) \ No newline at end of file diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index 23716551c5..50832081e2 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -18,6 +18,7 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API_ARGS(get_inbox, json_rpc::msg_pack, std::vector) DEFINE_API_ARGS(get_outbox, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(get_thread, json_rpc::msg_pack, std::vector) DEFINE_API_ARGS(get_settings , json_rpc::msg_pack, settings_api_object) DEFINE_API_ARGS(get_contact_info, json_rpc::msg_pack, contact_api_object) DEFINE_API_ARGS(get_contacts_size, json_rpc::msg_pack, contacts_size_api_object) @@ -53,6 +54,7 @@ namespace golos { namespace plugins { namespace private_message { DECLARE_API( (get_inbox) (get_outbox) + (get_thread) (get_settings) (get_contact_info) (get_contacts_size) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index ed5eae203b..c681f04d4d 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -49,6 +49,9 @@ namespace golos { namespace plugins { namespace private_message { std::vector get_outbox(const std::string& from, const outbox_query&) const; + std::vector get_thread( + const std::string& from, const std::string& to, const thread_query&) const; + settings_api_object get_settings(const std::string& owner) const; contact_api_object get_contact_item(const contact_object& o) const; @@ -136,6 +139,58 @@ namespace golos { namespace plugins { namespace private_message { return result; } + std::vector private_message_plugin::private_message_plugin_impl::get_thread( + const std::string& from, const std::string& to, const thread_query& query + ) const { + + std::vector result; + const auto& idx = db_.get_index().indices().get(); + + auto from_itr = idx.lower_bound(std::make_tuple(from, query.start_date)); + auto from_etr = idx.upper_bound(std::make_tuple(from, time_point::min())); + auto to_itr = idx.lower_bound(std::make_tuple(to, query.start_date)); + auto to_etr = idx.upper_bound(std::make_tuple(to, time_point::min())); + auto offset = query.offset; + + auto filter = [&](const message_object& o) { + return (!query.unread_only || o.read_time == time_point_sec::min()); + }; + + auto select_itr = [&]() -> auto& { + if (from_itr != from_etr) { + if (to_itr != to_etr && from_itr->id < to_itr->id) { + return to_itr; + } + return from_itr; + } else { + return to_itr; + } + }; + + auto is_done = [&]() { + return from_itr == from_etr && to_itr == to_etr; + }; + + while (!is_done() && offset) { + auto& itr = select_itr(); + if (filter(*itr)){ + --offset; + } + ++itr; + } + + result.reserve(query.limit); + while (!is_done() && result.size() < query.limit) { + auto& itr = select_itr(); + if (filter(*itr)) { + result.emplace_back(*itr); + } + ++itr; + } + + return result; + } + settings_api_object private_message_plugin::private_message_plugin_impl::get_settings( const std::string& owner ) const { @@ -726,6 +781,28 @@ namespace golos { namespace plugins { namespace private_message { }); } + DEFINE_API(private_message_plugin, get_thread) { + PLUGIN_API_VALIDATE_ARGS( + (std::string, from) + (std::string, to) + (thread_query, query) + ); + + GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); + + if (!query.limit) { + query.limit = PRIVATE_DEFAULT_LIMIT; + } + + if (query.start_date == time_point_sec::min()) { + query.start_date = my->db_.head_block_time(); + } + + return my->db_.with_weak_read_lock([&]() { + return my->get_thread(from, to, query); + }); + } + DEFINE_API(private_message_plugin, get_settings) { PLUGIN_API_VALIDATE_ARGS( (std::string, owner) From bb5f9bd01176e7d9351df0a0b7f15a281ba97782 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:18 +0700 Subject: [PATCH 199/250] Fix to_date in delete/mark private messages. #807 --- libraries/wallet/wallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 5e23d82bf6..2ed817903b 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2866,7 +2866,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.to = to; op.nonce = 0; op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point_sec::min()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point_sec::now()).time(); private_message_plugin_operation pop = op; @@ -2921,7 +2921,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.to = to; op.nonce = 0; op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point_sec::min()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point_sec::now()).time(); private_message_plugin_operation pop = op; From 4f199bc90d130f4e9626b928f9901db923a4648e Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:25 +0700 Subject: [PATCH 200/250] Fix ignore pinned private messages. #807 --- .../private_message/private_message_plugin.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index c681f04d4d..3cba057dfc 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -290,7 +290,9 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_LOGIC(contact_itr == contact_idx.end() || contact_itr->type != ignored, logic_errors::sender_in_ignore_list, "Sender is in the ignore list of recipient"); - GOLOS_CHECK_LOGIC(cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_undefined_contact, + GOLOS_CHECK_LOGIC( + (cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_undefined_contact) || + (contact_itr != contact_idx.end() && contact_itr->type == pinned), logic_errors::recepient_ignores_messages_from_undefined_contact, "Recipient accepts messages only from his contact list"); }); @@ -495,7 +497,7 @@ namespace golos { namespace plugins { namespace private_message { process_private_messages( d, pdm, - [&](auto& stat_map, const message_object& m) { + /* update_stat */ [&](auto& stat_map, const message_object& m) { auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; if (m.read_time == time_point_sec::min()) { @@ -505,12 +507,13 @@ namespace golos { namespace plugins { namespace private_message { send_stat.total_send_messages--; recv_stat.total_recv_messages--; }, - [&](const message_object& m) { + /* process_action */ [&](const message_object& m) { d.remove(m); }, - [&]() { + /* verify_action */ [&]() { // nothing }, + /* contact_action */ [&](const contact_object& co, const contact_size_object& so, const contact_size_info& size) -> bool { if (co.size != size || co.type != undefined) { return false; @@ -537,7 +540,7 @@ namespace golos { namespace plugins { namespace private_message { process_private_messages( d, pmm, - [&](auto& stat_map, const message_object& m) { + /* update_stat */ [&](auto& stat_map, const message_object& m) { auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; if (m.read_time == time_point_sec::min()) { @@ -546,16 +549,17 @@ namespace golos { namespace plugins { namespace private_message { total_marked_messages++; } }, - [&](const message_object& m) { + /* process_action */ [&](const message_object& m) { d.modify(m, [&](message_object& m){ m.read_time = now; }); }, - [&](){ + /* verify_action */ [&](){ GOLOS_CHECK_LOGIC(total_marked_messages > 0, logic_errors::no_unread_messages, "No unread messages in requested range"); }, + /* contact_action */ [&](const contact_object&, const contact_size_object&, const contact_size_info&) -> bool { return false; } From 6118acd73e9a5408209cc76ac58c1fcb40093c6a Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:31 +0700 Subject: [PATCH 201/250] Add unit tests for send private messages. #807 --- .../private_message_exceptions.hpp | 2 + .../private_message_plugin.cpp | 50 ++-- tests/CMakeLists.txt | 34 +-- tests/plugin_tests/private_message.cpp | 248 ++++++++++++++++++ 4 files changed, 291 insertions(+), 43 deletions(-) create mode 100644 tests/plugin_tests/private_message.cpp diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index a9a8268eea..60d390e7f7 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -15,6 +15,7 @@ namespace golos { namespace plugins { namespace private_message { add_undefined_contact, contact_has_same_type, no_unread_messages, + invalid_range, invalid_size, }; }; @@ -37,5 +38,6 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (add_undefined_contact) (contact_has_same_type) (no_unread_messages) + (invalid_range) (invalid_size) ); \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 3cba057dfc..44563b8113 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -301,12 +301,12 @@ namespace golos { namespace plugins { namespace private_message { auto id_itr = id_idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); GOLOS_CHECK_OP_PARAM(pm, nonce, { - if (pm.update) { - GOLOS_ASSERT(id_itr != id_idx.end(), golos::missing_object, "Private message doesn't exist", - ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); - } else { - GOLOS_ASSERT(id_itr == id_idx.end(), golos::object_already_exist, "Private message already exist", - ("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + if (pm.update && id_itr == id_idx.end()) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + } else if (!pm.update && id_itr != id_idx.end()){ + GOLOS_THROW_OBJECT_ALREADY_EXIST("private_message", + fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); } }); @@ -422,8 +422,10 @@ namespace golos { namespace plugins { namespace private_message { auto id_itr = id_idx.find(std::make_tuple(po.from, po.to, po.nonce)); GOLOS_CHECK_OP_PARAM(po, nonce, { - GOLOS_ASSERT(id_itr != id_idx.end(), golos::missing_object, "Private message doesn't exist", - ("from", po.from)("to", po.to)("nonce", po.nonce)); + if (id_itr == id_idx.end()) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from)("to", po.to)("nonce", po.nonce)); + } }); update_stat(stat_map, *id_itr); @@ -433,10 +435,12 @@ namespace golos { namespace plugins { namespace private_message { auto to_itr = to_idx.lower_bound(std::make_tuple(po.from, po.to, po.to_date)); auto to_etr = to_idx.upper_bound(std::make_tuple(po.from, po.to, po.from_date)); - GOLOS_CHECK_OP_PARAM(po, to, { - GOLOS_ASSERT(to_itr != to_etr, golos::missing_object, - "No private messages to account in requested range", - ("from", po.from)("to", po.to)("from_date", po.from_date)("to_time", po.to_date)); + GOLOS_CHECK_OP_PARAM(po, from_date, { + if (to_itr == to_etr) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from)("to", po.to) + ("from_date", po.from_date)("to_time", po.to_date)); + } }); process_range(to_itr, to_etr); @@ -445,10 +449,12 @@ namespace golos { namespace plugins { namespace private_message { auto date_itr = date_idx.lower_bound(std::make_tuple(po.from, po.to_date)); auto date_etr = date_idx.upper_bound(std::make_tuple(po.from, po.from_date)); - GOLOS_CHECK_OP_PARAM(po, from_date, { - GOLOS_ASSERT(date_itr != date_etr, golos::missing_object, - "No private messages in requested range", - ("from", po.from)("from_date", po.from_date)("to_date", po.to_date)); + GOLOS_CHECK_OP_PARAM(po, from, { + if (date_itr == date_etr) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from) + ("from_date", po.from_date)("to_time", po.to_date)); + } }); process_range(date_itr, date_etr); @@ -457,13 +463,17 @@ namespace golos { namespace plugins { namespace private_message { auto date_itr = date_idx.lower_bound(std::make_tuple(po.to, po.to_date)); auto date_etr = date_idx.upper_bound(std::make_tuple(po.to, po.from_date)); - GOLOS_CHECK_OP_PARAM(po, from_date, { - GOLOS_ASSERT(date_itr != date_etr, golos::missing_object, - "No private messages in requested range", - ("to", po.to)("from_date", po.from_date)("to_date", po.to_date)); + GOLOS_CHECK_OP_PARAM(po, to, { + if (date_itr == date_etr) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("to", po.to) + ("from_date", po.from_date)("to_time", po.to_date)); + } }); process_range(date_itr, date_etr); + } else { + GOLOS_CHECK_LOGIC(false, logic_errors::invalid_range, "Invalid range"); } verify_action(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2c18996706..a0dc45a4f4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,33 +37,21 @@ file(GLOB PLUGIN_TESTS "plugin_tests/json_rpc.cpp" "plugin_tests/operation_history.cpp" "plugin_tests/account_history.cpp" - "plugin_tests/follow.cpp") + "plugin_tests/follow.cpp" + "plugin_tests/private_message.cpp") add_executable(plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES}) -target_link_libraries(plugin_test golos_chain golos_protocol golos_account_history golos_market_history golos_debug_node golos_social_network fc ${PLATFORM_SPECIFIC_LIBS}) +target_link_libraries(plugin_test + golos_chain golos_protocol + golos_account_history + golos_market_history + golos_debug_node + golos_social_network + golos_private_message + fc + ${PLATFORM_SPECIFIC_LIBS}) target_include_directories(plugin_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") add_test(NAME plugin_test_run COMMAND plugin_test) -macro(add_exec_test) - set(OPTIONS) - set(ONE_VALUE_ARGS NAME) - set(MULTI_VALUE_ARGS FILES) - cmake_parse_arguments(GET "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) - string(TOUPPER "${GET_NAME}_TEST" TESTS) - MESSAGE(STATUS "\"${TESTS}\" \"${GET_NAME}\"") - file(GLOB ${TESTS} ${GET_FILES}) - add_executable("${GET_NAME}_test" ${${TESTS}} ${COMMON_SOURCES}) - target_link_libraries("${GET_NAME}_test" - golos_chain - golos_protocol - golos_account_history - golos_market_history - golos_debug_node - golos_social_network - fc ${PLATFORM_SPECIFIC_LIBS}) - target_include_directories("${GET_NAME}_test" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/common") - add_test(NAME "${GET_NAME}_test_run" COMMAND "${GET_NAME}_test") -endmacro(add_exec_test) - if(MSVC) set_source_files_properties(tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj") endif(MSVC) diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp new file mode 100644 index 0000000000..85d1b7bf79 --- /dev/null +++ b/tests/plugin_tests/private_message.cpp @@ -0,0 +1,248 @@ +#include + +#include "database_fixture.hpp" +#include "helpers.hpp" + +#include + +#include + +#include +#include + +using golos::plugins::json_rpc::msg_pack; +using golos::logic_exception; +using golos::missing_object; +using golos::object_already_exist; +using namespace golos::protocol; +using namespace golos::plugins::private_message; + +struct private_message_fixture : public golos::chain::database_fixture { + private_message_fixture() : golos::chain::database_fixture() { + initialize(); + pm_plugin = appbase::app().find_plugin(); + open_database(); + startup(); + } + + private_message_plugin* pm_plugin = nullptr; +}; + +fc::variant_object make_private_message_id(const std::string& from, const std::string& to, const uint64_t nonce) { + auto res = fc::mutable_variant_object()("from",from)("to",to)("nonce",nonce); + return fc::variant_object(res); +} + +#define _CHECK_EQUAL_MESSAGE_API_OBJECT(L, R) \ + BOOST_CHECK_EQUAL((L).from, (R).from); \ + BOOST_CHECK_EQUAL((L).to, (R).to); \ + BOOST_CHECK_EQUAL((L).nonce, (R).nonce); \ + BOOST_CHECK_EQUAL((L).from_memo_key, (R).from_memo_key); \ + BOOST_CHECK_EQUAL((L).to_memo_key, (R).to_memo_key); \ + BOOST_CHECK_EQUAL((L).create_time, (R).create_time); \ + BOOST_CHECK_EQUAL((L).receive_time, (R).receive_time); \ + BOOST_CHECK_EQUAL((L).checksum, (R).checksum); \ + BOOST_CHECK_EQUAL((L).read_time, (R).read_time); \ + BOOST_CHECK_EQUAL((L).encrypted_message.size(), (R).encrypted_message.size()); \ + BOOST_CHECK_EQUAL(std::equal( \ + (L).encrypted_message.begin(), (L).encrypted_message.end(), \ + (R).encrypted_message.begin(), (R).encrypted_message.end()), true); + +BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) + + BOOST_AUTO_TEST_CASE(private_send_message) { + BOOST_TEST_MESSAGE("Testing: private_message_operation"); + + ACTORS((alice)(bob)); + + BOOST_TEST_MESSAGE("--- Send message"); + + auto alice_bob_nonce = fc::time_point::now().time_since_epoch().count(); + auto alice_bob_secret = alice_private_key.get_shared_secret(bob_private_key.get_public_key()); + std::string alice_bob_msg = "Hello, Bob! My name is Alice."; + std::vector alice_bob_msg_data(alice_bob_msg.begin(), alice_bob_msg.end()); + + auto bob_alice_nonce = alice_bob_nonce + 10; + auto bob_alice_secret = bob_private_key.get_shared_secret(alice_private_key.get_public_key()); + std::string bob_alice_msg = "Hello, Alice!"; + std::vector bob_alice_msg_data(bob_alice_msg.begin(), bob_alice_msg.end()); + + BOOST_CHECK_EQUAL(alice_bob_secret, bob_alice_secret); + + fc::sha512::encoder enc; + fc::raw::pack(enc, alice_bob_nonce); + fc::raw::pack(enc, alice_bob_secret); + auto alice_bob_encrypt_key = enc.result(); + uint32_t alice_bob_checksum = fc::sha256::hash(alice_bob_encrypt_key)._hash[0]; + + private_message_operation mop; + + mop.from = "alice"; + mop.from_memo_key = alice_private_key.get_public_key(); + mop.to = "bob"; + mop.to_memo_key = bob_private_key.get_public_key(); + mop.nonce = alice_bob_nonce; + mop.encrypted_message = fc::aes_encrypt(alice_bob_encrypt_key, alice_bob_msg_data); + mop.checksum = alice_bob_checksum; + + private_message_plugin_operation pop = mop; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + signed_transaction trx; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + enc.reset(); + fc::raw::pack(enc, bob_alice_nonce); + fc::raw::pack(enc, bob_alice_secret); + auto bob_alice_encrypt_key = enc.result(); + uint32_t bob_alice_checksum = fc::sha256::hash(bob_alice_encrypt_key)._hash[0]; + + mop.from = "bob"; + mop.from_memo_key = bob_private_key.get_public_key(); + mop.to = "alice"; + mop.to_memo_key = alice_private_key.get_public_key(); + mop.nonce = bob_alice_nonce; + mop.encrypted_message = fc::aes_encrypt(bob_alice_encrypt_key, bob_alice_msg_data); + mop.checksum = bob_alice_checksum; + + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + + BOOST_TEST_MESSAGE("--- Get message "); + + msg_pack mp; + mp.args = std::vector({fc::variant("bob"), fc::variant(inbox_query())}); + auto bob_inbox = pm_plugin->get_inbox(mp); + + mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + auto bob_outbox = pm_plugin->get_outbox(mp); + + mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + auto alice_inbox = pm_plugin->get_inbox(mp); + + mp.args = std::vector({fc::variant("alice"), fc::variant(outbox_query())}); + auto alice_outbox = pm_plugin->get_outbox(mp); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob"), fc::variant(thread_query())}); + auto alice_bob_thread = pm_plugin->get_thread(mp); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice"), fc::variant(thread_query())}); + auto bob_alice_thread = pm_plugin->get_thread(mp); + + BOOST_CHECK_EQUAL(bob_outbox.size(), 1); + BOOST_CHECK_EQUAL(bob_inbox.size(), 1); + BOOST_CHECK_EQUAL(alice_inbox.size(), 1); + BOOST_CHECK_EQUAL(alice_outbox.size(), 1); + BOOST_CHECK_EQUAL(alice_bob_thread.size(), 2); + BOOST_CHECK_EQUAL(bob_alice_thread.size(), 2); + + _CHECK_EQUAL_MESSAGE_API_OBJECT(bob_outbox[0], alice_inbox[0]); + _CHECK_EQUAL_MESSAGE_API_OBJECT(bob_outbox[0], alice_bob_thread[0]); + _CHECK_EQUAL_MESSAGE_API_OBJECT(bob_outbox[0], bob_alice_thread[0]); + BOOST_CHECK_EQUAL(bob_outbox[0].nonce, bob_alice_nonce); + BOOST_CHECK_EQUAL(bob_outbox[0].checksum, bob_alice_checksum); + + _CHECK_EQUAL_MESSAGE_API_OBJECT(alice_outbox[0], bob_inbox[0]); + _CHECK_EQUAL_MESSAGE_API_OBJECT(alice_outbox[0], alice_bob_thread[1]); + _CHECK_EQUAL_MESSAGE_API_OBJECT(alice_outbox[0], bob_alice_thread[1]); + BOOST_CHECK_EQUAL(alice_outbox[0].nonce, alice_bob_nonce); + BOOST_CHECK_EQUAL(alice_outbox[0].checksum, alice_bob_checksum); + + BOOST_TEST_MESSAGE("--- Decrypt message"); + + enc.reset(); + fc::raw::pack(enc, alice_inbox[0].nonce); + fc::raw::pack(enc, alice_private_key.get_shared_secret(alice_inbox[0].from_memo_key)); + auto alice_bob_decrypt_key = enc.result(); + uint32_t alice_bob_decrypt_checksum = fc::sha256::hash(alice_bob_decrypt_key)._hash[0]; + + BOOST_CHECK_EQUAL(alice_bob_decrypt_checksum, alice_inbox[0].checksum); + + auto alice_bob_decrypt_msg_data = fc::aes_decrypt(alice_bob_decrypt_key, alice_inbox[0].encrypted_message); + + BOOST_CHECK_EQUAL(alice_bob_decrypt_msg_data.size(), bob_alice_msg_data.size()); + BOOST_CHECK_EQUAL(std::equal( + alice_bob_decrypt_msg_data.begin(), alice_bob_decrypt_msg_data.end(), + bob_alice_msg_data.begin(), bob_alice_msg_data.end()), true); + + enc.reset(); + fc::raw::pack(enc, bob_inbox[0].nonce); + fc::raw::pack(enc, bob_private_key.get_shared_secret(bob_inbox[0].from_memo_key)); + auto bob_alice_decrypt_key = enc.result(); + uint32_t bob_alice_decrypt_checksum = fc::sha256::hash(bob_alice_decrypt_key)._hash[0]; + + BOOST_CHECK_EQUAL(bob_alice_decrypt_checksum, bob_inbox[0].checksum); + + auto bob_alice_decrypt_msg_data = fc::aes_decrypt(bob_alice_decrypt_key, bob_inbox[0].encrypted_message); + + BOOST_CHECK_EQUAL(bob_alice_decrypt_msg_data.size(), alice_bob_msg_data.size()); + BOOST_CHECK_EQUAL(std::equal( + bob_alice_decrypt_msg_data.begin(), bob_alice_decrypt_msg_data.end(), + alice_bob_msg_data.begin(), alice_bob_msg_data.end()), true); + + BOOST_TEST_MESSAGE("--- Edit message"); + + std::string alice_bob_edited_msg = "Edited: Hello, Bob! My name is Alice."; + std::vector alice_bob_edited_msg_data(alice_bob_edited_msg.begin(), alice_bob_edited_msg.end()); + + mop.from = "alice"; + mop.from_memo_key = alice_private_key.get_public_key(); + mop.to = "bob"; + mop.to_memo_key = bob_private_key.get_public_key(); + mop.nonce = alice_bob_nonce + 1000; + mop.update = true; + mop.encrypted_message = fc::aes_encrypt(alice_bob_encrypt_key, alice_bob_edited_msg_data); + mop.checksum = alice_bob_checksum; + + pop = mop; + + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(missing_object, "private_message", + make_private_message_id("alice", "bob", mop.nonce)))); + + mop.nonce = alice_bob_nonce; + mop.update = false; + pop = mop; + jop.json = fc::json::to_string(pop); + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(object_already_exist, "private_message", + make_private_message_id("alice", "bob", mop.nonce)))); + + mop.update = true; + pop = mop; + jop.json = fc::json::to_string(pop); + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("bob"), fc::variant(inbox_query())}); + bob_inbox = pm_plugin->get_inbox(mp); + + mp.args = std::vector({fc::variant("alice"), fc::variant(outbox_query())}); + alice_outbox = pm_plugin->get_outbox(mp); + + BOOST_CHECK_EQUAL(bob_inbox.size(), 1); + BOOST_CHECK_EQUAL(alice_outbox.size(), 1); + _CHECK_EQUAL_MESSAGE_API_OBJECT(bob_inbox[0], alice_outbox[0]); + + auto bob_alice_edited_decrypt_msg_data = fc::aes_decrypt(bob_alice_decrypt_key, bob_inbox[0].encrypted_message); + + BOOST_CHECK_EQUAL(bob_alice_edited_decrypt_msg_data.size(), alice_bob_edited_msg_data.size()); + BOOST_CHECK_EQUAL(std::equal( + bob_alice_edited_decrypt_msg_data.begin(), bob_alice_edited_decrypt_msg_data.end(), + alice_bob_edited_msg_data.begin(), alice_bob_edited_msg_data.end()), true); + } + +BOOST_AUTO_TEST_SUITE_END() From de8a69037914f11dbe5f6f7453445156f5034408 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:37 +0700 Subject: [PATCH 202/250] Add tests for private message contacts. #807 --- .../private_message_api_objects.cpp | 3 +- tests/plugin_tests/private_message.cpp | 176 ++++++++++++++++++ 2 files changed, 178 insertions(+), 1 deletion(-) diff --git a/plugins/private_message/private_message_api_objects.cpp b/plugins/private_message/private_message_api_objects.cpp index 2b0edb1211..6dc32fb8d1 100644 --- a/plugins/private_message/private_message_api_objects.cpp +++ b/plugins/private_message/private_message_api_objects.cpp @@ -27,7 +27,8 @@ namespace golos { namespace plugins { namespace private_message { contact_api_object::contact_api_object(const contact_object& o) - : contact(o.contact), + : owner(o.owner), + contact(o.contact), json_metadata(o.json_metadata.begin(), o.json_metadata.end()), local_type(o.type), size(o.size) { diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 85d1b7bf79..26837579aa 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -9,6 +9,7 @@ #include #include +#include using golos::plugins::json_rpc::msg_pack; using golos::logic_exception; @@ -245,4 +246,179 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_bob_edited_msg_data.begin(), alice_bob_edited_msg_data.end()), true); } + BOOST_AUTO_TEST_CASE(private_contact) { + BOOST_TEST_MESSAGE("Testing: private_contact_operation"); + + ACTORS((alice)(bob)(sam)(dave)); + + BOOST_TEST_MESSAGE("--- Undefined contact"); + + private_contact_operation cop; + + cop.owner = "alice"; + cop.contact = "bob"; + cop.type = undefined; + + private_message_plugin_operation pop = cop; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + signed_transaction trx; + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::add_undefined_contact))); + + BOOST_TEST_MESSAGE("--- Ignored contact"); + + cop.type = ignored; + cop.json_metadata = "{}"; + pop = cop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + msg_pack mp; + mp.args = std::vector( + {fc::variant("alice"), fc::variant(ignored), fc::variant(100), fc::variant(0)}); + auto alice_contacts = pm_plugin->get_contacts(mp); + + BOOST_CHECK_EQUAL(alice_contacts.size(), 1); + BOOST_CHECK_EQUAL(alice_contacts[0].owner, cop.owner); + BOOST_CHECK_EQUAL(alice_contacts[0].contact, cop.contact); + BOOST_CHECK_EQUAL(alice_contacts[0].local_type, cop.type); + BOOST_CHECK_EQUAL(alice_contacts[0].remote_type, undefined); + BOOST_CHECK_EQUAL(alice_contacts[0].json_metadata, cop.json_metadata); + BOOST_CHECK_EQUAL(alice_contacts[0].size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_recv_messages, 0); + + generate_block(); + + BOOST_TEST_MESSAGE("--- Same contact"); + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::contact_has_same_type))); + + cop.json_metadata = "{\"name\":\"Mark\"}"; + pop = cop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + BOOST_TEST_MESSAGE("--- Send message from ignored contact"); + + auto base_nonce = fc::time_point::now().time_since_epoch().count(); + + fc::sha512::encoder enc; + fc::raw::pack(enc, base_nonce); + auto encrypt_key = enc.result(); + + private_message_operation mop; + + mop.from = "alice"; + mop.from_memo_key = alice_private_key.get_public_key(); + mop.to = "bob"; + mop.to_memo_key = bob_private_key.get_public_key(); + mop.nonce = base_nonce; + mop.encrypted_message = fc::aes_encrypt(encrypt_key, {}); + mop.checksum = encrypt_key._hash[0]; + + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mop.from = "bob"; + mop.to = "alice"; + mop.nonce += 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, bob_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::sender_in_ignore_list))); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce += 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + + BOOST_TEST_MESSAGE("--- Receive messages only from pinned contacts"); + + mp.args = std::vector({fc::variant("alice")}); + auto alice_settings = pm_plugin->get_settings(mp); + + BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_undefined_contact, false); + + private_settings_operation sop; + sop.owner = "alice"; + sop.ignore_messages_from_undefined_contact = true; + pop = sop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + alice_settings = pm_plugin->get_settings(mp); + + BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_undefined_contact, true); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce += 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, sam_private_key, jop), + CHECK_ERROR(tx_invalid_operation, 0, + CHECK_ERROR(logic_exception, logic_errors::recepient_ignores_messages_from_undefined_contact))); + + cop.owner = "alice"; + cop.contact = "dave"; + cop.type = pinned; + cop.json_metadata = "{}"; + pop = cop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mop.from = "dave"; + mop.to = "alice"; + mop.nonce += 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"dave"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, dave_private_key, jop)); + + mp.args = std::vector({fc::variant("alice"), fc::variant("dave")}); + auto alice_dave_contact = pm_plugin->get_contact_info(mp); + + BOOST_CHECK_EQUAL(alice_dave_contact.owner, "alice"); + BOOST_CHECK_EQUAL(alice_dave_contact.contact, "dave"); + BOOST_CHECK_EQUAL(alice_dave_contact.local_type, pinned); + BOOST_CHECK_EQUAL(alice_dave_contact.remote_type, pinned); + BOOST_CHECK_EQUAL(alice_dave_contact.json_metadata, "{}"); + BOOST_CHECK_EQUAL(alice_dave_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_dave_contact.size.total_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_recv_messages, 1); + } + BOOST_AUTO_TEST_SUITE_END() From 3b7da5cf6fba329ab62f4226d8d36c66c6bd63c2 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:43 +0700 Subject: [PATCH 203/250] Add tests for mark private messages. #807 --- .../private_message_api_objects.hpp | 4 +- .../private_message_plugin.cpp | 18 +- tests/plugin_tests/private_message.cpp | 321 ++++++++++++++++++ 3 files changed, 332 insertions(+), 11 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 0708e8c35b..fb4782831f 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -51,7 +51,7 @@ namespace golos { namespace plugins { namespace private_message { total_send_messages -= s.total_send_messages; unread_send_messages -= s.unread_send_messages; total_recv_messages -= s.total_recv_messages; - unread_recv_messages -= s.unread_send_messages; + unread_recv_messages -= s.unread_recv_messages; return *this; } @@ -59,7 +59,7 @@ namespace golos { namespace plugins { namespace private_message { total_send_messages += s.total_send_messages; unread_send_messages += s.unread_send_messages; total_recv_messages += s.total_recv_messages; - unread_recv_messages += s.unread_send_messages; + unread_recv_messages += s.unread_recv_messages; return *this; } diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 44563b8113..55737cc877 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -406,7 +406,7 @@ namespace golos { namespace plugins { namespace private_message { UpdateStat&& update_stat, ProcessAction&& process_action, VerifyAction&& verify_action, ContactAction&& contact_action ) { - fc::flat_map, contact_size_info> stat_map; + std::map, contact_size_info> stat_map; auto process_range = [&](auto itr, auto etr) { while (itr != etr) { @@ -511,11 +511,11 @@ namespace golos { namespace plugins { namespace private_message { auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; if (m.read_time == time_point_sec::min()) { - send_stat.unread_send_messages--; - recv_stat.unread_recv_messages--; + send_stat.unread_send_messages++; + recv_stat.unread_recv_messages++; } - send_stat.total_send_messages--; - recv_stat.total_recv_messages--; + send_stat.total_send_messages++; + recv_stat.total_recv_messages++; }, /* process_action */ [&](const message_object& m) { d.remove(m); @@ -551,11 +551,11 @@ namespace golos { namespace plugins { namespace private_message { process_private_messages( d, pmm, /* update_stat */ [&](auto& stat_map, const message_object& m) { - auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; - auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; if (m.read_time == time_point_sec::min()) { - send_stat.unread_send_messages--; - recv_stat.unread_recv_messages--; + auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; + auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; + send_stat.unread_send_messages++; + recv_stat.unread_recv_messages++; total_marked_messages++; } }, diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 26837579aa..e58f4e984f 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -421,4 +421,325 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_recv_messages, 1); } + BOOST_AUTO_TEST_CASE(private_mark) { + BOOST_TEST_MESSAGE("Testing: private_mark_message_operation"); + + ACTORS((alice)(bob)(sam)); + + BOOST_TEST_MESSAGE("--- Unread messages"); + + private_contact_operation cop; + + cop.owner = "alice"; + cop.contact = "bob"; + cop.type = pinned; + cop.json_metadata = "{}"; + + private_message_plugin_operation pop = cop; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + signed_transaction trx; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + generate_block(); + + auto base_nonce = fc::time_point::now().time_since_epoch().count(); + + fc::sha512::encoder enc; + fc::raw::pack(enc, base_nonce); + auto encrypt_key = enc.result(); + + private_message_operation mop; + + mop.from = "bob"; + mop.from_memo_key = bob_private_key.get_public_key(); + mop.to = "alice"; + mop.to_memo_key = alice_private_key.get_public_key(); + mop.nonce = base_nonce; + mop.encrypted_message = fc::aes_encrypt(encrypt_key, {}); + mop.checksum = encrypt_key._hash[0]; + + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + generate_block(); + + mop.from = "bob"; + mop.to = "alice"; + mop.nonce = base_nonce + 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + generate_block(); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce = base_nonce + 20; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + generate_block(); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce = base_nonce + 30; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + generate_block(); + + msg_pack mp; + mp.args = std::vector({fc::variant("alice")}); + auto alice_contacts_size = pm_plugin->get_contacts_size(mp); + + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + auto alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 2); + + mp.args = std::vector({fc::variant("bob")}); + auto bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); + auto bob_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Change contact type"); + + cop.owner = "alice"; + cop.contact = "sam"; + cop.type = pinned; + cop.json_metadata = "{}"; + pop = cop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Mark one message"); + + private_mark_message_operation rop; + + rop.from = "bob"; + rop.to = "alice"; + rop.nonce = base_nonce; + pop = rop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 3); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 1); + + mp.args = std::vector({fc::variant("bob")}); + bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); + bob_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Mark all messages from user"); + + generate_block(); + + rop.from = "sam"; + rop.to = "alice"; + rop.nonce = 0; + rop.to_date = db->head_block_time(); + pop = rop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 1); + + mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); + auto alice_sam_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam")}); + auto sam_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(sam_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 2); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); + auto sam_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 2); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Mark all messages to user"); + + generate_block(); + + rop.from = ""; + rop.to = "alice"; + rop.nonce = 0; + rop.to_date = db->head_block_time(); + pop = rop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); + alice_sam_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam")}); + sam_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(sam_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 2); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); + sam_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 2); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob")}); + bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); + bob_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + } BOOST_AUTO_TEST_SUITE_END() From f60379f746fe9f0ba2df1d95832f289ff50027e9 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:01:50 +0700 Subject: [PATCH 204/250] Add tests for delete private messages. #807 --- tests/plugin_tests/private_message.cpp | 250 +++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index e58f4e984f..59051f40db 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -742,4 +742,254 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); } + + BOOST_AUTO_TEST_CASE(private_delete) { + BOOST_TEST_MESSAGE("Testing: private_delete_message_operation"); + + ACTORS((alice)(bob)(sam)); + + BOOST_TEST_MESSAGE("--- Delete message"); + + private_contact_operation cop; + + cop.owner = "alice"; + cop.contact = "sam"; + cop.type = pinned; + cop.json_metadata = "{}"; + + private_message_plugin_operation pop = cop; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + + signed_transaction trx; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + generate_block(); + + auto base_nonce = fc::time_point::now().time_since_epoch().count(); + + fc::sha512::encoder enc; + fc::raw::pack(enc, base_nonce); + auto encrypt_key = enc.result(); + + private_message_operation mop; + + mop.from = "bob"; + mop.from_memo_key = bob_private_key.get_public_key(); + mop.to = "alice"; + mop.to_memo_key = alice_private_key.get_public_key(); + mop.nonce = base_nonce; + mop.encrypted_message = fc::aes_encrypt(encrypt_key, {}); + mop.checksum = encrypt_key._hash[0]; + + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + + generate_block(); + + mop.from = "bob"; + mop.to = "alice"; + mop.nonce = base_nonce + 10; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + + generate_block(); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce = base_nonce + 20; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + + generate_block(); + + mop.from = "sam"; + mop.to = "alice"; + mop.nonce = base_nonce + 30; + pop = mop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + + generate_block(); + + private_delete_message_operation dop; + + dop.from = "bob"; + dop.to = "alice"; + dop.nonce = base_nonce; + pop = dop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + + msg_pack mp; + mp.args = std::vector({fc::variant("alice")}); + auto alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + auto alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 1); + + mp.args = std::vector({fc::variant("bob")}); + auto bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); + auto bob_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Delete all messages from undefined contact"); + + dop.from = "bob"; + dop.to = "alice"; + dop.nonce = 0; + dop.to_date = db->head_block_time(); + pop = dop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"bob"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, bob_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob")}); + bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); + bob_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Delete all messages from pinned contact"); + + dop.from = "sam"; + dop.to = "alice"; + dop.nonce = 0; + dop.to_date = db->head_block_time(); + pop = dop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"sam"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, sam_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); + auto alice_sam_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam")}); + auto sam_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); + auto sam_alice_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + + BOOST_TEST_MESSAGE("--- Change contact type to undefined"); + + cop.owner = "alice"; + cop.contact = "sam"; + cop.type = undefined; + cop.json_metadata = ""; + pop = cop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); + + mp.args = std::vector({fc::variant("sam")}); + sam_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(sam_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(sam_contacts_size.size[ignored].total_contacts, 0); + + mp.args = std::vector({fc::variant("bob")}); + bob_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); + } + BOOST_AUTO_TEST_SUITE_END() From 4a4622fd1361a3886f97e1836a227844f1daea74 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 15:21:40 +0700 Subject: [PATCH 205/250] Refactor errors in cli_wallet for private messages. #807 --- libraries/wallet/wallet.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 2ed817903b..1fede1b151 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1105,7 +1105,7 @@ namespace golos { namespace wallet { const std::string& from, const std::string& to, const uint64_t nonce, const bool update, const message_body& message, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); auto from_account = get_account(from); auto to_account = get_account(to); @@ -2716,7 +2716,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st vector wallet_api::get_private_thread( const std::string& from, const std::string& to, const private_thread_query& query_template ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); std::vector result; thread_query query; query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); @@ -2742,7 +2742,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::set_private_settings( const std::string& owner, const settings_api_object& s, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); private_settings_operation op; op.owner = owner; @@ -2770,8 +2770,10 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const std::string& owner, const std::string& contact, private_contact_type type, fc::optional json_metadata, bool broadcast ) { - FC_ASSERT(!is_locked()); - FC_ASSERT(type != golos::plugins::private_message::undefined || !json_metadata); + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(type, + GOLOS_CHECK_VALUE(type != golos::plugins::private_message::undefined || !json_metadata, + "Undefined contact can't have a json_metadata")); private_contact_operation op; @@ -2830,8 +2832,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::delete_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast ) { - FC_ASSERT(!is_locked()); - FC_ASSERT(nonce != 0); + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); private_delete_message_operation op; op.from = from; @@ -2859,14 +2861,14 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const std::string& from_date, const std::string& to_date, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); private_delete_message_operation op; op.from = from; op.to = to; op.nonce = 0; op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point_sec::now()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point::now()).time(); private_message_plugin_operation pop = op; @@ -2885,8 +2887,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::mark_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast ) { - FC_ASSERT(!is_locked()); - FC_ASSERT(nonce != 0); + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of marked message")); private_mark_message_operation op; op.from = from; @@ -2914,14 +2916,14 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const std::string& from_date, const std::string& to_date, bool broadcast ) { - FC_ASSERT(!is_locked()); + WALLET_CHECK_UNLOCKED(); private_mark_message_operation op; op.from = from; op.to = to; op.nonce = 0; op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point_sec::now()).time(); + op.to_date = time_converter(to_date, time_point::now(), time_point::now()).time(); private_message_plugin_operation pop = op; From 711c9d3b6467d0fa8259b0b7c7ac23ee062d4507 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Tue, 31 Jul 2018 13:10:41 +0300 Subject: [PATCH 206/250] Remove unneeded exceptions + optimisation (review fixes) #801 --- libraries/chain/database.cpp | 12 ++++++------ .../protocol/include/golos/protocol/exceptions.hpp | 8 -------- tests/plugin_tests/operation_history.cpp | 2 -- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index ce1d7e5704..dd9cf5c494 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2408,12 +2408,12 @@ namespace golos { namespace chain { push_virtual_operation(comment_payout_update_operation(comment.author, to_string(comment.permlink))); - const auto& vote_idx = get_index().indices().get(); - auto vote_itr = vote_idx.lower_bound(comment.id); - while (vote_itr != vote_idx.end() && vote_itr->comment == comment.id) { - const auto& cur_vote = *vote_itr; - ++vote_itr; - if (comment.mode == archived) { + if (comment.mode == archived) { + const auto& vote_idx = get_index().indices().get(); + auto vote_itr = vote_idx.lower_bound(comment.id); + while (vote_itr != vote_idx.end() && vote_itr->comment == comment.id) { + const auto& cur_vote = *vote_itr; + ++vote_itr; modify(cur_vote, [&](comment_vote_object& cvo) { cvo.num_changes = -1; // mark vote that it's ready to be removed (archived comment) }); diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 47c941481e..d157d72b9d 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -218,7 +218,6 @@ namespace golos { votes_are_not_allowed, does_not_have_voting_power, voting_weight_is_too_small, - cannot_vote_after_payout, cannot_vote_within_last_minute_before_payout, cannot_vote_with_zero_rshares, voter_has_used_maximum_vote_changes, @@ -228,9 +227,6 @@ namespace golos { cannot_update_comment_because_nothing_changed, reached_comment_max_depth, replies_are_not_allowed, - discussion_is_frozen, - comment_is_archived, - comment_editable_during_first_24_hours, cannot_delete_comment_with_replies, cannot_delete_comment_with_positive_votes, comment_options_requires_no_rshares, @@ -451,7 +447,6 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (votes_are_not_allowed) (does_not_have_voting_power) (voting_weight_is_too_small) - (cannot_vote_after_payout) (cannot_vote_within_last_minute_before_payout) (cannot_vote_with_zero_rshares) (voter_has_used_maximum_vote_changes) @@ -461,9 +456,6 @@ FC_REFLECT_ENUM(golos::logic_exception::error_types, (cannot_update_comment_because_nothing_changed) (reached_comment_max_depth) (replies_are_not_allowed) - (discussion_is_frozen) - (comment_is_archived) - (comment_editable_during_first_24_hours) (cannot_delete_comment_with_replies) (cannot_delete_comment_with_positive_votes) (comment_options_requires_no_rshares) diff --git a/tests/plugin_tests/operation_history.cpp b/tests/plugin_tests/operation_history.cpp index 4eebd9de69..f218b428ca 100644 --- a/tests/plugin_tests/operation_history.cpp +++ b/tests/plugin_tests/operation_history.cpp @@ -66,8 +66,6 @@ BOOST_AUTO_TEST_CASE(operation_history_blocks) { auto _added_ops = add_operations(); auto _found_ops = check_operations(); - elog("---"); - size_t _checked_ops_count = 0; for (auto it = _found_ops.begin(); it != _found_ops.end(); ++it) { auto itr = _added_ops.find(it->first); From 62528c613e85ca028f393ed321035286405eab18 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 31 Jul 2018 19:01:31 +0700 Subject: [PATCH 207/250] Fix value of total_contacts in private messages. #807 --- .../plugins/private_message/private_message_api_objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index fb4782831f..20e9ecb516 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -77,7 +77,7 @@ namespace golos { namespace plugins { namespace private_message { }; struct contacts_size_info final: public contact_size_info { - uint32_t total_contacts; + uint32_t total_contacts = 0; }; /** From fdfb8e9c59e4323fe88ae89a9cbdeed9c6a27bf6 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 31 Jul 2018 20:56:49 +0700 Subject: [PATCH 208/250] Refactor errors: remove PLUGIN_CHECK_LOGIC from follow plugin #791 --- plugins/follow/follow_evaluators.cpp | 6 +++--- plugins/follow/follow_operations.cpp | 4 ++-- plugins/follow/include/golos/plugins/follow/plugin.hpp | 3 --- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/follow/follow_evaluators.cpp b/plugins/follow/follow_evaluators.cpp index d49a429ae1..e9d69bc345 100644 --- a/plugins/follow/follow_evaluators.cpp +++ b/plugins/follow/follow_evaluators.cpp @@ -41,7 +41,7 @@ namespace golos { } if (what & (1 << ignore)) - PLUGIN_CHECK_LOGIC(!(what & (1 << blog)), + GOLOS_CHECK_LOGIC(!(what & (1 << blog)), logic_errors::cannot_follow_and_ignore_simultaneously, "Cannot follow blog and ignore author at the same time"); @@ -109,7 +109,7 @@ namespace golos { void reblog_evaluator::do_apply(const reblog_operation &o) { try { const auto &c = db().get_comment(o.author, o.permlink); - PLUGIN_CHECK_LOGIC(c.parent_author.size() == 0, + GOLOS_CHECK_LOGIC(c.parent_author.size() == 0, logic_errors::only_top_level_posts_reblogged, "Only top level posts can be reblogged"); @@ -125,7 +125,7 @@ namespace golos { auto blog_itr = blog_comment_idx.find(boost::make_tuple(c.id, o.account)); - PLUGIN_CHECK_LOGIC(blog_itr == blog_comment_idx.end(), + GOLOS_CHECK_LOGIC(blog_itr == blog_comment_idx.end(), logic_errors::account_already_reblogged_this_post, "Account has already reblogged this post"); db().create([&](blog_object &b) { diff --git a/plugins/follow/follow_operations.cpp b/plugins/follow/follow_operations.cpp index 31e5251a66..a7dcd31c51 100644 --- a/plugins/follow/follow_operations.cpp +++ b/plugins/follow/follow_operations.cpp @@ -6,13 +6,13 @@ namespace golos { namespace follow { void follow_operation::validate() const { - PLUGIN_CHECK_LOGIC(follower != following, + GOLOS_CHECK_LOGIC(follower != following, logic_errors::cannot_follow_yourself, "You cannot follow yourself"); } void reblog_operation::validate() const { - PLUGIN_CHECK_LOGIC(account != author, + GOLOS_CHECK_LOGIC(account != author, logic_errors::cannot_reblog_own_content, "You cannot reblog your own content"); } diff --git a/plugins/follow/include/golos/plugins/follow/plugin.hpp b/plugins/follow/include/golos/plugins/follow/plugin.hpp index 87c95df365..da43114e6a 100644 --- a/plugins/follow/include/golos/plugins/follow/plugin.hpp +++ b/plugins/follow/include/golos/plugins/follow/plugin.hpp @@ -6,9 +6,6 @@ #include #include "follow_api_object.hpp" -#define PLUGIN_CHECK_LOGIC(expr, type, msg, ...) \ - GOLOS_CHECK_LOGIC(expr, type, msg, ("plugin", "follow") __VA_ARGS__) - namespace golos { namespace plugins { namespace follow { using json_rpc::msg_pack; From 7e301d03262acb0a8ec3e07ee9dc02c395d16def Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 13:29:38 +0700 Subject: [PATCH 209/250] Remove private messages from inbox/outbox. #807 --- .../wallet/include/golos/wallet/wallet.hpp | 12 +- libraries/wallet/wallet.cpp | 20 +- .../private_message_api_objects.hpp | 48 +- .../private_message_objects.hpp | 50 +- .../private_message_operations.hpp | 13 +- .../private_message_api_objects.cpp | 9 +- .../private_message_operations.cpp | 40 +- .../private_message_plugin.cpp | 314 ++++++------ tests/plugin_tests/main.cpp | 2 + tests/plugin_tests/private_message.cpp | 451 +++++++++++------- 10 files changed, 556 insertions(+), 403 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 1e460a077d..d1657f81a8 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1260,14 +1260,14 @@ namespace golos { namespace wallet { * * @param from account from which you send message * @param to account to which you send message - * @param from_date begin of date range - * @param to_date begin of date range + * @param start_date begin of date range + * @param stop_date begin of date range * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ annotated_signed_transaction delete_private_messages( const std::string& from, const std::string& to, - const std::string& from_date, const std::string& to_date, bool broadcast); + const std::string& start_date, const std::string& stop_date, bool broadcast); /** * Mark encrypted private message with read time @@ -1286,14 +1286,14 @@ namespace golos { namespace wallet { * * @param from account from which you send message * @param to account to which you send message - * @param from_date begin of date range - * @param to_date begin of date range + * @param start_date begin of date range + * @param stop_date begin of date range * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ annotated_signed_transaction mark_private_messages( const std::string& from, const std::string& to, - const std::string& from_date, const std::string& to_date, bool broadcast); + const std::string& start_date, const std::string& stop_date, bool broadcast); }; struct plain_keys { diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 1fede1b151..e81c5404b2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2839,8 +2839,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.from = from; op.to = to; op.nonce = nonce; - op.from_date = time_point_sec::min(); - op.to_date = time_point_sec::min(); + op.start_date = time_point_sec::min(); + op.stop_date = time_point_sec::min(); private_message_plugin_operation pop = op; @@ -2858,7 +2858,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::delete_private_messages( const std::string& from, const std::string& to, - const std::string& from_date, const std::string& to_date, + const std::string& start_date, const std::string& stop_date, bool broadcast ) { WALLET_CHECK_UNLOCKED(); @@ -2867,8 +2867,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.from = from; op.to = to; op.nonce = 0; - op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point::now()).time(); + op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); + op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); private_message_plugin_operation pop = op; @@ -2894,8 +2894,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.from = from; op.to = to; op.nonce = nonce; - op.from_date = time_point_sec::min(); - op.to_date = time_point_sec::min(); + op.start_date = time_point_sec::min(); + op.stop_date = time_point_sec::min(); private_message_plugin_operation pop = op; @@ -2913,7 +2913,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::mark_private_messages( const std::string& from, const std::string& to, - const std::string& from_date, const std::string& to_date, + const std::string& start_date, const std::string& stop_date, bool broadcast ) { WALLET_CHECK_UNLOCKED(); @@ -2922,8 +2922,8 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.from = from; op.to = to; op.nonce = 0; - op.from_date = time_converter(from_date, time_point::now(), time_point_sec::min()).time(); - op.to_date = time_converter(to_date, time_point::now(), time_point::now()).time(); + op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); + op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); private_message_plugin_operation pop = op; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 20e9ecb516..9adc0d2c78 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -21,11 +21,13 @@ namespace golos { namespace plugins { namespace private_message { uint64_t nonce = 0; public_key_type from_memo_key; public_key_type to_memo_key; - time_point_sec create_time; - time_point_sec receive_time; uint32_t checksum = 0; - time_point_sec read_time; std::vector encrypted_message; + + time_point_sec create_date; + time_point_sec receive_date; + time_point_sec read_date; + time_point_sec remove_date; }; class settings_object; @@ -38,37 +40,37 @@ namespace golos { namespace plugins { namespace private_message { }; struct contact_size_info { - uint32_t total_send_messages = 0; - uint32_t unread_send_messages = 0; - uint32_t total_recv_messages = 0; - uint32_t unread_recv_messages = 0; + uint32_t total_outbox_messages = 0; + uint32_t unread_outbox_messages = 0; + uint32_t total_inbox_messages = 0; + uint32_t unread_inbox_messages = 0; bool empty() const { - return !total_send_messages && !total_recv_messages; + return !total_outbox_messages && !total_inbox_messages; } contact_size_info& operator-=(const contact_size_info& s) { - total_send_messages -= s.total_send_messages; - unread_send_messages -= s.unread_send_messages; - total_recv_messages -= s.total_recv_messages; - unread_recv_messages -= s.unread_recv_messages; + total_outbox_messages -= s.total_outbox_messages; + unread_outbox_messages -= s.unread_outbox_messages; + total_inbox_messages -= s.total_inbox_messages; + unread_inbox_messages -= s.unread_inbox_messages; return *this; } contact_size_info& operator+=(const contact_size_info& s) { - total_send_messages += s.total_send_messages; - unread_send_messages += s.unread_send_messages; - total_recv_messages += s.total_recv_messages; - unread_recv_messages += s.unread_recv_messages; + total_outbox_messages += s.total_outbox_messages; + unread_outbox_messages += s.unread_outbox_messages; + total_inbox_messages += s.total_inbox_messages; + unread_inbox_messages += s.unread_inbox_messages; return *this; } bool operator==(const contact_size_info& s) const { return - total_send_messages == s.total_send_messages && - unread_send_messages == s.unread_send_messages && - total_recv_messages == s.total_recv_messages && - unread_recv_messages == s.unread_recv_messages; + total_outbox_messages == s.total_outbox_messages && + unread_outbox_messages == s.unread_outbox_messages && + total_inbox_messages == s.total_inbox_messages && + unread_inbox_messages == s.unread_inbox_messages; } bool operator!=(const contact_size_info& s) const { @@ -142,8 +144,8 @@ namespace golos { namespace plugins { namespace private_message { FC_REFLECT( (golos::plugins::private_message::message_api_object), - (from)(to)(from_memo_key)(to_memo_key)(nonce) - (create_time)(receive_time)(read_time)(checksum)(encrypted_message)) + (from)(to)(from_memo_key)(to_memo_key)(nonce)(checksum)(encrypted_message) + (create_date)(receive_date)(read_date)(remove_date)) FC_REFLECT( (golos::plugins::private_message::settings_api_object), @@ -151,7 +153,7 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::contact_size_info), - (total_send_messages)(unread_send_messages)(total_recv_messages)(unread_recv_messages)) + (total_outbox_messages)(unread_outbox_messages)(total_inbox_messages)(unread_inbox_messages)) FC_REFLECT_DERIVED( (golos::plugins::private_message::contacts_size_info), ((golos::plugins::private_message::contact_size_info)), diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 4e0a70123a..76c2659e99 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -40,22 +40,27 @@ namespace golos { namespace plugins { namespace private_message { account_name_type from; account_name_type to; - uint64_t nonce; /// used as seed to secret generation + uint64_t nonce; public_key_type from_memo_key; public_key_type to_memo_key; - time_point_sec create_time; - time_point_sec receive_time; /// time received by blockchain uint32_t checksum = 0; - time_point_sec read_time; buffer_type encrypted_message; + + time_point_sec inbox_create_date; // == time_point_sec::min() means removed message + time_point_sec outbox_create_date; // == time_point_sec::min() means removed message + time_point_sec receive_date; + time_point_sec read_date; + time_point_sec remove_date; }; using message_id_type = message_object::id_type; - struct by_to_date; - struct by_from_date; - struct by_from_to_date; + struct by_inbox; + struct by_inbox_account; + struct by_outbox; + struct by_outbox_account; struct by_nonce; + struct by_owner; struct by_contact; @@ -66,40 +71,53 @@ namespace golos { namespace plugins { namespace private_message { tag, member>, ordered_unique< - tag, + tag, + composite_key< + message_object, + member, + member, + member>, + composite_key_compare< + string_less, + std::greater, + std::greater>>, + ordered_unique< + tag, composite_key< message_object, member, - member, + member, + member, member>, composite_key_compare< + string_less, string_less, std::greater, - std::less>>, + std::greater>>, ordered_unique< - tag, + tag, composite_key< message_object, member, - member, + member, member>, composite_key_compare< string_less, std::greater, - std::less>>, + std::greater>>, ordered_unique< - tag, + tag, composite_key< message_object, member, member, - member, + member, member>, composite_key_compare< string_less, string_less, std::greater, - std::less>>, + std::greater>>, ordered_unique< tag, composite_key< diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp index 78d7ceda95..8581006975 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -21,11 +21,12 @@ namespace golos { namespace plugins { namespace private_message { }; struct private_delete_message_operation: public base_operation { + account_name_type requester; account_name_type from; account_name_type to; uint64_t nonce = 0; - time_point_sec from_date; - time_point_sec to_date; + time_point_sec start_date; + time_point_sec stop_date; void validate() const; void get_required_posting_authorities(flat_set& a) const; @@ -35,8 +36,8 @@ namespace golos { namespace plugins { namespace private_message { account_name_type from; account_name_type to; uint64_t nonce = 0; - time_point_sec from_date; - time_point_sec to_date; + time_point_sec start_date; + time_point_sec stop_date; void validate() const; void get_required_posting_authorities(flat_set& a) const; @@ -86,11 +87,11 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::private_delete_message_operation), - (from)(to)(nonce)(from_date)(to_date)) + (requester)(from)(to)(nonce)(start_date)(stop_date)) FC_REFLECT( (golos::plugins::private_message::private_mark_message_operation), - (from)(to)(nonce)(from_date)(to_date)) + (from)(to)(nonce)(start_date)(stop_date)) FC_REFLECT( (golos::plugins::private_message::private_settings_operation), diff --git a/plugins/private_message/private_message_api_objects.cpp b/plugins/private_message/private_message_api_objects.cpp index 6dc32fb8d1..58e91d1493 100644 --- a/plugins/private_message/private_message_api_objects.cpp +++ b/plugins/private_message/private_message_api_objects.cpp @@ -9,11 +9,12 @@ namespace golos { namespace plugins { namespace private_message { nonce(o.nonce), from_memo_key(o.from_memo_key), to_memo_key(o.to_memo_key), - create_time(o.create_time), - receive_time(o.receive_time), checksum(o.checksum), - read_time(o.read_time), - encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()) { + encrypted_message(o.encrypted_message.begin(), o.encrypted_message.end()), + create_date(std::max(o.inbox_create_date, o.outbox_create_date)), + receive_date(o.receive_date), + read_date(o.read_date), + remove_date(o.remove_date) { } message_api_object::message_api_object() = default; diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index df1d07f111..62b6b43922 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -69,6 +69,12 @@ namespace golos { namespace plugins { namespace private_message { void private_delete_message_operation::validate() const { + GOLOS_CHECK_PARAM(from, { + if (from.size()) { + validate_account_name(from); + } + }); + GOLOS_CHECK_PARAM(to, { if (to.size()) { validate_account_name(to); @@ -76,41 +82,51 @@ namespace golos { namespace plugins { namespace private_message { } }); - GOLOS_CHECK_PARAM(from_date, { - GOLOS_CHECK_VALUE(from_date <= to_date, "from_date can't be greater then to_time"); + GOLOS_CHECK_PARAM(requester, { + validate_account_name(requester); + if (to.size() || from.size()) { + GOLOS_CHECK_VALUE(requester == to || requester == from, + "Requester can't delete messages only from his inbox/outbox"); + } + }); + + GOLOS_CHECK_PARAM(start_date, { + GOLOS_CHECK_VALUE(start_date <= stop_date, "start_date can't be greater then to_time"); }); GOLOS_CHECK_PARAM(nonce, { if (nonce != 0) { GOLOS_CHECK_VALUE(to.size(), "to and nonce should be set both"); - GOLOS_CHECK_VALUE(from_date == time_point_sec::min(), "nonce and from_date can't be used together"); - GOLOS_CHECK_VALUE(to_date == time_point_sec::min(), "nonce and to_date can't be used together"); + GOLOS_CHECK_VALUE(start_date == time_point_sec::min(), "nonce and start_date can't be used together"); + GOLOS_CHECK_VALUE(stop_date == time_point_sec::min(), "nonce and stop_date can't be used together"); } }); } void private_delete_message_operation::get_required_posting_authorities(flat_set& a) const { - a.insert(from); + a.insert(requester); } void private_mark_message_operation::validate() const { - GOLOS_CHECK_PARAM(to, { - if (to.size()) { - validate_account_name(to); + GOLOS_CHECK_PARAM_ACCOUNT(to); + + GOLOS_CHECK_PARAM(from, { + if (from.size()) { + validate_account_name(from); GOLOS_CHECK_VALUE(to != from, "You cannot mark messages to yourself"); } }); - GOLOS_CHECK_PARAM(from_date, { - GOLOS_CHECK_VALUE(from_date <= to_date, "from_date can't be greater then to_time"); + GOLOS_CHECK_PARAM(start_date, { + GOLOS_CHECK_VALUE(start_date <= stop_date, "start_date can't be greater then to_time"); }); GOLOS_CHECK_PARAM(nonce, { if (nonce != 0) { GOLOS_CHECK_VALUE(to.size(), "to and nonce should be set both"); - GOLOS_CHECK_VALUE(from_date == time_point_sec::min(), "nonce and from_date can't be used together"); - GOLOS_CHECK_VALUE(to_date == time_point_sec::min(), "nonce and to_date can't be used together"); + GOLOS_CHECK_VALUE(start_date == time_point_sec::min(), "nonce and start_date can't be used together"); + GOLOS_CHECK_VALUE(stop_date == time_point_sec::min(), "nonce and stop_date can't be used together"); } }); } diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 55737cc877..6568efdf2d 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -74,20 +74,24 @@ namespace golos { namespace plugins { namespace private_message { golos::chain::database& db_; }; + static inline time_point_sec min_create_date() { + return time_point_sec(1); + } + std::vector private_message_plugin::private_message_plugin_impl::get_inbox( const std::string& to, const inbox_query& query ) const { std::vector result; - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(to, query.start_date)); - auto etr = idx.upper_bound(std::make_tuple(to, time_point::min())); + auto etr = idx.upper_bound(std::make_tuple(to, min_create_date())); auto offset = query.offset; auto filter = [&](const message_object& o) { return (query.select_from.empty() || query.select_from.count(o.from)) && - (!query.unread_only || o.read_time == time_point_sec::min()); + (!query.unread_only || o.read_date == time_point_sec::min()); }; for (; itr != etr && offset; ++itr) { @@ -111,16 +115,16 @@ namespace golos { namespace plugins { namespace private_message { ) const { std::vector result; - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(from, query.start_date)); - auto etr = idx.upper_bound(std::make_tuple(from, time_point::min())); + auto etr = idx.upper_bound(std::make_tuple(from, min_create_date())); auto offset = query.offset; auto filter = [&](const message_object& o) { return (query.select_to.empty() || query.select_to.count(o.to)) && - (!query.unread_only || o.read_time == time_point_sec::min()); + (!query.unread_only || o.read_date == time_point_sec::min()); }; for (; itr != etr && offset; ++itr) { @@ -144,48 +148,51 @@ namespace golos { namespace plugins { namespace private_message { ) const { std::vector result; - const auto& idx = db_.get_index().indices().get(); + const auto& outbox_idx = db_.get_index().indices().get(); + const auto& inbox_idx = db_.get_index().indices().get(); - auto from_itr = idx.lower_bound(std::make_tuple(from, query.start_date)); - auto from_etr = idx.upper_bound(std::make_tuple(from, time_point::min())); - auto to_itr = idx.lower_bound(std::make_tuple(to, query.start_date)); - auto to_etr = idx.upper_bound(std::make_tuple(to, time_point::min())); + auto outbox_itr = outbox_idx.lower_bound(std::make_tuple(from, to, query.start_date)); + auto outbox_etr = outbox_idx.upper_bound(std::make_tuple(from, to, min_create_date())); + auto inbox_itr = inbox_idx.lower_bound(std::make_tuple(from, to, query.start_date)); + auto inbox_etr = inbox_idx.upper_bound(std::make_tuple(from, to, min_create_date())); auto offset = query.offset; auto filter = [&](const message_object& o) { - return (!query.unread_only || o.read_time == time_point_sec::min()); + return (!query.unread_only || o.read_date == time_point_sec::min()); + }; + + auto itr_to_message = [&](auto& itr) -> const message_object& { + const message_object& result = *itr; + ++itr; + return result; }; - auto select_itr = [&]() -> auto& { - if (from_itr != from_etr) { - if (to_itr != to_etr && from_itr->id < to_itr->id) { - return to_itr; + auto select_message = [&]() -> const message_object& { + if (outbox_itr != outbox_etr) { + if (inbox_itr == inbox_etr || outbox_itr->id > inbox_itr->id) { + return itr_to_message(outbox_itr); } - return from_itr; - } else { - return to_itr; } + return itr_to_message(inbox_itr); }; - auto is_done = [&]() { - return from_itr == from_etr && to_itr == to_etr; + auto is_not_done = [&]() -> bool { + return outbox_itr != outbox_etr || inbox_itr != inbox_etr; }; - while (!is_done() && offset) { - auto& itr = select_itr(); - if (filter(*itr)){ + while (is_not_done() && offset) { + auto& message = select_message(); + if (filter(message)){ --offset; } - ++itr; } result.reserve(query.limit); - while (!is_done() && result.size() < query.limit) { - auto& itr = select_itr(); - if (filter(*itr)) { - result.emplace_back(*itr); + while (is_not_done() && result.size() < query.limit) { + auto& message = select_message(); + if (filter(message)) { + result.emplace_back(message); } - ++itr; } return result; @@ -310,12 +317,14 @@ namespace golos { namespace plugins { namespace private_message { } }); + auto now = d.head_block_time(); + auto set_message = [&](message_object& pmo) { pmo.from_memo_key = pm.from_memo_key; pmo.to_memo_key = pm.to_memo_key; pmo.checksum = pm.checksum; - pmo.read_time = time_point_sec::min(); - pmo.receive_time = d.head_block_time(); + pmo.read_date = time_point_sec::min(); + pmo.receive_date = now; pmo.encrypted_message.resize(pm.encrypted_message.size()); std::copy( pm.encrypted_message.begin(), pm.encrypted_message.end(), @@ -327,7 +336,9 @@ namespace golos { namespace plugins { namespace private_message { pmo.from = pm.from; pmo.to = pm.to; pmo.nonce = pm.nonce; - pmo.create_time = d.head_block_time(); + pmo.inbox_create_date = now; + pmo.outbox_create_date = now; + pmo.remove_date = time_point_sec::min(); set_message(pmo); }); } else { @@ -340,11 +351,11 @@ namespace golos { namespace plugins { namespace private_message { // Increment counters depends on side of communication auto inc_counters = [&](auto& o, const bool is_send) { if (is_send) { - o.total_send_messages++; - o.unread_send_messages++; + o.total_outbox_messages++; + o.unread_outbox_messages++; } else { - o.total_recv_messages++; - o.unread_recv_messages++; + o.total_inbox_messages++; + o.unread_inbox_messages++; } }; @@ -395,101 +406,83 @@ namespace golos { namespace plugins { namespace private_message { modify_contact(pm.to, pm.from, undefined, false); } - template < - typename Operation, - typename ProcessAction, - typename UpdateStat, - typename VerifyAction, - typename ContactAction> - void process_private_messages( - database& db, const Operation& po, - UpdateStat&& update_stat, ProcessAction&& process_action, - VerifyAction&& verify_action, ContactAction&& contact_action - ) { - std::map, contact_size_info> stat_map; - - auto process_range = [&](auto itr, auto etr) { - while (itr != etr) { - auto& m = (*itr); - ++itr; - update_stat(stat_map, m); - process_action(m); + template + bool process_private_messages(database& db, const Operation& po, Action&& action, Args&&... args) { + auto start_date = std::max(po.start_date, min_create_date()); + auto stop_date = std::max(po.stop_date, min_create_date()); + + auto& idx = db.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(std::forward(args)..., stop_date)); + auto etr = idx.lower_bound(std::make_tuple(std::forward(args)..., start_date)); + + if (itr == etr) { + return false; + } + + while (itr != etr) { + auto& message = (*itr); + ++itr; + if (!action(message)) { + break; } - }; + } + return true; + } + template + void process_group_message_operation( + database& db, const Operation& po, const std::string& requester, + Map& map, ProcessAction&& process_action, ContactAction&& contact_action + ) { if (po.nonce != 0) { - auto& id_idx = db.get_index().indices().get(); - auto id_itr = id_idx.find(std::make_tuple(po.from, po.to, po.nonce)); + auto& idx = db.get_index().indices().get(); + auto itr = idx.find(std::make_tuple(po.from, po.to, po.nonce)); - GOLOS_CHECK_OP_PARAM(po, nonce, { - if (id_itr == id_idx.end()) { - GOLOS_THROW_MISSING_OBJECT("private_message", - fc::mutable_variant_object()("from", po.from)("to", po.to)("nonce", po.nonce)); - } - }); + if (itr == idx.end()) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from)("to", po.to)("nonce", po.nonce)); + } - update_stat(stat_map, *id_itr); - process_action(*id_itr); + process_action(*itr); } else if (po.from.size() && po.to.size()) { - auto& to_idx = db.get_index().indices().get(); - auto to_itr = to_idx.lower_bound(std::make_tuple(po.from, po.to, po.to_date)); - auto to_etr = to_idx.upper_bound(std::make_tuple(po.from, po.to, po.from_date)); - - GOLOS_CHECK_OP_PARAM(po, from_date, { - if (to_itr == to_etr) { - GOLOS_THROW_MISSING_OBJECT("private_message", - fc::mutable_variant_object()("from", po.from)("to", po.to) - ("from_date", po.from_date)("to_time", po.to_date)); - } - }); - - process_range(to_itr, to_etr); + if (!process_private_messages(db, po, process_action, po.from, po.to)) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from)("to", po.to) + ("start_date", po.start_date)("stop_date", po.stop_date)); + } } else if (po.from.size()) { - auto& date_idx = db.get_index().indices().get(); - auto date_itr = date_idx.lower_bound(std::make_tuple(po.from, po.to_date)); - auto date_etr = date_idx.upper_bound(std::make_tuple(po.from, po.from_date)); - - GOLOS_CHECK_OP_PARAM(po, from, { - if (date_itr == date_etr) { - GOLOS_THROW_MISSING_OBJECT("private_message", - fc::mutable_variant_object()("from", po.from) - ("from_date", po.from_date)("to_time", po.to_date)); - } - }); - - process_range(date_itr, date_etr); + if (!process_private_messages(db, po, process_action, po.from)) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", po.from) + ("start_date", po.start_date)("stop_date", po.stop_date)); + } } else if (po.to.size()) { - auto& date_idx = db.get_index().indices().get(); - auto date_itr = date_idx.lower_bound(std::make_tuple(po.to, po.to_date)); - auto date_etr = date_idx.upper_bound(std::make_tuple(po.to, po.from_date)); - - GOLOS_CHECK_OP_PARAM(po, to, { - if (date_itr == date_etr) { - GOLOS_THROW_MISSING_OBJECT("private_message", - fc::mutable_variant_object()("to", po.to) - ("from_date", po.from_date)("to_time", po.to_date)); - } - }); - - process_range(date_itr, date_etr); + if (!process_private_messages(db, po, process_action, po.to)) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("to", po.to) + ("start_date", po.start_date)("stop_date", po.stop_date)); + } } else { - GOLOS_CHECK_LOGIC(false, logic_errors::invalid_range, "Invalid range"); + if (!process_private_messages(db, po, process_action, requester) && + !process_private_messages(db, po, process_action, requester) + ) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("requester", requester) + ("start_date", po.start_date)("stop_date", po.stop_date)); + } } - verify_action(); - auto& contact_idx = db.get_index().indices().get(); auto& size_idx = db.get_index().indices().get(); - for (const auto& stat_info: stat_map) { + for (const auto& stat_info: map) { const auto& owner = std::get<0>(stat_info.first); const auto& size = stat_info.second; auto contact_itr = contact_idx.find(stat_info.first); auto size_itr = size_idx.find(owner); GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr && size_idx.end() != size_itr, - logic_errors::invalid_size, - "Invalid size"); + logic_errors::invalid_size, "Invalid size"); if (!contact_action(*contact_itr, *size_itr, size)) { db.modify(*contact_itr, [&](auto& pco) { @@ -504,24 +497,48 @@ namespace golos { namespace plugins { namespace private_message { void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { database& d = db(); + auto now = d.head_block_time(); + fc::flat_map, contact_size_info> stat_map; + + process_group_message_operation( + d, pdm, pdm.requester, stat_map, + /* process_action */ + [&](const message_object& m) -> bool { + uint32_t unread_messages = 0; - process_private_messages( - d, pdm, - /* update_stat */ [&](auto& stat_map, const message_object& m) { - auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; - auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; - if (m.read_time == time_point_sec::min()) { - send_stat.unread_send_messages++; - recv_stat.unread_recv_messages++; + if (m.read_date == time_point_sec::min()) { + unread_messages = 1; } - send_stat.total_send_messages++; - recv_stat.total_recv_messages++; - }, - /* process_action */ [&](const message_object& m) { - d.remove(m); - }, - /* verify_action */ [&]() { - // nothing + if (pdm.requester == pdm.to) { + // remove from inbox + if (m.inbox_create_date == time_point_sec::min()) { + return false; + } + auto& inbox_stat = stat_map[std::make_tuple(m.to, m.from)]; + inbox_stat.unread_inbox_messages += unread_messages; + inbox_stat.total_inbox_messages++; + } else { + // remove from outbox + if (m.outbox_create_date == time_point_sec::min()) { + return false; + } + auto& outbox_stat = stat_map[std::make_tuple(m.from, m.to)]; + outbox_stat.unread_outbox_messages += unread_messages; + outbox_stat.total_outbox_messages++; + } + if (m.remove_date == time_point_sec::min()) { + d.modify(m, [&](auto& m) { + m.remove_date = now; + if (pdm.requester == pdm.to) { + m.inbox_create_date = time_point_sec::min(); // remove message from find requests + } else { + m.outbox_create_date = time_point_sec::min(); // remove message from find requests + } + }); + } else { + d.remove(m); + } + return true; }, /* contact_action */ [&](const contact_object& co, const contact_size_object& so, const contact_size_info& size) -> bool { @@ -547,33 +564,38 @@ namespace golos { namespace plugins { namespace private_message { uint32_t total_marked_messages = 0; auto now = d.head_block_time(); - - process_private_messages( - d, pmm, - /* update_stat */ [&](auto& stat_map, const message_object& m) { - if (m.read_time == time_point_sec::min()) { - auto& recv_stat = stat_map[std::make_tuple(m.to, m.from)]; - auto& send_stat = stat_map[std::make_tuple(m.from, m.to)]; - send_stat.unread_send_messages++; - recv_stat.unread_recv_messages++; - total_marked_messages++; + fc::flat_map, contact_size_info> stat_map; + + process_group_message_operation( + d, pmm, "", stat_map, + /* process_action */ + [&](const message_object& m) -> bool { + if (m.read_date != time_point_sec::min()) { + return true; } - }, - /* process_action */ [&](const message_object& m) { + // only recipient can mark messages + stat_map[std::make_tuple(m.to, m.from)].unread_inbox_messages++; + // if sender hasn't yet removed the message + if (m.remove_date == time_point_sec::min()) { + stat_map[std::make_tuple(m.from, m.to)].unread_outbox_messages++; + } + total_marked_messages++; + d.modify(m, [&](message_object& m){ - m.read_time = now; + m.read_date = now; }); + return true; }, - /* verify_action */ [&](){ - GOLOS_CHECK_LOGIC(total_marked_messages > 0, - logic_errors::no_unread_messages, - "No unread messages in requested range"); - }, + /* contact_action */ [&](const contact_object&, const contact_size_object&, const contact_size_info&) -> bool { return false; } ); + + GOLOS_CHECK_LOGIC(total_marked_messages > 0, + logic_errors::no_unread_messages, + "No unread messages in requested range"); } void private_settings_evaluator::do_apply(const private_settings_operation& ps) { diff --git a/tests/plugin_tests/main.cpp b/tests/plugin_tests/main.cpp index 1b4e0b2839..744d0b4bbc 100644 --- a/tests/plugin_tests/main.cpp +++ b/tests/plugin_tests/main.cpp @@ -23,6 +23,7 @@ */ #include #include +#include #ifdef BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE plugin_tests @@ -34,6 +35,7 @@ extern uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP; boost::unit_test::test_suite *init_unit_test_suite(int argc, char *argv[]) { + fc::configure_logging(fc::logging_config::default_config(fc::log_level::error)); std::srand(time(NULL)); std::cout << "Random number generator seeded to " << time(NULL) << std::endl; diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 59051f40db..48328cc48d 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -40,18 +40,19 @@ fc::variant_object make_private_message_id(const std::string& from, const std::s BOOST_CHECK_EQUAL((L).nonce, (R).nonce); \ BOOST_CHECK_EQUAL((L).from_memo_key, (R).from_memo_key); \ BOOST_CHECK_EQUAL((L).to_memo_key, (R).to_memo_key); \ - BOOST_CHECK_EQUAL((L).create_time, (R).create_time); \ - BOOST_CHECK_EQUAL((L).receive_time, (R).receive_time); \ BOOST_CHECK_EQUAL((L).checksum, (R).checksum); \ - BOOST_CHECK_EQUAL((L).read_time, (R).read_time); \ BOOST_CHECK_EQUAL((L).encrypted_message.size(), (R).encrypted_message.size()); \ BOOST_CHECK_EQUAL(std::equal( \ (L).encrypted_message.begin(), (L).encrypted_message.end(), \ - (R).encrypted_message.begin(), (R).encrypted_message.end()), true); + (R).encrypted_message.begin(), (R).encrypted_message.end()), true); \ + BOOST_CHECK_EQUAL((L).create_date, (R).create_date); \ + BOOST_CHECK_EQUAL((L).receive_date, (R).receive_date); \ + BOOST_CHECK_EQUAL((L).read_date, (R).read_date); + BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) - BOOST_AUTO_TEST_CASE(private_send_message) { + BOOST_AUTO_TEST_CASE(private_outbox_message) { BOOST_TEST_MESSAGE("Testing: private_message_operation"); ACTORS((alice)(bob)); @@ -293,10 +294,10 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_contacts[0].local_type, cop.type); BOOST_CHECK_EQUAL(alice_contacts[0].remote_type, undefined); BOOST_CHECK_EQUAL(alice_contacts[0].json_metadata, cop.json_metadata); - BOOST_CHECK_EQUAL(alice_contacts[0].size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts[0].size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_inbox_messages, 0); generate_block(); @@ -415,10 +416,10 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_dave_contact.local_type, pinned); BOOST_CHECK_EQUAL(alice_dave_contact.remote_type, pinned); BOOST_CHECK_EQUAL(alice_dave_contact.json_metadata, "{}"); - BOOST_CHECK_EQUAL(alice_dave_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_dave_contact.size.total_recv_messages, 1); - BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_dave_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_dave_contact.size.total_inbox_messages, 1); + BOOST_CHECK_EQUAL(alice_dave_contact.size.unread_inbox_messages, 1); } BOOST_AUTO_TEST_CASE(private_mark) { @@ -506,53 +507,53 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); auto alice_bob_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 2); mp.args = std::vector({fc::variant("bob")}); auto bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 2); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); auto bob_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 2); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); BOOST_TEST_MESSAGE("--- Change contact type"); @@ -570,20 +571,20 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 4); BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].unread_inbox_messages, 0); BOOST_TEST_MESSAGE("--- Mark one message"); @@ -601,33 +602,33 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 3); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 3); mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); alice_bob_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 1); mp.args = std::vector({fc::variant("bob")}); bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); bob_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 1); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); BOOST_TEST_MESSAGE("--- Mark all messages from user"); @@ -636,7 +637,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) rop.from = "sam"; rop.to = "alice"; rop.nonce = 0; - rop.to_date = db->head_block_time(); + rop.stop_date = db->head_block_time(); pop = rop; jop.json = fc::json::to_string(pop); jop.required_posting_auths = {"alice"}; @@ -646,33 +647,33 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 1); mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); auto alice_sam_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_inbox_messages, 0); mp.args = std::vector({fc::variant("sam")}); auto sam_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(sam_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 2); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_outbox_messages, 2); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); auto sam_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 2); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_outbox_messages, 2); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_inbox_messages, 0); BOOST_TEST_MESSAGE("--- Mark all messages to user"); @@ -681,7 +682,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) rop.from = ""; rop.to = "alice"; rop.nonce = 0; - rop.to_date = db->head_block_time(); + rop.stop_date = db->head_block_time(); pop = rop; jop.json = fc::json::to_string(pop); jop.required_posting_auths = {"alice"}; @@ -691,56 +692,56 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 4); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 4); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); alice_sam_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_inbox_messages, 0); mp.args = std::vector({fc::variant("sam")}); sam_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(sam_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 2); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_outbox_messages, 2); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); sam_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 2); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_outbox_messages, 2); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_inbox_messages, 0); mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); alice_bob_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob")}); bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); bob_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 2); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_outbox_messages, 2); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); } BOOST_AUTO_TEST_CASE(private_delete) { @@ -829,6 +830,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) private_delete_message_operation dop; + dop.requester = "bob"; dop.from = "bob"; dop.to = "alice"; dop.nonce = base_nonce; @@ -842,45 +844,58 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) auto alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 2); mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); auto alice_bob_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 1); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 1); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 2); mp.args = std::vector({fc::variant("bob")}); auto bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); auto bob_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 1); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 1); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_outbox_messages, 1); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + auto alice_inbox = pm_plugin->get_inbox(mp); + BOOST_CHECK_EQUAL(alice_inbox.size(), 4); + + mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + auto bob_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(bob_outbox.size(), 1); + + mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + auto sam_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(sam_outbox.size(), 2); - BOOST_TEST_MESSAGE("--- Delete all messages from undefined contact"); + BOOST_TEST_MESSAGE("--- Delete all messages in outbox from undefined contact"); + dop.requester = "bob"; dop.from = "bob"; dop.to = "alice"; dop.nonce = 0; - dop.to_date = db->head_block_time(); + dop.stop_date = db->head_block_time(); pop = dop; jop.json = fc::json::to_string(pop); jop.required_posting_auths = {"bob"}; @@ -888,45 +903,58 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); alice_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 2); mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); alice_bob_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 2); mp.args = std::vector({fc::variant("bob")}); bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("bob"), fc::variant("alice")}); bob_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); - BOOST_TEST_MESSAGE("--- Delete all messages from pinned contact"); + mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + alice_inbox = pm_plugin->get_inbox(mp); + BOOST_CHECK_EQUAL(alice_inbox.size(), 4); + + mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + bob_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(bob_outbox.size(), 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + sam_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(sam_outbox.size(), 2); + + BOOST_TEST_MESSAGE("--- Delete all messages in outbox from pinned contact"); + dop.requester = "sam"; dop.from = "sam"; dop.to = "alice"; dop.nonce = 0; - dop.to_date = db->head_block_time(); + dop.stop_date = db->head_block_time(); pop = dop; jop.json = fc::json::to_string(pop); jop.required_posting_auths = {"sam"}; @@ -935,32 +963,83 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 2); mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); auto alice_sam_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_inbox_messages, 2); mp.args = std::vector({fc::variant("sam")}); auto sam_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_send_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].unread_inbox_messages, 0); mp.args = std::vector({fc::variant("sam"), fc::variant("alice")}); auto sam_alice_contact = pm_plugin->get_contact_info(mp); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_send_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_send_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.total_recv_messages, 0); - BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_recv_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_inbox_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + alice_inbox = pm_plugin->get_inbox(mp); + BOOST_CHECK_EQUAL(alice_inbox.size(), 4); + + mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + bob_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(bob_outbox.size(), 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + sam_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(sam_outbox.size(), 0); + + BOOST_TEST_MESSAGE("--- Delete all messages from inbox"); + + dop.requester = "alice"; + dop.from = ""; + dop.to = "alice"; + dop.nonce = 0; + dop.stop_date = db->head_block_time(); + pop = dop; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths = {"alice"}; + GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); + + mp.args = std::vector({fc::variant("alice")}); + alice_contacts_size = pm_plugin->get_contacts_size(mp); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_inbox_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("sam")}); + alice_sam_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_sam_contact.size.unread_inbox_messages, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant("bob")}); + alice_bob_contact = pm_plugin->get_contact_info(mp); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 0); BOOST_TEST_MESSAGE("--- Change contact type to undefined"); @@ -990,6 +1069,18 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); + + mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + alice_inbox = pm_plugin->get_inbox(mp); + BOOST_CHECK_EQUAL(alice_inbox.size(), 0); + + mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + bob_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(bob_outbox.size(), 0); + + mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + sam_outbox = pm_plugin->get_outbox(mp); + BOOST_CHECK_EQUAL(sam_outbox.size(), 0); } BOOST_AUTO_TEST_SUITE_END() From 14d3ad4112cf34740bf9830c31443e873d7e7049 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 14:02:56 +0700 Subject: [PATCH 210/250] Rename undefined to unknown contact in private messages. #807 --- libraries/wallet/wallet.cpp | 7 +- .../private_message_api_objects.hpp | 8 +- .../private_message_exceptions.hpp | 8 +- .../private_message_objects.hpp | 2 +- .../private_message_operations.hpp | 8 +- .../private_message_api_objects.cpp | 2 +- .../private_message_operations.cpp | 4 +- .../private_message_plugin.cpp | 30 +++---- tests/plugin_tests/private_message.cpp | 88 +++++++++---------- 9 files changed, 77 insertions(+), 80 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index e81c5404b2..6fc6ca0305 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2746,7 +2746,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st private_settings_operation op; op.owner = owner; - op.ignore_messages_from_undefined_contact = s.ignore_messages_from_undefined_contact; + op.ignore_messages_from_unknown_contact = s.ignore_messages_from_unknown_contact; private_message_plugin_operation pop = op; @@ -2771,9 +2771,6 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st private_contact_type type, fc::optional json_metadata, bool broadcast ) { WALLET_CHECK_UNLOCKED(); - GOLOS_CHECK_PARAM(type, - GOLOS_CHECK_VALUE(type != golos::plugins::private_message::undefined || !json_metadata, - "Undefined contact can't have a json_metadata")); private_contact_operation op; @@ -2781,7 +2778,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st op.contact = contact; op.type = type; - if (type == golos::plugins::private_message::undefined) { + if (type == golos::plugins::private_message::unknown) { // op.json_metadata.clear(); } else if (!json_metadata) { op.json_metadata = my->_remote_private_message->get_contact_info(owner, contact).json_metadata; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 9adc0d2c78..387d96da87 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -36,7 +36,7 @@ namespace golos { namespace plugins { namespace private_message { settings_api_object(const settings_object& o); settings_api_object(); - bool ignore_messages_from_undefined_contact = false; + bool ignore_messages_from_unknown_contact = false; }; struct contact_size_info { @@ -94,8 +94,8 @@ namespace golos { namespace plugins { namespace private_message { account_name_type owner; account_name_type contact; std::string json_metadata; - private_contact_type local_type = undefined; - private_contact_type remote_type = undefined; + private_contact_type local_type = unknown; + private_contact_type remote_type = unknown; contact_size_info size; }; @@ -149,7 +149,7 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::settings_api_object), - (ignore_messages_from_undefined_contact)) + (ignore_messages_from_unknown_contact)) FC_REFLECT( (golos::plugins::private_message::contact_size_info), diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index 60d390e7f7..789dab79b5 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -11,8 +11,8 @@ namespace golos { namespace plugins { namespace private_message { from_and_to_memo_keys_must_be_different, cannot_add_contact_to_yourself, sender_in_ignore_list, - recepient_ignores_messages_from_undefined_contact, - add_undefined_contact, + recepient_ignores_messages_from_unknown_contact, + add_unknown_contact, contact_has_same_type, no_unread_messages, invalid_range, @@ -34,8 +34,8 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (from_and_to_memo_keys_must_be_different) (cannot_add_contact_to_yourself) (sender_in_ignore_list) - (recepient_ignores_messages_from_undefined_contact) - (add_undefined_contact) + (recepient_ignores_messages_from_unknown_contact) + (add_unknown_contact) (contact_has_same_type) (no_unread_messages) (invalid_range) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp index 76c2659e99..2bd5a4926c 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_objects.hpp @@ -144,7 +144,7 @@ namespace golos { namespace plugins { namespace private_message { id_type id; account_name_type owner; - bool ignore_messages_from_undefined_contact = false; + bool ignore_messages_from_unknown_contact = false; }; using settings_id_type = settings_object::id_type; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp index 8581006975..58bffcc754 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_operations.hpp @@ -45,7 +45,7 @@ namespace golos { namespace plugins { namespace private_message { struct private_settings_operation: public base_operation { account_name_type owner; - bool ignore_messages_from_undefined_contact = false; + bool ignore_messages_from_unknown_contact = false; void validate() const; void get_required_posting_authorities(flat_set& a) const; @@ -55,7 +55,7 @@ namespace golos { namespace plugins { namespace private_message { * Types of contacts */ enum private_contact_type: uint8_t { - undefined = 1, + unknown = 1, pinned = 2, ignored = 3, }; @@ -95,11 +95,11 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::private_settings_operation), - (owner)(ignore_messages_from_undefined_contact)) + (owner)(ignore_messages_from_unknown_contact)) FC_REFLECT_ENUM( golos::plugins::private_message::private_contact_type, - (undefined)(pinned)(ignored)) + (unknown)(pinned)(ignored)) FC_REFLECT( (golos::plugins::private_message::private_contact_operation), diff --git a/plugins/private_message/private_message_api_objects.cpp b/plugins/private_message/private_message_api_objects.cpp index 58e91d1493..22e5fdf37b 100644 --- a/plugins/private_message/private_message_api_objects.cpp +++ b/plugins/private_message/private_message_api_objects.cpp @@ -21,7 +21,7 @@ namespace golos { namespace plugins { namespace private_message { settings_api_object::settings_api_object(const settings_object& o) - : ignore_messages_from_undefined_contact(o.ignore_messages_from_undefined_contact) { + : ignore_messages_from_unknown_contact(o.ignore_messages_from_unknown_contact) { } settings_api_object::settings_api_object() = default; diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index 62b6b43922..aca21289ec 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -13,7 +13,7 @@ namespace golos { namespace plugins { namespace private_message { static inline bool is_valid_contact_type(private_contact_type type) { switch(type) { - case undefined: + case unknown: case pinned: case ignored: return true; @@ -151,7 +151,7 @@ namespace golos { namespace plugins { namespace private_message { if (json_metadata.size() > 0) { GOLOS_CHECK_PARAM(json_metadata, { GOLOS_CHECK_VALUE(fc::json::is_valid(json_metadata), "JSON Metadata not valid JSON"); - GOLOS_CHECK_VALUE(type != undefined, "JSON Metadata can't be set for undefined contact"); + GOLOS_CHECK_VALUE(type != unknown, "JSON Metadata can't be set for undefined contact"); }); } } diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 6568efdf2d..1ce785fbef 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -243,14 +243,14 @@ namespace golos { namespace plugins { namespace private_message { contacts_size_api_object result; const auto& idx = db_.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(owner, undefined)); + auto itr = idx.lower_bound(std::make_tuple(owner, unknown)); auto etr = idx.upper_bound(std::make_tuple(owner, private_contact_type_size)); for (; etr != itr; ++itr) { result.size[itr->type] = itr->size; } - for (uint8_t i = undefined; i < private_contact_type_size; ++i) { + for (uint8_t i = unknown; i < private_contact_type_size; ++i) { auto t = static_cast(i); if (!result.size.count(t)) { result.size[t] = contacts_size_info(); @@ -298,9 +298,9 @@ namespace golos { namespace plugins { namespace private_message { logic_errors::sender_in_ignore_list, "Sender is in the ignore list of recipient"); GOLOS_CHECK_LOGIC( - (cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_undefined_contact) || + (cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_unknown_contact) || (contact_itr != contact_idx.end() && contact_itr->type == pinned), - logic_errors::recepient_ignores_messages_from_undefined_contact, + logic_errors::recepient_ignores_messages_from_unknown_contact, "Recipient accepts messages only from his contact list"); }); @@ -403,7 +403,7 @@ namespace golos { namespace plugins { namespace private_message { }; modify_contact(pm.from, pm.to, pinned, true); - modify_contact(pm.to, pm.from, undefined, false); + modify_contact(pm.to, pm.from, unknown, false); } template @@ -542,7 +542,7 @@ namespace golos { namespace plugins { namespace private_message { }, /* contact_action */ [&](const contact_object& co, const contact_size_object& so, const contact_size_info& size) -> bool { - if (co.size != size || co.type != undefined) { + if (co.size != size || co.type != unknown) { return false; } d.remove(co); @@ -606,7 +606,7 @@ namespace golos { namespace plugins { namespace private_message { auto set_settings = [&](settings_object& pso) { pso.owner = ps.owner; - pso.ignore_messages_from_undefined_contact = ps.ignore_messages_from_undefined_contact; + pso.ignore_messages_from_unknown_contact = ps.ignore_messages_from_unknown_contact; }; if (idx.end() != itr) { @@ -630,9 +630,9 @@ namespace golos { namespace plugins { namespace private_message { d.get_account(pc.contact); if (d.is_producing()) { - GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pc.type != undefined, - logic_errors::add_undefined_contact, - "Can't add undefined contact"); + GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pc.type != unknown, + logic_errors::add_unknown_contact, + "Can't add unknown contact"); std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); GOLOS_CHECK_LOGIC(contact_itr->type != pc.type || pc.json_metadata != json_metadata, @@ -657,8 +657,8 @@ namespace golos { namespace plugins { namespace private_message { }); } - // has messages or type is not undefined - if (!contact_itr->size.empty() || pc.type != undefined) { + // has messages or type is not unknown + if (!contact_itr->size.empty() || pc.type != unknown) { auto modify_counters = [&](auto& dst) { dst.size.total_contacts++; dst.size += contact_itr->size; @@ -676,8 +676,8 @@ namespace golos { namespace plugins { namespace private_message { } } - // contact is undefined and no messages - if (pc.type == undefined && contact_itr->size.empty()) { + // contact is unknown and no messages + if (pc.type == unknown && contact_itr->size.empty()) { d.remove(*contact_itr); } else { d.modify(*contact_itr, [&](auto& plo) { @@ -685,7 +685,7 @@ namespace golos { namespace plugins { namespace private_message { from_string(plo.json_metadata, pc.json_metadata); }); } - } else if (pc.type != undefined) { + } else if (pc.type != unknown) { d.create([&](auto& plo){ plo.owner = pc.owner; plo.contact = pc.contact; diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 48328cc48d..b22d638b1a 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -252,13 +252,13 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) ACTORS((alice)(bob)(sam)(dave)); - BOOST_TEST_MESSAGE("--- Undefined contact"); + BOOST_TEST_MESSAGE("--- unknown contact"); private_contact_operation cop; cop.owner = "alice"; cop.contact = "bob"; - cop.type = undefined; + cop.type = unknown; private_message_plugin_operation pop = cop; @@ -271,7 +271,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), CHECK_ERROR(tx_invalid_operation, 0, - CHECK_ERROR(logic_exception, logic_errors::add_undefined_contact))); + CHECK_ERROR(logic_exception, logic_errors::add_unknown_contact))); BOOST_TEST_MESSAGE("--- Ignored contact"); @@ -292,7 +292,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_contacts[0].owner, cop.owner); BOOST_CHECK_EQUAL(alice_contacts[0].contact, cop.contact); BOOST_CHECK_EQUAL(alice_contacts[0].local_type, cop.type); - BOOST_CHECK_EQUAL(alice_contacts[0].remote_type, undefined); + BOOST_CHECK_EQUAL(alice_contacts[0].remote_type, unknown); BOOST_CHECK_EQUAL(alice_contacts[0].json_metadata, cop.json_metadata); BOOST_CHECK_EQUAL(alice_contacts[0].size.total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts[0].size.unread_outbox_messages, 0); @@ -363,11 +363,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); auto alice_settings = pm_plugin->get_settings(mp); - BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_undefined_contact, false); + BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_unknown_contact, false); private_settings_operation sop; sop.owner = "alice"; - sop.ignore_messages_from_undefined_contact = true; + sop.ignore_messages_from_unknown_contact = true; pop = sop; jop.json = fc::json::to_string(pop); jop.required_posting_auths = {"alice"}; @@ -376,7 +376,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_settings = pm_plugin->get_settings(mp); - BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_undefined_contact, true); + BOOST_CHECK_EQUAL(alice_settings.ignore_messages_from_unknown_contact, true); mop.from = "sam"; mop.to = "alice"; @@ -387,7 +387,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, sam_private_key, jop), CHECK_ERROR(tx_invalid_operation, 0, - CHECK_ERROR(logic_exception, logic_errors::recepient_ignores_messages_from_undefined_contact))); + CHECK_ERROR(logic_exception, logic_errors::recepient_ignores_messages_from_unknown_contact))); cop.owner = "alice"; cop.contact = "dave"; @@ -506,11 +506,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) auto alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); @@ -532,11 +532,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("bob")}); auto bob_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(bob_contacts_size.size.size(), 3); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_inbox_messages, 0); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].unread_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].total_contacts, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_outbox_messages, 2); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].unread_outbox_messages, 2); @@ -570,11 +570,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); @@ -843,11 +843,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); auto alice_contacts_size = pm_plugin->get_contacts_size(mp); BOOST_CHECK_EQUAL(alice_contacts_size.size.size(), 3); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); @@ -889,7 +889,7 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) auto sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 2); - BOOST_TEST_MESSAGE("--- Delete all messages in outbox from undefined contact"); + BOOST_TEST_MESSAGE("--- Delete all messages in outbox from unknown contact"); dop.requester = "bob"; dop.from = "bob"; @@ -903,11 +903,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); alice_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 1); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 2); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 1); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_inbox_messages, 2); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_inbox_messages, 2); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); @@ -1016,11 +1016,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); alice_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_outbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_inbox_messages, 0); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].unread_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_outbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_inbox_messages, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].unread_inbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_outbox_messages, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].unread_outbox_messages, 0); @@ -1041,11 +1041,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(alice_bob_contact.size.total_inbox_messages, 0); BOOST_CHECK_EQUAL(alice_bob_contact.size.unread_inbox_messages, 0); - BOOST_TEST_MESSAGE("--- Change contact type to undefined"); + BOOST_TEST_MESSAGE("--- Change contact type to unknown"); cop.owner = "alice"; cop.contact = "sam"; - cop.type = undefined; + cop.type = unknown; cop.json_metadata = ""; pop = cop; jop.json = fc::json::to_string(pop); @@ -1054,19 +1054,19 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) mp.args = std::vector({fc::variant("alice")}); alice_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(alice_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(alice_contacts_size.size[unknown].total_contacts, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[pinned].total_contacts, 0); BOOST_CHECK_EQUAL(alice_contacts_size.size[ignored].total_contacts, 0); mp.args = std::vector({fc::variant("sam")}); sam_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(sam_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(sam_contacts_size.size[unknown].total_contacts, 0); BOOST_CHECK_EQUAL(sam_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(sam_contacts_size.size[ignored].total_contacts, 0); mp.args = std::vector({fc::variant("bob")}); bob_contacts_size = pm_plugin->get_contacts_size(mp); - BOOST_CHECK_EQUAL(bob_contacts_size.size[undefined].total_contacts, 0); + BOOST_CHECK_EQUAL(bob_contacts_size.size[unknown].total_contacts, 0); BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); From 93ee46a9edec6c1118b30ac50df7d6d2b6dd2458 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 14:17:53 +0700 Subject: [PATCH 211/250] Refactor decrypting of private messages. #807 --- libraries/wallet/wallet.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 6fc6ca0305..d1e9f57e4b 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1060,24 +1060,20 @@ namespace golos { namespace wallet { fc::sha512 shared_secret; auto it = _keys.find(mo.from_memo_key); + auto pub_key = mo.to_memo_key; if (it == _keys.end()) { it = _keys.find(mo.to_memo_key); - if (it ==_keys.end()) { - wlog("unable to find keys"); - return result; - } - auto priv_key = wif_to_key(it->second); - if (!priv_key) { - return result; - } - shared_secret = priv_key->get_shared_secret(mo.from_memo_key); - } else { - auto priv_key = wif_to_key(it->second); - if (!priv_key) { - return result; - } - shared_secret = priv_key->get_shared_secret(mo.to_memo_key); + auto pub_key = mo.from_memo_key; + } + if (it ==_keys.end()) { + wlog("unable to find keys"); + return result; + } + auto priv_key = wif_to_key(it->second); + if (!priv_key) { + return result; } + shared_secret = priv_key->get_shared_secret(pub_key); fc::sha512::encoder enc; fc::raw::pack(enc, mo.nonce); From 0b11346f1d438079e665199f5e04eeaddd0e4cad Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 17:14:23 +0700 Subject: [PATCH 212/250] Simplify inbox/outbox queries. #807 --- .../include/golos/wallet/remote_node_api.hpp | 6 +- .../wallet/include/golos/wallet/wallet.hpp | 37 ++---- libraries/wallet/wallet.cpp | 81 ++++++------ .../private_message_api_objects.hpp | 35 ++---- .../private_message_plugin.cpp | 116 +++++++----------- tests/plugin_tests/private_message.cpp | 42 ++++--- 6 files changed, 128 insertions(+), 189 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 40809cd794..6d7772f1b8 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -175,9 +175,9 @@ struct remote_market_history { * Class is used by wallet to send formatted API calls to market_history plugin on remote node. */ struct remote_private_message { - vector get_inbox(const std::string& to, const inbox_query&) const; - vector get_outbox(const std::string& from, const outbox_query&) const; - vector get_thread(const std::string& from, const std::string& to, const thread_query&) const; + vector get_inbox(const std::string& to, const message_box_query&) const; + vector get_outbox(const std::string& from, const message_box_query&) const; + vector get_thread(const std::string& from, const std::string& to, const message_thread_query&) const; settings_api_object get_settings(const std::string& owner) const; contacts_size_api_object get_contacts_size(const std::string& owner) const; contact_api_object get_contact_info(const std::string& owner, const std::string& contact) const; diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index d1657f81a8..71f08890cb 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -45,24 +45,16 @@ namespace golos { namespace wallet { fc::optional min_delegation; }; - struct private_inbox_query { - fc::flat_set select_from; - std::string start_date; + struct optional_private_box_query { + fc::flat_set select_accounts; + std::string newest_date; fc::optional unread_only; fc::optional limit; fc::optional offset; }; - struct private_outbox_query { - fc::flat_set select_to; - std::string start_date; - fc::optional unread_only; - fc::optional limit; - fc::optional offset; - }; - - struct private_thread_query { - std::string start_date; + struct optional_private_thread_query { + std::string newest_date; fc::optional unread_only; fc::optional limit; fc::optional offset; @@ -1149,19 +1141,20 @@ namespace golos { namespace wallet { /** * Select inbox private messages for `to` account */ - vector get_private_inbox(const std::string& to, const private_inbox_query& query); + vector get_private_inbox( + const std::string& to, const optional_private_box_query& query); /** * Select outbox private messages for `from` account */ vector get_private_outbox( - const std::string& from, const private_outbox_query& query); + const std::string& from, const optional_private_box_query& query); /** * Select thread private messages between `from ` and `to` accounts */ vector get_private_thread( - const std::string& from, const std::string& to, const private_thread_query& query); + const std::string& from, const std::string& to, const optional_private_thread_query& query); /** * Change settings for private messages @@ -1435,16 +1428,12 @@ FC_REFLECT( (key_approvals_to_add)(key_approvals_to_remove)) FC_REFLECT( - (golos::wallet::private_inbox_query), - (select_from)(start_date)(limit)(offset)(unread_only)) - -FC_REFLECT( - (golos::wallet::private_outbox_query), - (select_to)(start_date)(limit)(offset)(unread_only)) + (golos::wallet::optional_private_box_query), + (select_accounts)(newest_date)(limit)(offset)(unread_only)) FC_REFLECT( - (golos::wallet::private_thread_query), - (start_date)(limit)(offset)(unread_only)) + (golos::wallet::optional_private_thread_query), + (newest_date)(limit)(offset)(unread_only)) FC_REFLECT((golos::wallet::optional_chain_props), (account_creation_fee)(maximum_block_size)(sbd_interest_rate) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d1e9f57e4b..90ac665923 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1054,7 +1054,7 @@ namespace golos { namespace wallet { return it->second; } - message_body try_decrypt_message(const message_api_object& mo) { + message_body try_decrypt_private_message(const message_api_object& mo) const { message_body result; fc::sha512 shared_secret; @@ -1063,7 +1063,7 @@ namespace golos { namespace wallet { auto pub_key = mo.to_memo_key; if (it == _keys.end()) { it = _keys.find(mo.to_memo_key); - auto pub_key = mo.from_memo_key; + pub_key = mo.from_memo_key; } if (it ==_keys.end()) { wlog("unable to find keys"); @@ -1071,6 +1071,7 @@ namespace golos { namespace wallet { } auto priv_key = wif_to_key(it->second); if (!priv_key) { + wlog("empty private key"); return result; } shared_secret = priv_key->get_shared_secret(pub_key); @@ -1097,6 +1098,18 @@ namespace golos { namespace wallet { return result; } + std::vector decrypt_private_messages( + std::vector remote_result + ) const { + std::vector result; + result.reserve(remote_result.size()); + for (const auto& item : remote_result) { + result.emplace_back(item); + result.back().message = try_decrypt_private_message(item); + } + return result; + } + annotated_signed_transaction send_private_message( const std::string& from, const std::string& to, const uint64_t nonce, const bool update, const message_body& message, bool broadcast @@ -2655,14 +2668,10 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->_remote_operation_history->get_transaction( id ); } - vector wallet_api::get_private_inbox( - const std::string& to, const private_inbox_query& query_template - ) { - WALLET_CHECK_UNLOCKED(); - std::vector result; - inbox_query query; - query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); - query.select_from = query_template.select_from; + message_box_query get_message_box_query(const optional_private_box_query& query_template) { + message_box_query query; + query.newest_date = time_converter(query_template.newest_date, time_point::now(), time_point::now()).time(); + query.select_accounts = query_template.select_accounts; if (query_template.unread_only) { query.unread_only = *query_template.unread_only; } @@ -2672,50 +2681,34 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st if (query_template.offset) { query.offset = *query_template.offset; } - auto remote_result = my->_remote_private_message->get_inbox(to, query); - result.reserve(remote_result.size()); - for (const auto& item : remote_result) { - result.emplace_back(item); - message_body tmp = my->try_decrypt_message(item); - result.back().message = std::move(tmp); - } - return result; + return query; + } + + vector wallet_api::get_private_inbox( + const std::string& to, const optional_private_box_query& query + ) { + WALLET_CHECK_UNLOCKED(); + return my->decrypt_private_messages( + my->_remote_private_message->get_inbox( + to, get_message_box_query(query))); } vector wallet_api::get_private_outbox( - const std::string& from, const private_outbox_query& query_template + const std::string& from, const optional_private_box_query& query ) { WALLET_CHECK_UNLOCKED(); - std::vector result; - outbox_query query; - query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); - query.select_to = query_template.select_to; - if (query_template.unread_only) { - query.unread_only = *query_template.unread_only; - } - if (query_template.limit) { - query.limit = *query_template.limit; - } - if (query_template.offset) { - query.offset = *query_template.offset; - } - auto remote_result = my->_remote_private_message->get_outbox(from, query); - result.reserve(remote_result.size()); - for (const auto& item : remote_result) { - result.emplace_back(item); - message_body tmp = my->try_decrypt_message(item); - result.back().message = std::move(tmp); - } - return result; + return my->decrypt_private_messages( + my->_remote_private_message->get_outbox( + from, get_message_box_query(query))); } vector wallet_api::get_private_thread( - const std::string& from, const std::string& to, const private_thread_query& query_template + const std::string& from, const std::string& to, const optional_private_thread_query& query_template ) { WALLET_CHECK_UNLOCKED(); std::vector result; - thread_query query; - query.start_date = time_converter(query_template.start_date, time_point::now(), time_point::now()).time(); + message_thread_query query; + query.newest_date = time_converter(query_template.newest_date, time_point::now(), time_point::now()).time(); if (query_template.unread_only) { query.unread_only = *query_template.unread_only; } @@ -2729,7 +2722,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st result.reserve(remote_result.size()); for (const auto& item : remote_result) { result.emplace_back(item); - message_body tmp = my->try_decrypt_message(item); + message_body tmp = my->try_decrypt_private_message(item); result.back().message = std::move(tmp); } return result; diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 387d96da87..2b01455884 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -109,22 +109,11 @@ namespace golos { namespace plugins { namespace private_message { }; /** - * Query for inbox messages + * Query for inbox/outbox messages */ - struct inbox_query { - fc::flat_set select_from; - time_point_sec start_date = time_point_sec::min(); - bool unread_only = false; - uint16_t limit = PRIVATE_DEFAULT_LIMIT; - uint32_t offset = 0; - }; - - /** - * Query for outbox messages - */ - struct outbox_query { - fc::flat_set select_to; - time_point_sec start_date = time_point_sec::min(); + struct message_box_query { + fc::flat_set select_accounts; + time_point_sec newest_date = time_point_sec::min(); bool unread_only = false; uint16_t limit = PRIVATE_DEFAULT_LIMIT; uint32_t offset = 0; @@ -133,8 +122,8 @@ namespace golos { namespace plugins { namespace private_message { /** * Query for thread messages */ - struct thread_query { - time_point_sec start_date = time_point_sec::min(); + struct message_thread_query { + time_point_sec newest_date = time_point_sec::min(); bool unread_only = false; uint16_t limit = PRIVATE_DEFAULT_LIMIT; uint32_t offset = 0; @@ -168,13 +157,9 @@ FC_REFLECT( (size)) FC_REFLECT( - (golos::plugins::private_message::inbox_query), - (select_from)(start_date)(unread_only)(limit)(offset)) + (golos::plugins::private_message::message_box_query), + (select_accounts)(newest_date)(unread_only)(limit)(offset)) FC_REFLECT( - (golos::plugins::private_message::outbox_query), - (select_to)(start_date)(unread_only)(limit)(offset)) - -FC_REFLECT( - (golos::plugins::private_message::thread_query), - (start_date)(unread_only)(limit)(offset)) \ No newline at end of file + (golos::plugins::private_message::message_thread_query), + (newest_date)(unread_only)(limit)(offset)) \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 1ce785fbef..8dfbd8571b 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -45,12 +45,12 @@ namespace golos { namespace plugins { namespace private_message { db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); } - std::vector get_inbox(const std::string& to, const inbox_query&) const; - - std::vector get_outbox(const std::string& from, const outbox_query&) const; + template + std::vector get_message_box( + const std::string& account, const message_box_query&, Filter&&) const; std::vector get_thread( - const std::string& from, const std::string& to, const thread_query&) const; + const std::string& from, const std::string& to, const message_thread_query&) const; settings_api_object get_settings(const std::string& owner) const; @@ -78,63 +78,36 @@ namespace golos { namespace plugins { namespace private_message { return time_point_sec(1); } - std::vector private_message_plugin::private_message_plugin_impl::get_inbox( - const std::string& to, const inbox_query& query + template + std::vector private_message_plugin::private_message_plugin_impl::get_message_box( + const std::string& to, const message_box_query& query, Filter&& filter ) const { std::vector result; - const auto& idx = db_.get_index().indices().get(); + const auto& idx = db_.get_index().indices().get(); + auto newest_date = query.newest_date; + + if (newest_date == time_point_sec::min()) { + newest_date = db_.head_block_time(); + } - auto itr = idx.lower_bound(std::make_tuple(to, query.start_date)); + auto itr = idx.lower_bound(std::make_tuple(to, newest_date)); auto etr = idx.upper_bound(std::make_tuple(to, min_create_date())); auto offset = query.offset; - auto filter = [&](const message_object& o) { - return - (query.select_from.empty() || query.select_from.count(o.from)) && - (!query.unread_only || o.read_date == time_point_sec::min()); - }; - for (; itr != etr && offset; ++itr) { if (filter(*itr)){ --offset; } } - result.reserve(query.limit); - for (; itr != etr && result.size() < query.limit; ++itr) { - if (filter(*itr)) { - result.emplace_back(*itr); - } - } - - return result; - } - - std::vector private_message_plugin::private_message_plugin_impl::get_outbox( - const std::string& from, const outbox_query& query - ) const { + auto limit = query.limit; - std::vector result; - const auto& idx = db_.get_index().indices().get(); - - auto itr = idx.lower_bound(std::make_tuple(from, query.start_date)); - auto etr = idx.upper_bound(std::make_tuple(from, min_create_date())); - auto offset = query.offset; - - auto filter = [&](const message_object& o) { - return - (query.select_to.empty() || query.select_to.count(o.to)) && - (!query.unread_only || o.read_date == time_point_sec::min()); - }; - - for (; itr != etr && offset; ++itr) { - if (filter(*itr)){ - --offset; - } + if (!limit) { + limit = PRIVATE_DEFAULT_LIMIT; } - result.reserve(query.limit); - for (; itr != etr && result.size() < query.limit; ++itr) { + result.reserve(limit); + for (; itr != etr && result.size() < limit; ++itr) { if (filter(*itr)) { result.emplace_back(*itr); } @@ -143,17 +116,17 @@ namespace golos { namespace plugins { namespace private_message { return result; } - std::vector private_message_plugin::private_message_plugin_impl::get_thread( - const std::string& from, const std::string& to, const thread_query& query + std::vector private_message_plugin::private_message_plugin_impl::get_thread( + const std::string& from, const std::string& to, const message_thread_query& query ) const { std::vector result; const auto& outbox_idx = db_.get_index().indices().get(); const auto& inbox_idx = db_.get_index().indices().get(); - auto outbox_itr = outbox_idx.lower_bound(std::make_tuple(from, to, query.start_date)); + auto outbox_itr = outbox_idx.lower_bound(std::make_tuple(from, to, query.newest_date)); auto outbox_etr = outbox_idx.upper_bound(std::make_tuple(from, to, min_create_date())); - auto inbox_itr = inbox_idx.lower_bound(std::make_tuple(from, to, query.start_date)); + auto inbox_itr = inbox_idx.lower_bound(std::make_tuple(from, to, query.newest_date)); auto inbox_etr = inbox_idx.upper_bound(std::make_tuple(from, to, min_create_date())); auto offset = query.offset; @@ -778,42 +751,39 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API(private_message_plugin, get_inbox) { PLUGIN_API_VALIDATE_ARGS( (std::string, to) - (inbox_query, query) + (message_box_query, query) ); GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); - if (!query.limit) { - query.limit = PRIVATE_DEFAULT_LIMIT; - } - - if (query.start_date == time_point_sec::min()) { - query.start_date = my->db_.head_block_time(); - } - return my->db_.with_weak_read_lock([&]() { - return my->get_inbox(to, query); + return my->get_message_box( + to, query, + [&](const message_object& o) -> bool { + return + (query.select_accounts.empty() || query.select_accounts.count(o.from)) && + (!query.unread_only || o.read_date == time_point_sec::min()); + } + ); }); } DEFINE_API(private_message_plugin, get_outbox) { PLUGIN_API_VALIDATE_ARGS( (std::string, from) - (outbox_query, query) + (message_box_query, query) ); GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); - if (!query.limit) { - query.limit = PRIVATE_DEFAULT_LIMIT; - } - - if (query.start_date == time_point_sec::min()) { - query.start_date = my->db_.head_block_time(); - } - return my->db_.with_weak_read_lock([&]() { - return my->get_outbox(from, query); + return my->get_message_box( + from, query, + [&](const message_object& o) -> bool { + return + (query.select_accounts.empty() || query.select_accounts.count(o.to)) && + (!query.unread_only || o.read_date == time_point_sec::min()); + }); }); } @@ -821,7 +791,7 @@ namespace golos { namespace plugins { namespace private_message { PLUGIN_API_VALIDATE_ARGS( (std::string, from) (std::string, to) - (thread_query, query) + (message_thread_query, query) ); GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); @@ -830,8 +800,8 @@ namespace golos { namespace plugins { namespace private_message { query.limit = PRIVATE_DEFAULT_LIMIT; } - if (query.start_date == time_point_sec::min()) { - query.start_date = my->db_.head_block_time(); + if (query.newest_date == time_point_sec::min()) { + query.newest_date = my->db_.head_block_time(); } return my->db_.with_weak_read_lock([&]() { diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index b22d638b1a..38b8e57f6e 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -121,22 +121,24 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_TEST_MESSAGE("--- Get message "); msg_pack mp; - mp.args = std::vector({fc::variant("bob"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); auto bob_inbox = pm_plugin->get_inbox(mp); - mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); auto bob_outbox = pm_plugin->get_outbox(mp); - mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); auto alice_inbox = pm_plugin->get_inbox(mp); - mp.args = std::vector({fc::variant("alice"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); auto alice_outbox = pm_plugin->get_outbox(mp); - mp.args = std::vector({fc::variant("alice"), fc::variant("bob"), fc::variant(thread_query())}); + mp.args = std::vector( + {fc::variant("alice"), fc::variant("bob"), fc::variant(message_thread_query())}); auto alice_bob_thread = pm_plugin->get_thread(mp); - mp.args = std::vector({fc::variant("bob"), fc::variant("alice"), fc::variant(thread_query())}); + mp.args = std::vector( + {fc::variant("bob"), fc::variant("alice"), fc::variant(message_thread_query())}); auto bob_alice_thread = pm_plugin->get_thread(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 1); @@ -229,10 +231,10 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) jop.json = fc::json::to_string(pop); GOLOS_CHECK_NO_THROW(push_tx_with_ops(trx, alice_private_key, jop)); - mp.args = std::vector({fc::variant("bob"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); bob_inbox = pm_plugin->get_inbox(mp); - mp.args = std::vector({fc::variant("alice"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); alice_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_inbox.size(), 1); @@ -877,15 +879,15 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); - mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); auto alice_inbox = pm_plugin->get_inbox(mp); BOOST_CHECK_EQUAL(alice_inbox.size(), 4); - mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); auto bob_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 1); - mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("sam"), fc::variant(message_box_query())}); auto sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 2); @@ -936,15 +938,15 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(bob_alice_contact.size.total_inbox_messages, 0); BOOST_CHECK_EQUAL(bob_alice_contact.size.unread_inbox_messages, 0); - mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); alice_inbox = pm_plugin->get_inbox(mp); BOOST_CHECK_EQUAL(alice_inbox.size(), 4); - mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); bob_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 0); - mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("sam"), fc::variant(message_box_query())}); sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 2); @@ -990,15 +992,15 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(sam_alice_contact.size.total_inbox_messages, 0); BOOST_CHECK_EQUAL(sam_alice_contact.size.unread_inbox_messages, 0); - mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); alice_inbox = pm_plugin->get_inbox(mp); BOOST_CHECK_EQUAL(alice_inbox.size(), 4); - mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); bob_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 0); - mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("sam"), fc::variant(message_box_query())}); sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 0); @@ -1070,15 +1072,15 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) BOOST_CHECK_EQUAL(bob_contacts_size.size[pinned].total_contacts, 1); BOOST_CHECK_EQUAL(bob_contacts_size.size[ignored].total_contacts, 0); - mp.args = std::vector({fc::variant("alice"), fc::variant(inbox_query())}); + mp.args = std::vector({fc::variant("alice"), fc::variant(message_box_query())}); alice_inbox = pm_plugin->get_inbox(mp); BOOST_CHECK_EQUAL(alice_inbox.size(), 0); - mp.args = std::vector({fc::variant("bob"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); bob_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 0); - mp.args = std::vector({fc::variant("sam"), fc::variant(outbox_query())}); + mp.args = std::vector({fc::variant("sam"), fc::variant(message_box_query())}); sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 0); } From 7baa4f455b23d85bea2a4658f8c8725ccaafbdc4 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 17:23:57 +0700 Subject: [PATCH 213/250] Fix error throwing in private messages. #807 --- .../private_message_plugin.cpp | 58 +++++++++---------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 8dfbd8571b..9d51a2aa28 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -265,30 +265,28 @@ namespace golos { namespace plugins { namespace private_message { auto& cfg_idx = d.get_index().indices().get(); auto cfg_itr = cfg_idx.find(pm.to); - GOLOS_CHECK_OP_PARAM(pm, to, { - d.get_account(pm.to); - GOLOS_CHECK_LOGIC(contact_itr == contact_idx.end() || contact_itr->type != ignored, - logic_errors::sender_in_ignore_list, - "Sender is in the ignore list of recipient"); - GOLOS_CHECK_LOGIC( - (cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_unknown_contact) || - (contact_itr != contact_idx.end() && contact_itr->type == pinned), - logic_errors::recepient_ignores_messages_from_unknown_contact, - "Recipient accepts messages only from his contact list"); - }); + d.get_account(pm.to); + + GOLOS_CHECK_LOGIC(contact_itr == contact_idx.end() || contact_itr->type != ignored, + logic_errors::sender_in_ignore_list, + "Sender is in the ignore list of recipient"); + + GOLOS_CHECK_LOGIC( + (cfg_itr == cfg_idx.end() || !cfg_itr->ignore_messages_from_unknown_contact) || + (contact_itr != contact_idx.end() && contact_itr->type == pinned), + logic_errors::recepient_ignores_messages_from_unknown_contact, + "Recipient accepts messages only from his contact list"); auto& id_idx = d.get_index().indices().get(); auto id_itr = id_idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); - GOLOS_CHECK_OP_PARAM(pm, nonce, { - if (pm.update && id_itr == id_idx.end()) { - GOLOS_THROW_MISSING_OBJECT("private_message", - fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); - } else if (!pm.update && id_itr != id_idx.end()){ - GOLOS_THROW_OBJECT_ALREADY_EXIST("private_message", - fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); - } - }); + if (pm.update && id_itr == id_idx.end()) { + GOLOS_THROW_MISSING_OBJECT("private_message", + fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + } else if (!pm.update && id_itr != id_idx.end()){ + GOLOS_THROW_OBJECT_ALREADY_EXIST("private_message", + fc::mutable_variant_object()("from", pm.from)("to", pm.to)("nonce", pm.nonce)); + } auto now = d.head_block_time(); @@ -599,20 +597,16 @@ namespace golos { namespace plugins { namespace private_message { auto& contact_idx = d.get_index().indices().get(); auto contact_itr = contact_idx.find(std::make_tuple(pc.owner, pc.contact)); - GOLOS_CHECK_OP_PARAM(pc, contact, { - d.get_account(pc.contact); + d.get_account(pc.contact); - if (d.is_producing()) { - GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pc.type != unknown, - logic_errors::add_unknown_contact, - "Can't add unknown contact"); + GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr || pc.type != unknown, + logic_errors::add_unknown_contact, + "Can't add unknown contact"); - std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); - GOLOS_CHECK_LOGIC(contact_itr->type != pc.type || pc.json_metadata != json_metadata, - logic_errors::contact_has_same_type, - "Contact has the same type"); - } - }); + std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); + GOLOS_CHECK_LOGIC(contact_itr->type != pc.type || pc.json_metadata != json_metadata, + logic_errors::contact_has_same_type, + "Contact has the same type"); auto& owner_idx = d.get_index().indices().get(); auto dst_itr = owner_idx.find(std::make_tuple(pc.owner, pc.type)); From e52a58f67e17f598a2d671113bea12332334f91a Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 17:42:52 +0700 Subject: [PATCH 214/250] Extend delete private messages. #807 --- .../wallet/include/golos/wallet/wallet.hpp | 40 ++++++++++-- libraries/wallet/wallet.cpp | 64 ++++++++++++++++++- 2 files changed, 96 insertions(+), 8 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 71f08890cb..453fc4581e 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1237,7 +1237,7 @@ namespace golos { namespace wallet { const message_body& message, bool broadcast); /** - * Delete encrypted private message + * Delete encrypted private message from inbox * * @param from account from which you send message * @param to account to which you send message @@ -1245,11 +1245,11 @@ namespace golos { namespace wallet { * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ - annotated_signed_transaction delete_private_message( + annotated_signed_transaction delete_inbox_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast); /** - * Delete encrypted private messages by date range + * Delete encrypted private messages from inbox by date range * * @param from account from which you send message * @param to account to which you send message @@ -1258,7 +1258,33 @@ namespace golos { namespace wallet { * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ - annotated_signed_transaction delete_private_messages( + annotated_signed_transaction delete_inbox_private_messages( + const std::string& from, const std::string& to, + const std::string& start_date, const std::string& stop_date, bool broadcast); + + /** + * Delete encrypted private message from outbox + * + * @param from account from which you send message + * @param to account to which you send message + * @param nonce of sended message + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction delete_outbox_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast); + + /** + * Delete encrypted private messages from outbox by date range + * + * @param from account from which you send message + * @param to account to which you send message + * @param start_date begin of date range + * @param stop_date begin of date range + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + annotated_signed_transaction delete_outbox_private_messages( const std::string& from, const std::string& to, const std::string& start_date, const std::string& stop_date, bool broadcast); @@ -1413,8 +1439,10 @@ FC_API( golos::wallet::wallet_api, (add_private_contact) (send_private_message) (edit_private_message) - (delete_private_message) - (delete_private_messages) + (delete_inbox_private_message) + (delete_inbox_private_messages) + (delete_outbox_private_message) + (delete_outbox_private_messages) (mark_private_message) (mark_private_messages) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 90ac665923..fbeb2d61cf 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2815,13 +2815,72 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->send_private_message(from, to, nonce, false, message, broadcast); } - annotated_signed_transaction wallet_api::delete_private_message( + annotated_signed_transaction wallet_api::delete_inbox_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast ) { WALLET_CHECK_UNLOCKED(); GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); private_delete_message_operation op; + op.requester = to; + op.from = from; + op.to = to; + op.nonce = nonce; + op.start_date = time_point_sec::min(); + op.stop_date = time_point_sec::min(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + + annotated_signed_transaction wallet_api::delete_inbox_private_messages( + const std::string& from, const std::string& to, + const std::string& start_date, const std::string& stop_date, + bool broadcast + ) { + WALLET_CHECK_UNLOCKED(); + + private_delete_message_operation op; + op.requester = to; + op.from = from; + op.to = to; + op.nonce = 0; + op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); + op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return my->sign_transaction(trx, broadcast); + } + + + annotated_signed_transaction wallet_api::delete_outbox_private_message( + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast + ) { + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); + + private_delete_message_operation op; + op.requester = from; op.from = from; op.to = to; op.nonce = nonce; @@ -2842,7 +2901,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction(trx, broadcast); } - annotated_signed_transaction wallet_api::delete_private_messages( + annotated_signed_transaction wallet_api::delete_outbox_private_messages( const std::string& from, const std::string& to, const std::string& start_date, const std::string& stop_date, bool broadcast @@ -2850,6 +2909,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st WALLET_CHECK_UNLOCKED(); private_delete_message_operation op; + op.requester = from; op.from = from; op.to = to; op.nonce = 0; From dcc0e4c1443853cd16753b1bd72fbc9905d51373 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 17:55:27 +0700 Subject: [PATCH 215/250] Simplify delete private messages in cli_wallet. #807 --- libraries/wallet/wallet.cpp | 154 +++++++++++++++--------------------- 1 file changed, 63 insertions(+), 91 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index fbeb2d61cf..57cd78a2a2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1153,6 +1153,65 @@ namespace golos { namespace wallet { return sign_transaction(trx, broadcast); } + annotated_signed_transaction delete_private_message( + const std::string& requester, + const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast + ) { + WALLET_CHECK_UNLOCKED(); + GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); + + private_delete_message_operation op; + op.requester = requester; + op.from = from; + op.to = to; + op.nonce = nonce; + op.start_date = time_point_sec::min(); + op.stop_date = time_point_sec::min(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return sign_transaction(trx, broadcast); + } + + annotated_signed_transaction delete_private_messages( + const std::string& requester, + const std::string& from, const std::string& to, + const std::string& start_date, const std::string& stop_date, + bool broadcast + ) { + WALLET_CHECK_UNLOCKED(); + + private_delete_message_operation op; + op.requester = requester; + op.from = from; + op.to = to; + op.nonce = 0; + op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); + op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); + + private_message_plugin_operation pop = op; + + custom_json_operation jop; + jop.id = "private_message"; + jop.json = fc::json::to_string(pop); + jop.required_posting_auths.insert(to); + + signed_transaction trx; + trx.operations.push_back(jop); + trx.validate(); + + return sign_transaction(trx, broadcast); + } + string _wallet_filename; wallet_data _wallet; golos::protocol::chain_id_type steem_chain_id; @@ -2818,29 +2877,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st annotated_signed_transaction wallet_api::delete_inbox_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast ) { - WALLET_CHECK_UNLOCKED(); - GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); - - private_delete_message_operation op; - op.requester = to; - op.from = from; - op.to = to; - op.nonce = nonce; - op.start_date = time_point_sec::min(); - op.stop_date = time_point_sec::min(); - - private_message_plugin_operation pop = op; - - custom_json_operation jop; - jop.id = "private_message"; - jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(to); - - signed_transaction trx; - trx.operations.push_back(jop); - trx.validate(); - - return my->sign_transaction(trx, broadcast); + return my->delete_private_message(to, from, to, nonce, broadcast); } annotated_signed_transaction wallet_api::delete_inbox_private_messages( @@ -2848,57 +2885,13 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const std::string& start_date, const std::string& stop_date, bool broadcast ) { - WALLET_CHECK_UNLOCKED(); - - private_delete_message_operation op; - op.requester = to; - op.from = from; - op.to = to; - op.nonce = 0; - op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); - op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); - - private_message_plugin_operation pop = op; - - custom_json_operation jop; - jop.id = "private_message"; - jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(to); - - signed_transaction trx; - trx.operations.push_back(jop); - trx.validate(); - - return my->sign_transaction(trx, broadcast); + return my->delete_private_messages(to, from, to, start_date, stop_date, broadcast); } - annotated_signed_transaction wallet_api::delete_outbox_private_message( const std::string& from, const std::string& to, const uint64_t nonce, bool broadcast ) { - WALLET_CHECK_UNLOCKED(); - GOLOS_CHECK_PARAM(nonce, GOLOS_CHECK_VALUE(nonce != 0, "You should specify nonce of deleted message")); - - private_delete_message_operation op; - op.requester = from; - op.from = from; - op.to = to; - op.nonce = nonce; - op.start_date = time_point_sec::min(); - op.stop_date = time_point_sec::min(); - - private_message_plugin_operation pop = op; - - custom_json_operation jop; - jop.id = "private_message"; - jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(from); - - signed_transaction trx; - trx.operations.push_back(jop); - trx.validate(); - - return my->sign_transaction(trx, broadcast); + return my->delete_private_message(from, from, to, nonce, broadcast); } annotated_signed_transaction wallet_api::delete_outbox_private_messages( @@ -2906,28 +2899,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const std::string& start_date, const std::string& stop_date, bool broadcast ) { - WALLET_CHECK_UNLOCKED(); - - private_delete_message_operation op; - op.requester = from; - op.from = from; - op.to = to; - op.nonce = 0; - op.start_date = time_converter(start_date, time_point::now(), time_point_sec::min()).time(); - op.stop_date = time_converter(stop_date, time_point::now(), time_point::now()).time(); - - private_message_plugin_operation pop = op; - - custom_json_operation jop; - jop.id = "private_message"; - jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(from); - - signed_transaction trx; - trx.operations.push_back(jop); - trx.validate(); - - return my->sign_transaction(trx, broadcast); + return my->delete_private_messages(from, from, to, start_date, stop_date, broadcast); } annotated_signed_transaction wallet_api::mark_private_message( From ff84a03872e5f91b0ba1d28e7b77f4c173b1ea09 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 20:04:08 +0700 Subject: [PATCH 216/250] Add checking of private message thread on delete. #807 --- tests/plugin_tests/private_message.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 38b8e57f6e..2c9ce79c59 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -883,10 +883,18 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) auto alice_inbox = pm_plugin->get_inbox(mp); BOOST_CHECK_EQUAL(alice_inbox.size(), 4); + mp.args = std::vector({fc::variant("alice"), fc::variant("bob"), fc::variant(message_thread_query())}); + auto alice_bob_thread = pm_plugin->get_thread(mp); + BOOST_CHECK_EQUAL(alice_bob_thread.size(), 2); + mp.args = std::vector({fc::variant("bob"), fc::variant(message_box_query())}); auto bob_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(bob_outbox.size(), 1); + mp.args = std::vector({fc::variant("bob"), fc::variant("alice"), fc::variant(message_thread_query())}); + auto bob_alice_thread = pm_plugin->get_thread(mp); + BOOST_CHECK_EQUAL(bob_alice_thread.size(), 1); + mp.args = std::vector({fc::variant("sam"), fc::variant(message_box_query())}); auto sam_outbox = pm_plugin->get_outbox(mp); BOOST_CHECK_EQUAL(sam_outbox.size(), 2); From 55f1e12754719f9dcc9133f82277ec7dd2d1fffe Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Wed, 1 Aug 2018 20:11:42 +0700 Subject: [PATCH 217/250] Fix error messages in private messages. #807 --- .../private_message_exceptions.hpp | 4 ---- .../private_message_operations.cpp | 18 +++++++++--------- .../private_message/private_message_plugin.cpp | 3 +-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index 789dab79b5..6c95039b15 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -15,8 +15,6 @@ namespace golos { namespace plugins { namespace private_message { add_unknown_contact, contact_has_same_type, no_unread_messages, - invalid_range, - invalid_size, }; }; @@ -38,6 +36,4 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (add_unknown_contact) (contact_has_same_type) (no_unread_messages) - (invalid_range) - (invalid_size) ); \ No newline at end of file diff --git a/plugins/private_message/private_message_operations.cpp b/plugins/private_message/private_message_operations.cpp index aca21289ec..a226e8828b 100644 --- a/plugins/private_message/private_message_operations.cpp +++ b/plugins/private_message/private_message_operations.cpp @@ -42,17 +42,17 @@ namespace golos { namespace plugins { namespace private_message { "You cannot write to yourself"); GOLOS_CHECK_PARAM(to_memo_key, { - GOLOS_CHECK_VALUE(to_memo_key != public_key_type(), "to_key can't be empty"); + GOLOS_CHECK_VALUE(to_memo_key != public_key_type(), "`to_key` can't be empty"); }); GOLOS_CHECK_PARAM(from_memo_key, { - GOLOS_CHECK_VALUE(from_memo_key != public_key_type(), "From_key can't be empty"); + GOLOS_CHECK_VALUE(from_memo_key != public_key_type(), "`from_key` can't be empty"); }); GOLOS_CHECK_LOGIC( from_memo_key != to_memo_key, logic_errors::from_and_to_memo_keys_must_be_different, - "from_key can't be equal to to_key"); + "`from_key` can't be equal to `to_key`"); GOLOS_CHECK_PARAM(nonce, { GOLOS_CHECK_VALUE(nonce != 0, "Nonce can't be zero"); @@ -86,12 +86,12 @@ namespace golos { namespace plugins { namespace private_message { validate_account_name(requester); if (to.size() || from.size()) { GOLOS_CHECK_VALUE(requester == to || requester == from, - "Requester can't delete messages only from his inbox/outbox"); + "`requester` can delete messages only from his inbox/outbox"); } }); GOLOS_CHECK_PARAM(start_date, { - GOLOS_CHECK_VALUE(start_date <= stop_date, "start_date can't be greater then to_time"); + GOLOS_CHECK_VALUE(start_date <= stop_date, "`start_date` can't be greater then to_time"); }); GOLOS_CHECK_PARAM(nonce, { @@ -119,14 +119,14 @@ namespace golos { namespace plugins { namespace private_message { }); GOLOS_CHECK_PARAM(start_date, { - GOLOS_CHECK_VALUE(start_date <= stop_date, "start_date can't be greater then to_time"); + GOLOS_CHECK_VALUE(start_date <= stop_date, "`start_date` can't be greater then `stop_date`"); }); GOLOS_CHECK_PARAM(nonce, { if (nonce != 0) { - GOLOS_CHECK_VALUE(to.size(), "to and nonce should be set both"); - GOLOS_CHECK_VALUE(start_date == time_point_sec::min(), "nonce and start_date can't be used together"); - GOLOS_CHECK_VALUE(stop_date == time_point_sec::min(), "nonce and stop_date can't be used together"); + GOLOS_CHECK_VALUE(to.size(), "Non-zero 'nonce' requires 'to' to be set too"); + GOLOS_CHECK_VALUE(start_date == time_point_sec::min(), "Non-zero `nonce` can't be used with `start_date`"); + GOLOS_CHECK_VALUE(stop_date == time_point_sec::min(), "Non-zero `nonce` can't be used with `stop_date`"); } }); } diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 9d51a2aa28..f990c461dc 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -452,8 +452,7 @@ namespace golos { namespace plugins { namespace private_message { auto contact_itr = contact_idx.find(stat_info.first); auto size_itr = size_idx.find(owner); - GOLOS_CHECK_LOGIC(contact_idx.end() != contact_itr && size_idx.end() != size_itr, - logic_errors::invalid_size, "Invalid size"); + FC_ASSERT(contact_idx.end() != contact_itr && size_idx.end() != size_itr, "Invalid size"); if (!contact_action(*contact_itr, *size_itr, size)) { db.modify(*contact_itr, [&](auto& pco) { From b3d4c6fad36e226fc338659326dbe0527bbe2750 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Sat, 21 Jul 2018 18:50:03 +0300 Subject: [PATCH 218/250] Add comment_reward_object to social_network #829 --- libraries/api/discussion_helper.cpp | 81 +++++++++++- .../include/golos/api/comment_api_object.hpp | 14 +- .../api/include/golos/api/discussion.hpp | 16 ++- libraries/chain/database.cpp | 36 +----- .../include/golos/chain/comment_object.hpp | 7 - .../chain/include/golos/chain/database.hpp | 2 - plugins/chain/plugin.cpp | 3 +- plugins/mongo_db/mongo_db_state.cpp | 20 ++- .../social_network/social_network_types.hpp | 42 +++++- plugins/social_network/social_network.cpp | 120 +++++++++++++++++- tests/common/comment_reward.hpp | 4 +- tests/common/helpers.hpp | 4 + tests/tests/operation_time_tests.cpp | 58 +++++++-- 13 files changed, 333 insertions(+), 74 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index e34856a7b3..7d14d5b4d3 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -39,6 +39,8 @@ namespace golos { namespace api { const std::string& author, const std::string& permlink, uint32_t limit ) const ; + share_type get_curator_rewards_claim(const discussion& d, share_type max_rewards) const; + void set_pending_payout(discussion& d) const; void set_url(discussion& d) const; @@ -102,9 +104,6 @@ namespace golos { namespace api { d.max_cashout_time = o.max_cashout_time; d.total_vote_weight = o.total_vote_weight; d.reward_weight = o.reward_weight; - d.total_payout_value = o.total_payout_value; - d.curator_payout_value = o.curator_payout_value; - d.author_rewards = o.author_rewards; d.net_votes = o.net_votes; d.mode = o.mode; d.root_comment = o.root_comment; @@ -175,6 +174,32 @@ namespace golos { namespace api { pimpl->select_active_votes(result, total_count, author, permlink, limit); } + share_type discussion_helper::impl::get_curator_rewards_claim(const discussion& d, share_type max_rewards) const { + share_type total_claim = max_rewards; + auto& db = database(); + try { + uint128_t total_weight(d.total_vote_weight); + + if (d.allow_curation_rewards) { + if (d.total_vote_weight > 0) { + const auto &cvidx = db.get_index().indices().get(); + for (auto itr = cvidx.lower_bound(d.id); itr != cvidx.end() && itr->comment == d.id; ++itr) { + auto claim = ((max_rewards.value * uint128_t(itr->weight)) / total_weight).to_uint64(); + if (claim > 0) { // min_amt is non-zero satoshis + total_claim += claim; + } else { + break; + } + } + } else { + total_claim = 0; + } + } + + return total_claim; + } FC_CAPTURE_AND_RETHROW() + } + // // set_pending_payout void discussion_helper::impl::set_pending_payout(discussion& d) const { @@ -185,8 +210,9 @@ namespace golos { namespace api { const auto& props = db.get_dynamic_global_properties(); const auto& hist = db.get_feed_history(); asset pot = props.total_reward_fund_steem; - if (!hist.current_median_history.is_null()) { - pot = pot * hist.current_median_history; + + if (hist.current_median_history.is_null()) { + return; } u256 total_r2 = to256(props.total_reward_shares2); @@ -195,15 +221,56 @@ namespace golos { namespace api { auto vshares = db.calculate_vshares(d.net_rshares.value > 0 ? d.net_rshares.value : 0); u256 r2 = to256(vshares); //to256(abs_net_rshares); + r2 = (r2 * d.reward_weight) / STEEMIT_100_PERCENT; r2 *= pot.amount.value; r2 /= total_r2; + uint64_t payout = static_cast(r2); + + payout = std::min(payout, uint64_t(d.max_accepted_payout.amount.value)); + + uint128_t reward_tokens = uint128_t(payout); + + share_type curation_tokens = ((reward_tokens * db.get_curation_rewards_percent()) + / STEEMIT_100_PERCENT).to_uint64(); + auto crs_claim = get_curator_rewards_claim(d, curation_tokens); + share_type author_tokens = reward_tokens.to_uint64() - crs_claim; + if (d.allow_curation_rewards) { + d.pending_curator_payout_value = db.to_sbd(asset(crs_claim, STEEM_SYMBOL)); + d.pending_curator_payout_gests_value = asset(crs_claim, STEEM_SYMBOL) * props.get_vesting_share_price(); + d.pending_payout_value += d.pending_curator_payout_value; + } + + uint32_t benefactor_weights = 0; + for (auto &b : d.beneficiaries) { + benefactor_weights += b.weight; + } + if (benefactor_weights != 0) { + auto total_beneficiary = (author_tokens * benefactor_weights) / STEEMIT_100_PERCENT; + author_tokens -= total_beneficiary; + d.pending_benefactor_payout_value = db.to_sbd(asset(total_beneficiary, STEEM_SYMBOL)); + d.pending_benefactor_payout_gests_value = (asset(total_beneficiary, STEEM_SYMBOL) * props.get_vesting_share_price()); + d.pending_payout_value += d.pending_benefactor_payout_value; + } + + auto sbd_steem = (author_tokens * d.percent_steem_dollars) / (2 * STEEMIT_100_PERCENT); + auto vesting_steem = asset(author_tokens - sbd_steem, STEEM_SYMBOL); + d.pending_author_payout_gests_value = vesting_steem * props.get_vesting_share_price(); + auto to_sbd = asset((props.sbd_print_rate * sbd_steem) / STEEMIT_100_PERCENT, STEEM_SYMBOL); + auto to_steem = asset(sbd_steem, STEEM_SYMBOL) - to_sbd; + + d.pending_author_payout_golos_value = to_steem; + d.pending_author_payout_gbg_value = db.to_sbd(to_sbd); + d.pending_author_payout_value = d.pending_author_payout_gbg_value + db.to_sbd(to_steem + vesting_steem); + d.pending_payout_value += d.pending_author_payout_value; + + // End of main calculation + u256 tpp = to256(d.children_rshares2); tpp *= pot.amount.value; tpp /= total_r2; - d.pending_payout_value = asset(static_cast(r2), pot.symbol); - d.total_pending_payout_value = asset(static_cast(tpp), pot.symbol); + d.total_pending_payout_value = db.to_sbd(asset(static_cast(tpp), pot.symbol)); } fill_reputation_(db, d.author, d.author_reputation); diff --git a/libraries/api/include/golos/api/comment_api_object.hpp b/libraries/api/include/golos/api/comment_api_object.hpp index acd8b6c752..10d0bc2336 100644 --- a/libraries/api/include/golos/api/comment_api_object.hpp +++ b/libraries/api/include/golos/api/comment_api_object.hpp @@ -8,6 +8,7 @@ namespace golos { namespace api { using namespace golos::chain; + using namespace golos::protocol; struct comment_api_object { comment_object::id_type id; @@ -44,10 +45,16 @@ namespace golos { namespace api { uint16_t reward_weight = 0; - protocol::asset total_payout_value; - protocol::asset curator_payout_value; + asset total_payout_value = asset(0, SBD_SYMBOL); + asset beneficiary_payout_value = asset(0, SBD_SYMBOL); + asset beneficiary_gests_payout_value = asset(0, VESTS_SYMBOL); + asset curator_payout_value = asset(0, SBD_SYMBOL); + asset curator_gests_payout_value = asset(0, VESTS_SYMBOL); share_type author_rewards; + asset author_gbg_payout_value = asset(0, SBD_SYMBOL); + asset author_golos_payout_value = asset(0, STEEM_SYMBOL); + asset author_gests_payout_value = asset(0, VESTS_SYMBOL); int32_t net_votes = 0; @@ -73,7 +80,8 @@ FC_REFLECT( (id)(author)(permlink)(parent_author)(parent_permlink)(category)(title)(body)(json_metadata)(last_update) (created)(active)(last_payout)(depth)(children)(children_rshares2)(net_rshares)(abs_rshares) (vote_rshares)(children_abs_rshares)(cashout_time)(max_cashout_time)(total_vote_weight) - (reward_weight)(total_payout_value)(curator_payout_value)(author_rewards)(net_votes) + (reward_weight)(total_payout_value)(beneficiary_payout_value)(beneficiary_gests_payout_value)(curator_payout_value)(curator_gests_payout_value) + (author_rewards)(author_gbg_payout_value)(author_golos_payout_value)(author_gests_payout_value)(net_votes) (mode)(root_comment)(root_title)(max_accepted_payout)(percent_steem_dollars)(allow_replies)(allow_votes) (allow_curation_rewards)(beneficiaries)) diff --git a/libraries/api/include/golos/api/discussion.hpp b/libraries/api/include/golos/api/discussion.hpp index c62534084a..583ffe87e0 100644 --- a/libraries/api/include/golos/api/discussion.hpp +++ b/libraries/api/include/golos/api/discussion.hpp @@ -16,8 +16,18 @@ namespace golos { namespace api { } string url; /// /category/@rootauthor/root_permlink#author/permlink + + asset pending_author_payout_value = asset(0, SBD_SYMBOL); + asset pending_author_payout_gbg_value = asset(0, SBD_SYMBOL); + asset pending_author_payout_gests_value = asset(0, VESTS_SYMBOL); + asset pending_author_payout_golos_value = asset(0, STEEM_SYMBOL); + asset pending_benefactor_payout_value = asset(0, SBD_SYMBOL); + asset pending_benefactor_payout_gests_value = asset(0, VESTS_SYMBOL); + asset pending_curator_payout_value = asset(0, SBD_SYMBOL); + asset pending_curator_payout_gests_value = asset(0, VESTS_SYMBOL); asset pending_payout_value = asset(0, SBD_SYMBOL); ///< sbd asset total_pending_payout_value = asset(0, SBD_SYMBOL); ///< sbd including replies + std::vector active_votes; uint32_t active_votes_count = 0; std::vector replies; ///< author/slug mapping @@ -34,5 +44,9 @@ namespace golos { namespace api { } } // golos::api FC_REFLECT_DERIVED( (golos::api::discussion), ((golos::api::comment_api_object)), - (url)(pending_payout_value)(total_pending_payout_value)(active_votes)(active_votes_count)(replies) + (url)(pending_author_payout_value)(pending_author_payout_gbg_value) + (pending_author_payout_gests_value)(pending_author_payout_golos_value) + (pending_benefactor_payout_value)(pending_benefactor_payout_gests_value) + (pending_curator_payout_value)(pending_curator_payout_gests_value) + (pending_payout_value)(total_pending_payout_value)(active_votes)(active_votes_count)(replies) (author_reputation)(promoted)(body_length)(reblogged_by)(first_reblogged_by)(first_reblogged_on)) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index dd9cf5c494..1464d70f0c 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2235,22 +2235,6 @@ namespace golos { namespace chain { } } - void database::adjust_total_payout( - const comment_object &cur, - const asset &sbd_created, - const asset &curator_sbd_value, - const asset &beneficiary_value - ) { - modify(cur, [&](comment_object &c) { - if (c.total_payout_value.symbol == sbd_created.symbol) { - c.total_payout_value += sbd_created; - c.beneficiary_payout_value += beneficiary_value; - c.curator_payout_value += curator_sbd_value; - } - }); - /// TODO: potentially modify author's total payout numbers as well - } - /** * This method will iterate through all comment_vote_objects and give them * (max_rewards * weight) / c.total_vote_weight. @@ -2273,6 +2257,7 @@ namespace golos { namespace chain { if (claim > 0) // min_amt is non-zero satoshis { unclaimed_rewards -= claim; + const auto &voter = get(itr->voter); auto reward = create_vesting(voter, asset(claim, STEEM_SYMBOL)); @@ -2283,6 +2268,8 @@ namespace golos { namespace chain { a.curation_rewards += claim; }); #endif + } else { + break; } ++itr; } @@ -2339,19 +2326,6 @@ namespace golos { namespace chain { auto vest_created = create_vesting(author, vesting_steem); auto sbd_payout = create_sbd(author, sbd_steem); - adjust_total_payout( - comment, - sbd_payout.first + to_sbd(sbd_payout.second + asset(vesting_steem, STEEM_SYMBOL)), - to_sbd(asset(curation_tokens, STEEM_SYMBOL)), - to_sbd(asset(total_beneficiary, STEEM_SYMBOL)) - ); - - /*if( sbd_created.symbol == SBD_SYMBOL ) - adjust_total_payout( comment, sbd_created + to_sbd( asset( vesting_steem, STEEM_SYMBOL ) ), to_sbd( asset( reward_tokens.to_uint64() - author_tokens, STEEM_SYMBOL ) ) ); - else - adjust_total_payout( comment, to_sbd( asset( vesting_steem + sbd_steem, STEEM_SYMBOL ) ), to_sbd( asset( reward_tokens.to_uint64() - author_tokens, STEEM_SYMBOL ) ) ); - */ - // stats only.. TODO: Move to plugin... total_payout = to_sbd(asset(reward_tokens.to_uint64(), STEEM_SYMBOL)); @@ -2359,10 +2333,6 @@ namespace golos { namespace chain { push_virtual_operation(comment_reward_operation(comment.author, to_string(comment.permlink), total_payout)); #ifndef IS_LOW_MEM - modify(comment, [&](comment_object &c) { - c.author_rewards += author_tokens; - }); - modify(get_account(comment.author), [&](account_object &a) { a.posting_rewards += author_tokens; }); diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index 25c9dd931d..24660d3aba 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -85,13 +85,6 @@ namespace golos { uint16_t reward_weight = 0; - /** tracks the total payout this comment has received over time, measured in SBD */ - asset total_payout_value = asset(0, SBD_SYMBOL); - asset curator_payout_value = asset(0, SBD_SYMBOL); - asset beneficiary_payout_value = asset(0, SBD_SYMBOL); - - share_type author_rewards = 0; - int32_t net_votes = 0; id_type root_comment; diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 743519ad09..0ebc031fc3 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -371,8 +371,6 @@ namespace golos { namespace chain { asset create_vesting(const account_object &to_account, asset steem); - void adjust_total_payout(const comment_object &a, const asset &sbd, const asset &curator_sbd_value, const asset& beneficiary_value); - void update_witness_schedule(); void adjust_liquidity_reward(const account_object &owner, const asset &volume, bool is_bid); diff --git a/plugins/chain/plugin.cpp b/plugins/chain/plugin.cpp index cd592b2953..a4501e4bdd 100644 --- a/plugins/chain/plugin.cpp +++ b/plugins/chain/plugin.cpp @@ -257,9 +257,10 @@ namespace golos { namespace plugins { namespace chain { "store-account-metadata-list", bpo::value(), "names of accounts to store metadata" ) ( - "store-memo-in-savings-withdraws", bpo::bool_switch()->default_value(true), + "store-memo-in-savings-withdraws", bpo::value()->default_value(true), "store memo for all savings withdraws" ); + // Do not use bool_switch() in cfg! cli.add_options() ( "replay-blockchain", bpo::bool_switch()->default_value(false), diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index c40f880e45..dcd4dcbfb6 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -75,14 +75,11 @@ namespace mongo_db { format_value(body, "allow_curation_rewards", comment.allow_curation_rewards); format_value(body, "allow_replies", comment.allow_replies); format_value(body, "allow_votes", comment.allow_votes); - format_value(body, "author_rewards", comment.author_rewards); - format_value(body, "beneficiary_payout", comment.beneficiary_payout_value); format_value(body, "cashout_time", comment.cashout_time); format_value(body, "children", comment.children); format_value(body, "children_abs_rshares", comment.children_abs_rshares); format_value(body, "children_rshares2", comment.children_rshares2); format_value(body, "created", comment.created); - format_value(body, "curator_payout", comment.curator_payout_value); format_value(body, "depth", comment.depth); format_value(body, "last_payout", comment.last_payout); format_value(body, "max_accepted_payout", comment.max_accepted_payout); @@ -93,7 +90,6 @@ namespace mongo_db { format_value(body, "parent_permlink", comment.parent_permlink); format_value(body, "percent_steem_dollars", comment.percent_steem_dollars); format_value(body, "reward_weight", comment.reward_weight); - format_value(body, "total_payout", comment.total_payout_value); format_value(body, "total_vote_weight", comment.total_vote_weight); format_value(body, "vote_rshares", comment.vote_rshares); @@ -145,6 +141,22 @@ namespace mongo_db { } } + if (db_.has_index()) { + const auto& cr_idx = db_.get_index().indices().get(); + auto cr_itr = cr_idx.find(comment.id); + if (cr_itr != cr_idx.end()) { + format_value(body, "author_rewards", cr_itr->author_rewards); + format_value(body, "author_gbg_payout", cr_itr->author_gbg_payout_value); + format_value(body, "author_golos_payout", cr_itr->author_golos_payout_value); + format_value(body, "author_gests_payout", cr_itr->author_gests_payout_value); + format_value(body, "beneficiary_payout", cr_itr->beneficiary_payout_value); + format_value(body, "beneficiary_gests_payout", cr_itr->beneficiary_gests_payout_value); + format_value(body, "curator_payout", cr_itr->curator_payout_value); + format_value(body, "curator_gests_payout", cr_itr->curator_gests_payout_value); + format_value(body, "total_payout", cr_itr->total_payout_value); + } + } + std::string category, root_oid; if (comment.parent_author == STEEMIT_ROOT_POST_PARENT) { category = to_string(comment.parent_permlink); diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp index 27532eb094..d49ba998da 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp @@ -9,7 +9,8 @@ namespace golos { namespace plugins { namespace social_network { enum social_network_types { comment_content_object_type = (SOCIAL_NETWORK_SPACE_ID << 8), - comment_last_update_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1 + comment_last_update_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 1, + comment_reward_object_type = (SOCIAL_NETWORK_SPACE_ID << 8) + 2 }; @@ -100,6 +101,39 @@ namespace golos { namespace plugins { namespace social_network { >, allocator >; + + class comment_reward_object: public object { + public: + comment_reward_object() = delete; + + template + comment_reward_object(Constructor&& c, allocator a) { + c(*this); + } + + id_type id; + + comment_id_type comment; + asset total_payout_value{0, SBD_SYMBOL}; + share_type author_rewards = 0; + asset author_gbg_payout_value{0, SBD_SYMBOL}; + asset author_golos_payout_value{0, STEEM_SYMBOL}; + asset author_gests_payout_value{0, VESTS_SYMBOL}; + asset beneficiary_payout_value{0, SBD_SYMBOL}; + asset beneficiary_gests_payout_value{0, VESTS_SYMBOL}; + asset curator_payout_value{0, SBD_SYMBOL}; + asset curator_gests_payout_value{0, VESTS_SYMBOL}; + }; + + typedef object_id comment_reward_id_type; + + typedef multi_index_container< + comment_reward_object, + indexed_by< + ordered_unique, member>, + ordered_unique, member>>, + allocator + > comment_reward_index; } } } @@ -110,4 +144,8 @@ CHAINBASE_SET_INDEX_TYPE( CHAINBASE_SET_INDEX_TYPE( golos::plugins::social_network::comment_last_update_object, - golos::plugins::social_network::comment_last_update_index) \ No newline at end of file + golos::plugins::social_network::comment_last_update_index) + +CHAINBASE_SET_INDEX_TYPE( + golos::plugins::social_network::comment_reward_object, + golos::plugins::social_network::comment_reward_index) \ No newline at end of file diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 73d99aa031..8f5e978bc7 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -138,6 +138,13 @@ namespace golos { namespace plugins { namespace social_network { golos::chain::database& db; std::unique_ptr helper; comment_depth_params depth_parameters; + + // variables to temporarily store values through states of operation visitor + asset author_gbg_payout_value{0, SBD_SYMBOL}; // part of author payout + asset author_golos_payout_value{0, STEEM_SYMBOL}; // part of author payout + asset author_gests_payout_value{0, VESTS_SYMBOL}; // part of author payout + asset benef_payout_gests{0, VESTS_SYMBOL}; // GESTS version of benef payout + asset curator_payout_gests{0, VESTS_SYMBOL}; // GESTS version of curator payout }; const comment_content_object& social_network::impl::get_comment_content(const comment_id_type& comment) const { @@ -265,7 +272,7 @@ namespace golos { namespace plugins { namespace social_network { template void operator()(const T& o) const { - } + } /// ignore all other ops void operator()(const golos::protocol::comment_operation& o) const { const auto& comment = db.get_comment(o.author, o.permlink); @@ -338,6 +345,94 @@ namespace golos { namespace plugins { namespace social_network { } } + result_type operator()(const author_reward_operation& op) const { + if (!db.has_index()) { + return; + } + + impl.author_gbg_payout_value += op.sbd_payout; + impl.author_golos_payout_value += op.steem_payout; + impl.author_gests_payout_value += op.vesting_payout; + } + + result_type operator()(const comment_payout_update_operation& op) const { + if (!db.has_index()) { + return; + } + + const auto& comment = db.get_comment(op.author, op.permlink); + + const auto& cprops = db.get_dynamic_global_properties(); + auto vesting_sp = cprops.get_vesting_share_price(); + + // Calculation author rewards value + + auto author_rewards = impl.author_golos_payout_value.amount; + author_rewards += (impl.author_gests_payout_value * vesting_sp).amount; + author_rewards += db.to_steem(impl.author_gbg_payout_value).amount; + + // Converting + + asset total_payout_golos = asset(author_rewards, STEEM_SYMBOL); + asset total_payout_gbg = db.to_sbd(total_payout_golos); + + asset benef_payout_golos = impl.benef_payout_gests * vesting_sp; + asset benef_payout_gbg = db.to_sbd(benef_payout_golos); + + asset curator_payout_golos = impl.curator_payout_gests * vesting_sp; + asset curator_payout_gbg = db.to_sbd(curator_payout_golos); + + const auto& cr_idx = db.get_index().indices().get(); + auto cr_itr = cr_idx.find(comment.id); + if (cr_itr == cr_idx.end()) { + db.create([&](golos::plugins::social_network::comment_reward_object& cr) { + cr.comment = comment.id; + cr.author_rewards = author_rewards; + cr.author_gbg_payout_value = impl.author_gbg_payout_value; + cr.author_golos_payout_value = impl.author_golos_payout_value; + cr.author_gests_payout_value = impl.author_gests_payout_value; + cr.total_payout_value = total_payout_gbg; + cr.beneficiary_payout_value = benef_payout_gbg; + cr.beneficiary_gests_payout_value = impl.benef_payout_gests; + cr.curator_payout_value = curator_payout_gbg; + cr.curator_gests_payout_value = impl.curator_payout_gests; + }); + } else { + db.modify(*cr_itr, [&](comment_reward_object& cr) { + cr.author_rewards += author_rewards; + cr.author_gbg_payout_value += impl.author_gbg_payout_value; + cr.author_golos_payout_value += impl.author_golos_payout_value; + cr.author_gests_payout_value += impl.author_gests_payout_value; + cr.total_payout_value += total_payout_gbg; + cr.beneficiary_payout_value += benef_payout_gbg; + cr.beneficiary_gests_payout_value = impl.benef_payout_gests; + cr.curator_payout_value += curator_payout_gbg; + cr.curator_gests_payout_value += impl.curator_payout_gests; + }); + } + + impl.author_gbg_payout_value.amount = 0; + impl.benef_payout_gests.amount = 0; + impl.curator_payout_gests.amount = 0; + impl.author_golos_payout_value.amount = 0; + impl.author_gests_payout_value.amount = 0; + } + + result_type operator()(const curation_reward_operation& op) const { + if (!db.has_index()) { + return; + } + + impl.curator_payout_gests += op.reward; + } + + result_type operator()(const comment_benefactor_reward_operation& op) const { + if (!db.has_index()) { + return; + } + + impl.benef_payout_gests += op.reward; + } }; void social_network::impl::pre_operation(const operation_notification& o) { try { @@ -446,7 +541,11 @@ namespace golos { namespace plugins { namespace social_network { ) ( "comment-last-update-depth", boost::program_options::value()->default_value(std::numeric_limits::max()), "mode of storing records of comment.active and comment.last_update: 4294967295 = store all, 0 = do not store, N = storing N blocks depth" + ) ( + "store-comment-rewards", boost::program_options::value()->default_value(true), + "store comment rewards" ); + // Do not use bool_switch() in cfg! } void social_network::plugin_initialize(const boost::program_options::variables_map& options) { @@ -468,6 +567,10 @@ namespace golos { namespace plugins { namespace social_network { } } + if (options.at("store-comment-rewards").as()) { + add_plugin_index(db); + } + db.pre_apply_operation.connect([&](const operation_notification &o) { pimpl->pre_operation(o); }); @@ -733,6 +836,21 @@ namespace golos { namespace plugins { namespace social_network { con.last_update = time_point_sec::min(); } } + + if (db.has_index()) { + const auto reward = db.find(co.id); + if (reward != nullptr) { + con.author_rewards = reward->author_rewards; + con.author_gbg_payout_value = reward->author_gbg_payout_value; + con.author_golos_payout_value = reward->author_golos_payout_value; + con.author_gests_payout_value = reward->author_gests_payout_value; + con.total_payout_value = reward->total_payout_value; + con.beneficiary_payout_value = reward->beneficiary_payout_value; + con.beneficiary_gests_payout_value = reward->beneficiary_gests_payout_value; + con.curator_payout_value = reward->curator_payout_value; + con.curator_gests_payout_value = reward->curator_gests_payout_value; + } + } } std::string get_json_metadata(const golos::chain::database& db, const comment_object& c) { diff --git a/tests/common/comment_reward.hpp b/tests/common/comment_reward.hpp index 5135b8260a..056e898814 100644 --- a/tests/common/comment_reward.hpp +++ b/tests/common/comment_reward.hpp @@ -151,7 +151,7 @@ namespace golos { namespace chain { } asset total_payout() const { - return total_payout_; + return sbd_payout_ + db_.to_sbd(vesting_payout_ * db_.get_dynamic_global_properties().get_vesting_share_price()); } private: @@ -218,7 +218,6 @@ namespace golos { namespace chain { auto sbd_payout_value = comment_rewards_ / 2; auto vesting_payout_value = comment_rewards_ - sbd_payout_value; - total_payout_ = db_.to_sbd(asset(sbd_payout_value + vesting_payout_value, STEEM_SYMBOL)); sbd_payout_ = asset(sbd_payout_value, SBD_SYMBOL); vesting_payout_ = fund_.create_vesting(asset(vesting_payout_value, STEEM_SYMBOL)); } @@ -240,7 +239,6 @@ namespace golos { namespace chain { asset sbd_payout_; asset vesting_payout_; - asset total_payout_; }; } } // namespace golos::chain \ No newline at end of file diff --git a/tests/common/helpers.hpp b/tests/common/helpers.hpp index 63a7f77964..67f2adac5e 100644 --- a/tests/common/helpers.hpp +++ b/tests/common/helpers.hpp @@ -39,6 +39,10 @@ BOOST_CHECK_EQUAL(posting_auths, POSTING); \ } +// Check if 2 numeric values are approximately equal +#define APPROX_CHECK_EQUAL(X, Y, DELTA) { \ + BOOST_CHECK(std::abs(X - Y) <= DELTA); \ +} // internals //------------------------------------------------------------- diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 3317bb8e05..1e6ae4ed93 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -14,6 +14,7 @@ #include "database_fixture.hpp" #include "comment_reward.hpp" +#include "helpers.hpp" #include @@ -35,6 +36,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) fund("dave", 5000); vest("dave", 5000); + BOOST_CHECK(db->has_index()); + + const auto& cr_idx = db->get_index().indices().get(); + price exchange_rate(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); set_price_feed(exchange_rate); @@ -106,7 +111,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(gpo.total_reward_shares2 == total_comment_fund.reward_shares()); BOOST_REQUIRE(gpo.total_vesting_shares == total_comment_fund.vesting_shares()); BOOST_REQUIRE(gpo.total_vesting_fund_steem == total_comment_fund.vesting_fund()); - BOOST_REQUIRE(bob_comment.total_payout_value == bob_comment_reward.total_payout()); + auto bob_cr_itr = cr_idx.find(bob_comment.id); + BOOST_CHECK(bob_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(bob_cr_itr->total_payout_value, bob_comment_reward.total_payout()); bob_sbd_balance += bob_comment_reward.sbd_payout(); BOOST_REQUIRE(bob_account.sbd_balance == bob_sbd_balance); @@ -188,6 +195,10 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) fund("dave", 5000); vest("dave", 5000); + BOOST_CHECK(db->has_index()); + + const auto& cr_idx = db->get_index().indices().get(); + price exchange_rate(ASSET("1.000 GOLOS"), ASSET("1.000 GBG")); set_price_feed(exchange_rate); @@ -324,7 +335,9 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) alice_comment_reward.vote_payout(bob_account); BOOST_REQUIRE(bob_comment.net_rshares.value == 0); - BOOST_REQUIRE(bob_comment.total_payout_value == bob_comment_reward.total_payout()); + auto bob_cr_itr = cr_idx.find(bob_comment.id); + BOOST_CHECK(bob_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(bob_cr_itr->total_payout_value, bob_comment_reward.total_payout()); BOOST_REQUIRE(bob_account.sbd_balance == bob_sbd_balance + bob_comment_reward.sbd_payout()); BOOST_REQUIRE(bob_account.vesting_shares == bob_total_vesting); @@ -577,10 +590,22 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(gpo.total_vesting_shares == total_comment_fund.vesting_shares()); BOOST_REQUIRE(gpo.total_vesting_fund_steem == total_comment_fund.vesting_fund()); - BOOST_REQUIRE(alice_comment.total_payout_value == alice_comment_reward.total_payout()); - BOOST_REQUIRE(bob_comment.total_payout_value == bob_comment_reward.total_payout()); - BOOST_REQUIRE(sam_comment.total_payout_value.amount.value == 0); - BOOST_REQUIRE(dave_comment.total_payout_value == dave_comment_reward.total_payout()); + BOOST_REQUIRE(db->has_index()); + + const auto& cr_idx = db->get_index().indices().get(); + + auto alice_cr_itr = cr_idx.find(alice_comment.id); + BOOST_CHECK(alice_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(alice_cr_itr->total_payout_value, alice_comment_reward.total_payout()); + auto bob_cr_itr = cr_idx.find(bob_comment.id); + BOOST_CHECK(bob_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(bob_cr_itr->total_payout_value, bob_comment_reward.total_payout()); + auto sam_cr_itr = cr_idx.find(sam_comment.id); + BOOST_CHECK(sam_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(sam_cr_itr->total_payout_value.amount.value, 0); + auto dave_cr_itr = cr_idx.find(dave_comment.id); + BOOST_CHECK(dave_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(dave_cr_itr->total_payout_value, dave_comment_reward.total_payout()); auto ops = get_last_operations(9); @@ -752,7 +777,13 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(gpo.total_vesting_shares == total_comment_fund.vesting_shares()); BOOST_REQUIRE(gpo.total_vesting_fund_steem == total_comment_fund.vesting_fund()); - BOOST_REQUIRE(alice_comment.total_payout_value == alice_comment_reward.total_payout()); + BOOST_REQUIRE(db->has_index()); + + const auto& cr_idx = db->get_index().indices().get(); + + auto alice_cr_itr = cr_idx.find(alice_comment.id); + BOOST_CHECK(alice_cr_itr != cr_idx.end()); + BOOST_CHECK_EQUAL(alice_cr_itr->total_payout_value, alice_comment_reward.total_payout()); auto alice_total_vesting = alice_starting_vesting + alice_comment_reward.vesting_payout(); auto alice_total_sbd = alice_starting_sbd + alice_comment_reward.sbd_payout(); @@ -1175,8 +1206,15 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) generate_blocks(db->get_comment("alice", string("test")).cashout_time, true); + BOOST_REQUIRE(db->has_index()); + + const auto& cr_idx = db->get_index().indices().get(); + + auto alice_cr_itr = cr_idx.find(db->get_comment("alice", string("test")).id); + BOOST_REQUIRE(alice_cr_itr != cr_idx.end()); + auto start_balance = asset( - db->get_comment("alice", string("test")).total_payout_value.amount /2, + alice_cr_itr->total_payout_value.amount /2, SBD_SYMBOL); BOOST_TEST_MESSAGE("Setup conversion to GOLOS"); @@ -1202,7 +1240,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_REQUIRE(convert_request != convert_request_idx.end()); BOOST_REQUIRE(alice_2.balance.amount.value == 0); - BOOST_REQUIRE(alice_2.sbd_balance.amount.value == (start_balance - op.amount).amount.value); + APPROX_CHECK_EQUAL(alice_2.sbd_balance.amount.value, (start_balance - op.amount).amount.value, 10); validate_database(); BOOST_TEST_MESSAGE("Generate one more block"); @@ -1215,7 +1253,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) convert_request = convert_request_idx.find(std::make_tuple("alice", 2)); BOOST_REQUIRE(convert_request == convert_request_idx.end()); BOOST_REQUIRE(alice_3.balance.amount.value == 2500); - BOOST_REQUIRE(alice_3.sbd_balance.amount.value == (start_balance - op.amount).amount.value); + APPROX_CHECK_EQUAL(alice_3.sbd_balance.amount.value, (start_balance - op.amount).amount.value, 10); BOOST_REQUIRE(vop.owner == "alice"); BOOST_REQUIRE(vop.requestid == 2); BOOST_REQUIRE(vop.amount_in.amount.value == ASSET("2.000 GBG").amount.value); From 59ad74503ee9bec10fdb301676637b21221b34ae Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 2 Aug 2018 12:20:13 +0700 Subject: [PATCH 219/250] Fix authority for delete private message in cli_wallet. #807 --- libraries/wallet/wallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 57cd78a2a2..02d3ea43c5 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1173,7 +1173,7 @@ namespace golos { namespace wallet { custom_json_operation jop; jop.id = "private_message"; jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(to); + jop.required_posting_auths.insert(requester); signed_transaction trx; trx.operations.push_back(jop); @@ -1203,7 +1203,7 @@ namespace golos { namespace wallet { custom_json_operation jop; jop.id = "private_message"; jop.json = fc::json::to_string(pop); - jop.required_posting_auths.insert(to); + jop.required_posting_auths.insert(requester); signed_transaction trx; trx.operations.push_back(jop); From d03ef65c8aaf6797c58e847ddecc27034664fa80 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 2 Aug 2018 12:19:51 +0700 Subject: [PATCH 220/250] Add filter_accounts to query of private messages. #806 --- .../wallet/include/golos/wallet/wallet.hpp | 3 ++- libraries/wallet/wallet.cpp | 1 + .../private_message_api_objects.hpp | 3 ++- .../private_message_plugin.cpp | 24 +++++++++++-------- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 453fc4581e..37f2f8bf21 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -47,6 +47,7 @@ namespace golos { namespace wallet { struct optional_private_box_query { fc::flat_set select_accounts; + fc::flat_set filter_accounts; std::string newest_date; fc::optional unread_only; fc::optional limit; @@ -1457,7 +1458,7 @@ FC_REFLECT( FC_REFLECT( (golos::wallet::optional_private_box_query), - (select_accounts)(newest_date)(limit)(offset)(unread_only)) + (select_accounts)(filter_accounts)(newest_date)(limit)(offset)(unread_only)) FC_REFLECT( (golos::wallet::optional_private_thread_query), diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 02d3ea43c5..90ea200797 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2731,6 +2731,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st message_box_query query; query.newest_date = time_converter(query_template.newest_date, time_point::now(), time_point::now()).time(); query.select_accounts = query_template.select_accounts; + query.filter_accounts = query_template.filter_accounts; if (query_template.unread_only) { query.unread_only = *query_template.unread_only; } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 2b01455884..09eec1bb4b 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -113,6 +113,7 @@ namespace golos { namespace plugins { namespace private_message { */ struct message_box_query { fc::flat_set select_accounts; + fc::flat_set filter_accounts; time_point_sec newest_date = time_point_sec::min(); bool unread_only = false; uint16_t limit = PRIVATE_DEFAULT_LIMIT; @@ -158,7 +159,7 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::message_box_query), - (select_accounts)(newest_date)(unread_only)(limit)(offset)) + (select_accounts)(filter_accounts)(newest_date)(unread_only)(limit)(offset)) FC_REFLECT( (golos::plugins::private_message::message_thread_query), diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index f990c461dc..48b479969a 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -78,9 +78,9 @@ namespace golos { namespace plugins { namespace private_message { return time_point_sec(1); } - template + template std::vector private_message_plugin::private_message_plugin_impl::get_message_box( - const std::string& to, const message_box_query& query, Filter&& filter + const std::string& to, const message_box_query& query, GetAccount&& get_account ) const { std::vector result; const auto& idx = db_.get_index().indices().get(); @@ -94,6 +94,14 @@ namespace golos { namespace plugins { namespace private_message { auto etr = idx.upper_bound(std::make_tuple(to, min_create_date())); auto offset = query.offset; + auto filter = [&](const message_object& o) -> bool { + auto& account = get_account(o); + return + (query.select_accounts.empty() || query.select_accounts.count(account)) && + (query.filter_accounts.empty() || !query.filter_accounts.count(account)) && + (!query.unread_only || o.read_date == time_point_sec::min()); + }; + for (; itr != etr && offset; ++itr) { if (filter(*itr)){ --offset; @@ -752,10 +760,8 @@ namespace golos { namespace plugins { namespace private_message { return my->db_.with_weak_read_lock([&]() { return my->get_message_box( to, query, - [&](const message_object& o) -> bool { - return - (query.select_accounts.empty() || query.select_accounts.count(o.from)) && - (!query.unread_only || o.read_date == time_point_sec::min()); + [&](const message_object& o) -> const account_name_type& { + return o.from; } ); }); @@ -772,10 +778,8 @@ namespace golos { namespace plugins { namespace private_message { return my->db_.with_weak_read_lock([&]() { return my->get_message_box( from, query, - [&](const message_object& o) -> bool { - return - (query.select_accounts.empty() || query.select_accounts.count(o.to)) && - (!query.unread_only || o.read_date == time_point_sec::min()); + [&](const message_object& o) -> const account_name_type& { + return o.to; }); }); } From 1f7f4f23819518a54ecad82e4a2fd35fa6c4a351 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 2 Aug 2018 12:40:02 +0700 Subject: [PATCH 221/250] Eliminate the inbuilt NTP-client #753 --- libraries/time/include/golos/time/time.hpp | 9 ---- libraries/time/time.cpp | 59 +--------------------- plugins/witness/witness.cpp | 5 +- 3 files changed, 3 insertions(+), 70 deletions(-) diff --git a/libraries/time/include/golos/time/time.hpp b/libraries/time/include/golos/time/time.hpp index 86c4a7195d..55969870a4 100644 --- a/libraries/time/include/golos/time/time.hpp +++ b/libraries/time/include/golos/time/time.hpp @@ -10,17 +10,8 @@ namespace golos { typedef fc::signal time_discontinuity_signal_type; extern time_discontinuity_signal_type time_discontinuity_signal; - fc::optional ntp_time(); - fc::time_point now(); - fc::time_point nonblocking_now(); // identical to now() but guaranteed not to block - void update_ntp_time(); - - fc::microseconds ntp_error(); - - void shutdown_ntp_time(); - void start_simulated_time(const fc::time_point sim_time); void advance_simulated_time_to(const fc::time_point sim_time); diff --git a/libraries/time/time.cpp b/libraries/time/time.cpp index cd12132df5..7bf5e44eff 100644 --- a/libraries/time/time.cpp +++ b/libraries/time/time.cpp @@ -15,70 +15,13 @@ namespace golos { time_discontinuity_signal_type time_discontinuity_signal; - namespace detail { - std::atomic ntp_service(nullptr); - fc::mutex ntp_service_initialization_mutex; - } - - fc::optional ntp_time() { - fc::ntp *actual_ntp_service = detail::ntp_service.load(); - if (!actual_ntp_service) { - fc::scoped_lock lock(detail::ntp_service_initialization_mutex); - actual_ntp_service = detail::ntp_service.load(); - if (!actual_ntp_service) { - actual_ntp_service = new fc::ntp; - detail::ntp_service.store(actual_ntp_service); - } - } - return actual_ntp_service->get_time(); - } - - void shutdown_ntp_time() { - fc::ntp *actual_ntp_service = detail::ntp_service.exchange(nullptr); - delete actual_ntp_service; - } - fc::time_point now() { if (simulated_time) { return fc::time_point() + fc::seconds(simulated_time + adjusted_time_sec); } - fc::optional current_ntp_time = ntp_time(); - if (current_ntp_time.valid()) { - return *current_ntp_time + fc::seconds(adjusted_time_sec); - } else { - return fc::time_point::now() + fc::seconds(adjusted_time_sec); - } - } - - fc::time_point nonblocking_now() { - if (simulated_time) { - return fc::time_point() + - fc::seconds(simulated_time + adjusted_time_sec); - } - - fc::ntp *actual_ntp_service = detail::ntp_service.load(); - fc::optional current_ntp_time; - if (actual_ntp_service) { - current_ntp_time = actual_ntp_service->get_time(); - } - - if (current_ntp_time) { - return *current_ntp_time + fc::seconds(adjusted_time_sec); - } else { - return fc::time_point::now() + fc::seconds(adjusted_time_sec); - } - } - - void update_ntp_time() { - detail::ntp_service.load()->request_now(); - } - - fc::microseconds ntp_error() { - fc::optional current_ntp_time = ntp_time(); - FC_ASSERT(current_ntp_time, "We don't have NTP time!"); - return *current_ntp_time - fc::time_point::now(); + return fc::time_point::now() + fc::seconds(adjusted_time_sec); } void start_simulated_time(const fc::time_point sim_time) { diff --git a/plugins/witness/witness.cpp b/plugins/witness/witness.cpp index 9b18221c40..f4dbc4b083 100644 --- a/plugins/witness/witness.cpp +++ b/plugins/witness/witness.cpp @@ -263,7 +263,6 @@ namespace golos { } void witness_plugin::plugin_shutdown() { - golos::time::shutdown_ntp_time(); if (pimpl->mining_threads_) { ilog("shutting downing mining threads"); pimpl->mining_service_.stop(); @@ -561,7 +560,7 @@ namespace golos { op.props = _miner_prop_vote; while (true) { - if (golos::time::nonblocking_now() > stop) { + if (golos::time::now() > stop) { // ilog( "stop mining due to time out, nonce: ${n}", ("n",op.nonce) ); return; } @@ -609,7 +608,7 @@ namespace golos { op.props = _miner_prop_vote; while (true) { // if( ((op.nonce/num_threads) % 1000) == 0 ) idump((op.nonce)); - if (golos::time::nonblocking_now() > stop) { + if (golos::time::now() > stop) { // ilog( "stop mining due to time out, nonce: ${n}", ("n",op.nonce) ); return; } From cc2c10906c642e8aca15eaf9324d2a9087643f6c Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 2 Aug 2018 12:20:02 +0700 Subject: [PATCH 222/250] Add callbacks for private messages. #806 --- .../private_message_api_objects.hpp | 65 +++++- .../private_message_evaluators.hpp | 65 +++--- .../private_message_plugin.hpp | 4 +- .../private_message_plugin.cpp | 195 +++++++++++++++--- 4 files changed, 268 insertions(+), 61 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp index 09eec1bb4b..b48db7f0e6 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_api_objects.hpp @@ -32,7 +32,7 @@ namespace golos { namespace plugins { namespace private_message { class settings_object; - struct settings_api_object { + struct settings_api_object final { settings_api_object(const settings_object& o); settings_api_object(); @@ -87,7 +87,7 @@ namespace golos { namespace plugins { namespace private_message { */ class contact_object; - struct contact_api_object { + struct contact_api_object final { contact_api_object(const contact_object& o); contact_api_object(); @@ -111,7 +111,7 @@ namespace golos { namespace plugins { namespace private_message { /** * Query for inbox/outbox messages */ - struct message_box_query { + struct message_box_query final { fc::flat_set select_accounts; fc::flat_set filter_accounts; time_point_sec newest_date = time_point_sec::min(); @@ -123,13 +123,50 @@ namespace golos { namespace plugins { namespace private_message { /** * Query for thread messages */ - struct message_thread_query { + struct message_thread_query final { time_point_sec newest_date = time_point_sec::min(); bool unread_only = false; uint16_t limit = PRIVATE_DEFAULT_LIMIT; uint32_t offset = 0; }; - + + /** + * Events for callbacks + */ + enum class callback_event_type: uint8_t { + message, + mark, + remove_inbox, + remove_outbox, + contact, + }; + + /** + * Query for callback + */ + struct callback_query final { + fc::flat_set select_accounts; + fc::flat_set filter_accounts; + fc::flat_set select_events; + fc::flat_set filter_events; + }; + + /** + * Callback event about message + */ + struct callback_message_event final { + callback_event_type type; + message_api_object message; + }; + + /** + * Callback event about contact + */ + struct callback_contact_event final { + callback_event_type type; + contact_api_object contact; + }; + } } } // golos::plugins::private_message FC_REFLECT( @@ -163,4 +200,20 @@ FC_REFLECT( FC_REFLECT( (golos::plugins::private_message::message_thread_query), - (newest_date)(unread_only)(limit)(offset)) \ No newline at end of file + (newest_date)(unread_only)(limit)(offset)) + +FC_REFLECT_ENUM( + golos::plugins::private_message::callback_event_type, + (message)(mark)(remove_inbox)(remove_outbox)(contact)) + +FC_REFLECT( + (golos::plugins::private_message::callback_query), + (select_accounts)(filter_accounts)(select_events)(filter_events)) + +FC_REFLECT( + (golos::plugins::private_message::callback_message_event), + (type)(message)) + +FC_REFLECT( + (golos::plugins::private_message::callback_contact_event), + (type)(contact)) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp index 94e1eae49a..a276e5eb30 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_evaluators.hpp @@ -14,84 +14,89 @@ namespace golos { namespace plugins { namespace private_message { using golos::chain::evaluator_impl; using golos::chain::database; - class private_message_evaluator: - public evaluator_impl + template + class private_message_evaluator final: + public evaluator_impl, private_message_plugin_operation> { public: using operation_type = private_message_operation; - private_message_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), - plugin_(plugin) { + private_message_evaluator(database& db, Impl* impl) + : evaluator_impl, private_message_plugin_operation>(db), + impl_(impl) { } void do_apply(const private_message_operation& o); - private_message_plugin* plugin_; + Impl* impl_; }; - class private_delete_message_evaluator: - public evaluator_impl + template + class private_delete_message_evaluator final: + public evaluator_impl, private_message_plugin_operation> { public: using operation_type = private_delete_message_operation; - private_delete_message_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), - plugin_(plugin) { + private_delete_message_evaluator(database& db, Impl* impl) + : evaluator_impl, private_message_plugin_operation>(db), + impl_(impl) { } void do_apply(const private_delete_message_operation& o); - private_message_plugin* plugin_; + Impl* impl_; }; - class private_mark_message_evaluator: - public evaluator_impl + template + class private_mark_message_evaluator final: + public evaluator_impl, private_message_plugin_operation> { public: using operation_type = private_mark_message_operation; - private_mark_message_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), - plugin_(plugin) { + private_mark_message_evaluator(database& db, Impl* impl) + : evaluator_impl, private_message_plugin_operation>(db), + impl_(impl) { } void do_apply(const private_mark_message_operation& o); - private_message_plugin* plugin_; + Impl* impl_; }; - class private_settings_evaluator: - public evaluator_impl + template + class private_settings_evaluator final: + public evaluator_impl, private_message_plugin_operation> { public: using operation_type = private_settings_operation; - private_settings_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), - plugin_(plugin) { + private_settings_evaluator(database& db, Impl* impl) + : evaluator_impl, private_message_plugin_operation>(db), + impl_(impl) { } void do_apply(const private_settings_operation& o); - private_message_plugin* plugin_; + Impl* impl_; }; - class private_contact_evaluator: - public evaluator_impl + template + class private_contact_evaluator final: + public evaluator_impl, private_message_plugin_operation> { public: using operation_type = private_contact_operation; - private_contact_evaluator(database& db, private_message_plugin* plugin) - : evaluator_impl(db), - plugin_(plugin) { + private_contact_evaluator(database& db, Impl* impl) + : evaluator_impl, private_message_plugin_operation>(db), + impl_(impl) { } void do_apply(const private_contact_operation& o); - private_message_plugin* plugin_; + Impl* impl_; }; } } } diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp index 50832081e2..16173a6907 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_plugin.hpp @@ -23,6 +23,7 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API_ARGS(get_contact_info, json_rpc::msg_pack, contact_api_object) DEFINE_API_ARGS(get_contacts_size, json_rpc::msg_pack, contacts_size_api_object) DEFINE_API_ARGS(get_contacts, json_rpc::msg_pack, std::vector) + DEFINE_API_ARGS(set_callback, json_rpc::msg_pack, json_rpc::void_type) /** * This plugin scans the blockchain for custom operations containing a valid message and authorized @@ -47,8 +48,6 @@ namespace golos { namespace plugins { namespace private_message { void plugin_shutdown() override; - bool is_tracked_account(account_name_type) const; - static const std::string& name(); DECLARE_API( @@ -59,6 +58,7 @@ namespace golos { namespace plugins { namespace private_message { (get_contact_info) (get_contacts_size) (get_contacts) + (set_callback) ) private: diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 48b479969a..934d178033 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -12,6 +12,7 @@ #include +#include // template @@ -28,6 +29,18 @@ if( options.count(name) ) { \ namespace golos { namespace plugins { namespace private_message { + struct callback_info final { + callback_query query; + std::shared_ptr msg; + + callback_info() = default; + callback_info(callback_query&& q, std::shared_ptr m) + : query(q), + msg(m) { + + } + }; + class private_message_plugin::private_message_plugin_impl final { public: private_message_plugin_impl(private_message_plugin& plugin) @@ -36,11 +49,15 @@ namespace golos { namespace plugins { namespace private_message { custom_operation_interpreter_ = std::make_shared >(db_); - custom_operation_interpreter_->register_evaluator(&plugin); - custom_operation_interpreter_->register_evaluator(&plugin); - custom_operation_interpreter_->register_evaluator(&plugin); - custom_operation_interpreter_->register_evaluator(&plugin); - custom_operation_interpreter_->register_evaluator(&plugin); + auto coi = custom_operation_interpreter_.get(); + + using impl = private_message_plugin_impl; + + coi->register_evaluator>(this); + coi->register_evaluator>(this); + coi->register_evaluator>(this); + coi->register_evaluator>(this); + coi->register_evaluator>(this); db_.set_custom_operation_interpreter(plugin.name(), custom_operation_interpreter_); } @@ -63,6 +80,11 @@ namespace golos { namespace plugins { namespace private_message { std::vector get_contacts( const std::string& owner, const private_contact_type, uint16_t limit, uint32_t offset) const; + void call_callbacks( + const callback_event_type, const account_name_type& from, const account_name_type& to, fc::variant); + + bool can_call_callbacks() const; + ~private_message_plugin_impl() = default; bool is_tracked_account(account_name_type) const; @@ -72,6 +94,9 @@ namespace golos { namespace plugins { namespace private_message { flat_set tracked_account_list_; golos::chain::database& db_; + + std::mutex callbacks_mutex_; + std::list callbacks_; }; static inline time_point_sec min_create_date() { @@ -260,13 +285,44 @@ namespace golos { namespace plugins { namespace private_message { return result; } - void private_message_evaluator::do_apply(const private_message_operation& pm) { - database& d = db(); + bool private_message_plugin::private_message_plugin_impl::can_call_callbacks() const { + return !db_.is_producing() && !callbacks_.empty(); + } + + void private_message_plugin::private_message_plugin_impl::call_callbacks( + const callback_event_type event, const account_name_type& from, const account_name_type& to, fc::variant r + ) { + std::lock_guard lock(callbacks_mutex_); + for (auto itr = callbacks_.begin(); callbacks_.end() != itr; ) { + auto& info = *itr; + + if (info.query.filter_events.count(event) || + (!info.query.select_events.empty() && !info.query.select_events.count(event)) || + info.query.filter_accounts.count(from) || + info.query.filter_accounts.count(to) || + (to.size() && !info.query.select_accounts.empty() && !info.query.select_accounts.count(to)) || + (from.size() && !info.query.select_accounts.empty() && !info.query.select_accounts.count(from)) + ) { + ++itr; + continue; + } + + try { + info.msg->unsafe_result(r); + ++itr; + } catch (...) { + callbacks_.erase(itr++); + } + } + } - if (!plugin_->is_tracked_account(pm.from) && !plugin_->is_tracked_account(pm.to)) { + template + void private_message_evaluator::do_apply(const private_message_operation& pm) { + if (!impl_->is_tracked_account(pm.from) && !impl_->is_tracked_account(pm.to)) { return; } + database& d = impl_->db_; auto& contact_idx = d.get_index().indices().get(); auto contact_itr = contact_idx.find(std::make_tuple(pm.to, pm.from)); @@ -320,10 +376,17 @@ namespace golos { namespace plugins { namespace private_message { pmo.remove_date = time_point_sec::min(); set_message(pmo); }); + id_itr = id_idx.find(std::make_tuple(pm.from, pm.to, pm.nonce)); } else { d.modify(*id_itr, set_message); } + if (this->impl_->can_call_callbacks()) { + this->impl_->call_callbacks( + callback_event_type::message, pm.from, pm.to, + fc::variant(callback_message_event({callback_event_type::message, message_api_object(*id_itr)}))); + } + // Ok, now update contact lists and counters in them auto& size_idx = d.get_index().indices().get(); @@ -377,6 +440,14 @@ namespace golos { namespace plugins { namespace private_message { inc_counters(pco.size, is_send); }); is_new_contact = true; + + if (this->impl_->can_call_callbacks()) { + contact_itr = contact_idx.find(std::make_tuple(owner, contact)); + this->impl_->call_callbacks( + callback_event_type::contact, owner, contact, + fc::variant(callback_contact_event( + {callback_event_type::contact, contact_api_object(*contact_itr)}))); + } } modify_size(owner, type, is_new_contact, is_send); }; @@ -473,8 +544,16 @@ namespace golos { namespace plugins { namespace private_message { } } - void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { - database& d = db(); + template + void private_delete_message_evaluator::do_apply(const private_delete_message_operation& pdm) { + if (!impl_->is_tracked_account(pdm.from) && + !impl_->is_tracked_account(pdm.to) && + !impl_->is_tracked_account(pdm.requester) + ) { + return; + } + + database& d = impl_->db_; auto now = d.head_block_time(); fc::flat_map, contact_size_info> stat_map; @@ -504,6 +583,24 @@ namespace golos { namespace plugins { namespace private_message { outbox_stat.unread_outbox_messages += unread_messages; outbox_stat.total_outbox_messages++; } + + if (this->impl_->can_call_callbacks()) { + message_api_object ma(m); + ma.remove_date = now; + + if (pdm.requester == pdm.to) { + this->impl_->call_callbacks( + callback_event_type::remove_inbox, m.from, m.to, + fc::variant(callback_message_event( + {callback_event_type::remove_inbox, ma}))); + } else { + this->impl_->call_callbacks( + callback_event_type::remove_outbox, m.from, m.to, + fc::variant(callback_message_event( + {callback_event_type::remove_outbox, ma}))); + } + } + if (m.remove_date == time_point_sec::min()) { d.modify(m, [&](auto& m) { m.remove_date = now; @@ -537,8 +634,13 @@ namespace golos { namespace plugins { namespace private_message { ); } - void private_mark_message_evaluator::do_apply(const private_mark_message_operation& pmm) { - database& d = db(); + template + void private_mark_message_evaluator::do_apply(const private_mark_message_operation& pmm) { + if (!impl_->is_tracked_account(pmm.from) && !impl_->is_tracked_account(pmm.to)) { + return; + } + + database& d = impl_->db_; uint32_t total_marked_messages = 0; auto now = d.head_block_time(); @@ -562,6 +664,12 @@ namespace golos { namespace plugins { namespace private_message { d.modify(m, [&](message_object& m){ m.read_date = now; }); + + if (this->impl_->can_call_callbacks()) { + this->impl_->call_callbacks( + callback_event_type::mark, m.from, m.to, + fc::variant(callback_message_event({callback_event_type::mark, message_api_object(m)}))); + } return true; }, @@ -576,8 +684,13 @@ namespace golos { namespace plugins { namespace private_message { "No unread messages in requested range"); } - void private_settings_evaluator::do_apply(const private_settings_operation& ps) { - database& d = db(); + template + void private_settings_evaluator::do_apply(const private_settings_operation& ps) { + if (!impl_->is_tracked_account(ps.owner)) { + return; + } + + database& d = impl_->db_; auto& idx = d.get_index().indices().get(); auto itr = idx.find(ps.owner); @@ -594,13 +707,14 @@ namespace golos { namespace plugins { namespace private_message { } } - void private_contact_evaluator::do_apply(const private_contact_operation& pc) { - database& d = db(); - - if (!plugin_->is_tracked_account(pc.owner) && !plugin_->is_tracked_account(pc.contact)) { + template + void private_contact_evaluator::do_apply(const private_contact_operation& pc) { + if (!impl_->is_tracked_account(pc.owner) && !impl_->is_tracked_account(pc.contact)) { return; } + database& d = impl_->db_; + auto& contact_idx = d.get_index().indices().get(); auto contact_itr = contact_idx.find(std::make_tuple(pc.owner, pc.contact)); @@ -667,6 +781,8 @@ namespace golos { namespace plugins { namespace private_message { from_string(plo.json_metadata, pc.json_metadata); }); + contact_itr = contact_idx.find(std::make_tuple(pc.owner, pc.contact)); + if (owner_idx.end() == dst_itr) { d.create([&](auto& pcso) { pcso.owner = pc.owner; @@ -679,6 +795,13 @@ namespace golos { namespace plugins { namespace private_message { }); } } + + if (this->impl_->can_call_callbacks()) { + this->impl_->call_callbacks( + callback_event_type::contact, pc.owner, pc.contact, + fc::variant(callback_contact_event( + {callback_event_type::contact, contact_api_object(*contact_itr)}))); + } } private_message_plugin::private_message_plugin() = default; @@ -743,10 +866,6 @@ namespace golos { namespace plugins { namespace private_message { return tracked_account_ranges_.end() != range_itr && name >= range_itr->first && name <= range_itr->second; } - bool private_message_plugin::is_tracked_account(account_name_type name) const { - return my->is_tracked_account(name); - } - // Api Defines DEFINE_API(private_message_plugin, get_inbox) { @@ -770,7 +889,7 @@ namespace golos { namespace plugins { namespace private_message { DEFINE_API(private_message_plugin, get_outbox) { PLUGIN_API_VALIDATE_ARGS( (std::string, from) - (message_box_query, query) + (message_box_query, query) ); GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); @@ -852,4 +971,34 @@ namespace golos { namespace plugins { namespace private_message { }); } + DEFINE_API(private_message_plugin, set_callback) { + PLUGIN_API_VALIDATE_ARGS( + (callback_query, query) + ); + + GOLOS_CHECK_PARAM(query.filter_accounts, { + for (auto& itr : query.filter_accounts) { + GOLOS_CHECK_VALUE(!query.select_accounts.count(itr), + "Can't filter and select accounts '${account}' at the same time", + ("account", itr)); + } + }); + + GOLOS_CHECK_PARAM(query.filter_events, { + for (auto& itr : query.filter_events) { + GOLOS_CHECK_VALUE(!query.select_events.count(itr), + "Can't filter and select accounts '${event}' at the same time", + ("event", itr)); + } + }); + + json_rpc::msg_pack_transfer transfer(args); + { + std::lock_guard lock(my->callbacks_mutex_); + my->callbacks_.emplace_back(std::move(query), transfer.msg()); + }; + transfer.complete(); + return {}; + } + } } } // golos::plugins::private_message From 213738ee950047e1ab82af8e52b0044f87a33ef4 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 2 Aug 2018 14:17:37 +0700 Subject: [PATCH 223/250] Add checking of filter_accounts in private messages. #807 --- .../private_message/private_message_plugin.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index 934d178033..f47e87b359 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -876,6 +876,14 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); + GOLOS_CHECK_PARAM(query.filter_accounts, { + for (auto& itr : query.filter_accounts) { + GOLOS_CHECK_VALUE(!query.select_accounts.count(itr), + "Can't filter and select accounts '${account}' at the same time", + ("account", itr)); + } + }); + return my->db_.with_weak_read_lock([&]() { return my->get_message_box( to, query, @@ -894,6 +902,14 @@ namespace golos { namespace plugins { namespace private_message { GOLOS_CHECK_LIMIT_PARAM(query.limit, PRIVATE_DEFAULT_LIMIT); + GOLOS_CHECK_PARAM(query.filter_accounts, { + for (auto& itr : query.filter_accounts) { + GOLOS_CHECK_VALUE(!query.select_accounts.count(itr), + "Can't filter and select accounts '${account}' at the same time", + ("account", itr)); + } + }); + return my->db_.with_weak_read_lock([&]() { return my->get_message_box( from, query, From 6bebb43851d7269d7ec92c278f555ef2f09b5826 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Thu, 2 Aug 2018 15:15:44 +0700 Subject: [PATCH 224/250] Add contact_has_not_changed to private messages. #807 --- .../plugins/private_message/private_message_exceptions.hpp | 4 ++-- plugins/private_message/private_message_plugin.cpp | 4 ++-- tests/plugin_tests/private_message.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp index 6c95039b15..4e9a04a7c3 100644 --- a/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp +++ b/plugins/private_message/include/golos/plugins/private_message/private_message_exceptions.hpp @@ -13,7 +13,7 @@ namespace golos { namespace plugins { namespace private_message { sender_in_ignore_list, recepient_ignores_messages_from_unknown_contact, add_unknown_contact, - contact_has_same_type, + contact_has_not_changed, no_unread_messages, }; }; @@ -34,6 +34,6 @@ FC_REFLECT_ENUM(golos::plugins::private_message::logic_errors::types, (sender_in_ignore_list) (recepient_ignores_messages_from_unknown_contact) (add_unknown_contact) - (contact_has_same_type) + (contact_has_not_changed) (no_unread_messages) ); \ No newline at end of file diff --git a/plugins/private_message/private_message_plugin.cpp b/plugins/private_message/private_message_plugin.cpp index f47e87b359..55fdd2621e 100644 --- a/plugins/private_message/private_message_plugin.cpp +++ b/plugins/private_message/private_message_plugin.cpp @@ -726,8 +726,8 @@ namespace golos { namespace plugins { namespace private_message { std::string json_metadata(contact_itr->json_metadata.begin(), contact_itr->json_metadata.end()); GOLOS_CHECK_LOGIC(contact_itr->type != pc.type || pc.json_metadata != json_metadata, - logic_errors::contact_has_same_type, - "Contact has the same type"); + logic_errors::contact_has_not_changed, + "Contact hasn't changed"); auto& owner_idx = d.get_index().indices().get(); auto dst_itr = owner_idx.find(std::make_tuple(pc.owner, pc.type)); diff --git a/tests/plugin_tests/private_message.cpp b/tests/plugin_tests/private_message.cpp index 2c9ce79c59..2565746e8c 100644 --- a/tests/plugin_tests/private_message.cpp +++ b/tests/plugin_tests/private_message.cpp @@ -303,11 +303,11 @@ BOOST_FIXTURE_TEST_SUITE(private_message_plugin, private_message_fixture) generate_block(); - BOOST_TEST_MESSAGE("--- Same contact"); + BOOST_TEST_MESSAGE("--- Contact hasn't changed"); GOLOS_CHECK_ERROR_PROPS(push_tx_with_ops(trx, alice_private_key, jop), CHECK_ERROR(tx_invalid_operation, 0, - CHECK_ERROR(logic_exception, logic_errors::contact_has_same_type))); + CHECK_ERROR(logic_exception, logic_errors::contact_has_not_changed))); cop.json_metadata = "{\"name\":\"Mark\"}"; pop = cop; From 6f0bf7c37705958f685fce38fa3946dcf11b2fa9 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Thu, 2 Aug 2018 11:54:07 +0300 Subject: [PATCH 225/250] Fix pending curators payout calculation #903 --- libraries/api/discussion_helper.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/api/discussion_helper.cpp b/libraries/api/discussion_helper.cpp index 7d14d5b4d3..a901d7664d 100644 --- a/libraries/api/discussion_helper.cpp +++ b/libraries/api/discussion_helper.cpp @@ -39,7 +39,7 @@ namespace golos { namespace api { const std::string& author, const std::string& permlink, uint32_t limit ) const ; - share_type get_curator_rewards_claim(const discussion& d, share_type max_rewards) const; + share_type get_curator_unclaimed_rewards(const discussion& d, share_type max_rewards) const; void set_pending_payout(discussion& d) const; @@ -174,8 +174,8 @@ namespace golos { namespace api { pimpl->select_active_votes(result, total_count, author, permlink, limit); } - share_type discussion_helper::impl::get_curator_rewards_claim(const discussion& d, share_type max_rewards) const { - share_type total_claim = max_rewards; + share_type discussion_helper::impl::get_curator_unclaimed_rewards(const discussion& d, share_type max_rewards) const { + share_type unclaimed_rewards = max_rewards; auto& db = database(); try { uint128_t total_weight(d.total_vote_weight); @@ -186,17 +186,17 @@ namespace golos { namespace api { for (auto itr = cvidx.lower_bound(d.id); itr != cvidx.end() && itr->comment == d.id; ++itr) { auto claim = ((max_rewards.value * uint128_t(itr->weight)) / total_weight).to_uint64(); if (claim > 0) { // min_amt is non-zero satoshis - total_claim += claim; + unclaimed_rewards -= claim; } else { break; } } - } else { - total_claim = 0; } + } else { + unclaimed_rewards = 0; } - return total_claim; + return unclaimed_rewards; } FC_CAPTURE_AND_RETHROW() } @@ -233,7 +233,8 @@ namespace golos { namespace api { share_type curation_tokens = ((reward_tokens * db.get_curation_rewards_percent()) / STEEMIT_100_PERCENT).to_uint64(); - auto crs_claim = get_curator_rewards_claim(d, curation_tokens); + auto crs_unclaimed = get_curator_unclaimed_rewards(d, curation_tokens); + auto crs_claim = curation_tokens - crs_unclaimed; share_type author_tokens = reward_tokens.to_uint64() - crs_claim; if (d.allow_curation_rewards) { d.pending_curator_payout_value = db.to_sbd(asset(crs_claim, STEEM_SYMBOL)); From b93b6f01badaf061f9900ffd91f6a8e96a7e9c8a Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Wed, 1 Aug 2018 15:04:58 +0300 Subject: [PATCH 226/250] Add delete_reblog_operation to follow-plugin #751 --- plugins/follow/follow_evaluators.cpp | 132 ++++++++++----- plugins/follow/follow_operations.cpp | 6 + .../plugins/follow/follow_api_object.hpp | 2 +- .../plugins/follow/follow_evaluators.hpp | 24 ++- .../golos/plugins/follow/follow_objects.hpp | 2 +- .../plugins/follow/follow_operations.hpp | 16 +- .../include/golos/plugins/follow/plugin.hpp | 14 +- plugins/follow/plugin.cpp | 153 +++++++++--------- 8 files changed, 219 insertions(+), 130 deletions(-) diff --git a/plugins/follow/follow_evaluators.cpp b/plugins/follow/follow_evaluators.cpp index 628be85960..5de28d0179 100644 --- a/plugins/follow/follow_evaluators.cpp +++ b/plugins/follow/follow_evaluators.cpp @@ -8,7 +8,28 @@ namespace golos { namespace plugins { namespace follow { - void follow_evaluator::do_apply(const follow_operation &o) { + void save_blog_stats(database& db, account_name_type blogger, account_name_type guest, uint32_t start_count = 0) { + + const auto& stats_idx = db.get_index(); + auto stats_itr = stats_idx.lower_bound(boost::make_tuple(blogger, guest)); + if (stats_itr != stats_idx.end() && stats_itr->blogger == blogger && stats_itr->guest == guest) { + db.modify(*stats_itr, [&](blog_author_stats_object& s) { + if (start_count > 0) { + ++s.count; + } else { + --s.count; + } + }); + } else { + db.create([&](blog_author_stats_object& s) { + s.count = start_count; + s.blogger = blogger; + s.guest = guest; + }); + } + } + + void follow_evaluator::do_apply(const follow_operation& o) { try { static map follow_type_map = []() { map follow_map; @@ -19,7 +40,7 @@ namespace golos { return follow_map; }(); - const auto &idx = db().get_index().indices().get(); + const auto& idx = db().get_index().indices().get(); auto itr = idx.find(boost::make_tuple(o.follower, o.following)); uint16_t what = 0; @@ -48,7 +69,7 @@ namespace golos { bool was_followed = false; if (itr == idx.end()) { - db().create([&](follow_object &obj) { + db().create([&](follow_object& obj) { obj.follower = o.follower; obj.following = o.following; obj.what = what; @@ -56,15 +77,15 @@ namespace golos { } else { was_followed = itr->what & 1 << blog; - db().modify(*itr, [&](follow_object &obj) { + db().modify(*itr, [&](follow_object& obj) { obj.what = what; }); } - const auto &follower = db().find(o.follower); + const auto& follower = db().find(o.follower); if (follower == nullptr) { - db().create([&](follow_count_object &obj) { + db().create([&](follow_count_object& obj) { obj.account = o.follower; if (is_following) { @@ -72,7 +93,7 @@ namespace golos { } }); } else { - db().modify(*follower, [&](follow_count_object &obj) { + db().modify(*follower, [&](follow_count_object& obj) { if (was_followed) { obj.following_count--; } @@ -82,10 +103,10 @@ namespace golos { }); } - const auto &following = db().find(o.following); + const auto& following = db().find(o.following); if (following == nullptr) { - db().create([&](follow_count_object &obj) { + db().create([&](follow_count_object& obj) { obj.account = o.following; if (is_following) { @@ -93,7 +114,7 @@ namespace golos { } }); } else { - db().modify(*following, [&](follow_count_object &obj) { + db().modify(*following, [&](follow_count_object& obj) { if (was_followed) { obj.follower_count--; } @@ -106,15 +127,15 @@ namespace golos { FC_CAPTURE_AND_RETHROW((o)) } - void reblog_evaluator::do_apply(const reblog_operation &o) { + void reblog_evaluator::do_apply(const reblog_operation& o) { try { - const auto &c = db().get_comment(o.author, o.permlink); + const auto& c = db().get_comment(o.author, o.permlink); GOLOS_CHECK_LOGIC(c.parent_author.size() == 0, logic_errors::only_top_level_posts_reblogged, "Only top level posts can be reblogged"); - const auto &blog_idx = db().get_index().indices().get(); - const auto &blog_comment_idx = db().get_index().indices().get(); + const auto& blog_idx = db().get_index().indices().get(); + const auto& blog_comment_idx = db().get_index().indices().get(); auto next_blog_id = 0; auto last_blog = blog_idx.lower_bound(o.account); @@ -128,34 +149,20 @@ namespace golos { GOLOS_CHECK_LOGIC(blog_itr == blog_comment_idx.end(), logic_errors::account_already_reblogged_this_post, "Account has already reblogged this post"); - db().create([&](blog_object &b) { + db().create([&](blog_object& b) { b.account = o.account; b.comment = c.id; b.reblogged_on = db().head_block_time(); b.blog_feed_id = next_blog_id; }); - const auto &stats_idx = db().get_index(); - auto stats_itr = stats_idx.lower_bound(boost::make_tuple(o.account, c.author)); - if (stats_itr != stats_idx.end() && stats_itr->blogger == o.account && - stats_itr->guest == c.author) { - db().modify(*stats_itr, [&](blog_author_stats_object &s) { - ++s.count; - }); - } else { - db().create([&](blog_author_stats_object &s) { - s.count = 1; - s.blogger = o.account; - s.guest = c.author; - }); - } - - const auto &feed_idx = db().get_index().indices().get(); - const auto &comment_idx = db().get_index().indices().get(); - const auto &idx = db().get_index().indices().get(); - auto itr = idx.find(o.account); + save_blog_stats(db(), o.account, c.author, 1); - while (itr != idx.end() && itr->following == o.account) { + const auto& feed_idx = db().get_index().indices().get(); + const auto& comment_idx = db().get_index().indices().get(); + const auto& idx = db().get_index().indices().get(); + + for (auto itr = idx.find(o.account); itr != idx.end() && itr->following == o.account; ++itr) { if (itr->what & (1 << blog)) { uint32_t next_id = 0; @@ -168,7 +175,7 @@ namespace golos { auto feed_itr = comment_idx.find(boost::make_tuple(c.id, itr->follower)); if (feed_itr == comment_idx.end()) { - db().create([&](feed_object &f) { + db().create([&](feed_object& f) { f.account = itr->follower; f.reblogged_by.push_back(o.account); f.first_reblogged_by = o.account; @@ -178,13 +185,13 @@ namespace golos { f.account_feed_id = next_id; }); } else { - db().modify(*feed_itr, [&](feed_object &f) { + db().modify(*feed_itr, [&](feed_object& f) { f.reblogged_by.push_back(o.account); f.reblogs++; }); } - const auto &old_feed_idx = db().get_index().indices().get(); + const auto& old_feed_idx = db().get_index().indices().get(); auto old_feed = old_feed_idx.lower_bound(itr->follower); while (old_feed->account == itr->follower && next_id - old_feed->account_feed_id > _plugin->max_feed_size()) { @@ -192,9 +199,56 @@ namespace golos { old_feed = old_feed_idx.lower_bound(itr->follower); }; } + } + } FC_CAPTURE_AND_RETHROW((o)) + } - ++itr; + void delete_reblog_evaluator::do_apply(const delete_reblog_operation& o) { + try { + const auto& c = db().get_comment(o.author, o.permlink); + + // Deleting blog object + + const auto& blog_comment_idx = db().get_index().indices().get(); + + auto blog_itr = blog_comment_idx.find(boost::make_tuple(c.id, o.account)); + + GOLOS_CHECK_LOGIC(blog_itr != blog_comment_idx.end(), + logic_errors::account_has_not_reblogged_this_post, + "Account has not reblogged this post"); + + db().remove(*blog_itr); + + // Fixing blog statistics + + save_blog_stats(db(), o.account, c.author, 0); + + // Removing info about reblog from feed_objects for followers of reblogger + + const auto& comment_idx = db().get_index().indices().get(); + const auto& idx = db().get_index().indices().get(); + + for (auto itr = idx.find(o.account); itr != idx.end() && itr->following == o.account; ++itr) { + + if (itr->what & (1 << blog)) { + + auto feed_itr = comment_idx.find(boost::make_tuple(c.id, itr->follower)); + + if (feed_itr != comment_idx.end()) { + if (feed_itr->reblogs <= 1) { + db().remove(*feed_itr); + } else { + db().modify(*feed_itr, [&](feed_object& f) { + f.reblogged_by.erase(std::remove(f.reblogged_by.begin(), f.reblogged_by.end(), + o.account)); + f.reblogs--; + }); + } + } + } } + + } FC_CAPTURE_AND_RETHROW((o)) } diff --git a/plugins/follow/follow_operations.cpp b/plugins/follow/follow_operations.cpp index a7dcd31c51..be9725e134 100644 --- a/plugins/follow/follow_operations.cpp +++ b/plugins/follow/follow_operations.cpp @@ -17,6 +17,12 @@ namespace golos { "You cannot reblog your own content"); } + void delete_reblog_operation::validate() const { + GOLOS_CHECK_LOGIC(account != author, + logic_errors::cannot_delete_reblog_of_own_content, + "You cannot delete reblog of your own content"); + } + } } } //golos::follow diff --git a/plugins/follow/include/golos/plugins/follow/follow_api_object.hpp b/plugins/follow/include/golos/plugins/follow/follow_api_object.hpp index f5b5a53de7..ce53a5bfd0 100644 --- a/plugins/follow/include/golos/plugins/follow/follow_api_object.hpp +++ b/plugins/follow/include/golos/plugins/follow/follow_api_object.hpp @@ -67,7 +67,7 @@ namespace golos { limit(lim) { } - follow_count_api_obj(const follow_count_api_obj &o) : + follow_count_api_obj(const follow_count_api_obj& o) : account(o.account), follower_count(o.follower_count), following_count(o.following_count), diff --git a/plugins/follow/include/golos/plugins/follow/follow_evaluators.hpp b/plugins/follow/include/golos/plugins/follow/follow_evaluators.hpp index cc00314153..0ec41396b5 100644 --- a/plugins/follow/include/golos/plugins/follow/follow_evaluators.hpp +++ b/plugins/follow/include/golos/plugins/follow/follow_evaluators.hpp @@ -15,24 +15,36 @@ namespace golos { public: typedef follow_operation operation_type; - follow_evaluator(database &db, plugin *plugin) : golos::chain::evaluator_impl(db), _plugin(plugin) { + follow_evaluator(database& db, plugin* plugin) : golos::chain::evaluator_impl(db), _plugin(plugin) { } - void do_apply(const follow_operation &o); + void do_apply(const follow_operation& o); - plugin *_plugin; + plugin* _plugin; }; class reblog_evaluator : public golos::chain::evaluator_impl { public: typedef reblog_operation operation_type; - reblog_evaluator(database &db, plugin *plugin) : golos::chain::evaluator_impl(db), _plugin(plugin) { + reblog_evaluator(database& db, plugin* plugin) : golos::chain::evaluator_impl(db), _plugin(plugin) { } - void do_apply(const reblog_operation &o); + void do_apply(const reblog_operation& o); - plugin *_plugin; + plugin* _plugin; + }; + + class delete_reblog_evaluator : public golos::chain::evaluator_impl { + public: + typedef delete_reblog_operation operation_type; + + delete_reblog_evaluator(database& db, plugin* plugin) : golos::chain::evaluator_impl(db), _plugin(plugin) { + } + + void do_apply(const delete_reblog_operation& o); + + plugin* _plugin; }; } } diff --git a/plugins/follow/include/golos/plugins/follow/follow_objects.hpp b/plugins/follow/include/golos/plugins/follow/follow_objects.hpp index 0bc3f7c24c..3bda8d6105 100644 --- a/plugins/follow/include/golos/plugins/follow/follow_objects.hpp +++ b/plugins/follow/include/golos/plugins/follow/follow_objects.hpp @@ -10,7 +10,7 @@ namespace golos { using protocol::share_type; using chainbase::object; using chainbase::object_id; - using chainbase::allocator ; + using chainbase::allocator; using chainbase::shared_vector; using golos::chain::comment_object; using golos::chain::by_id; diff --git a/plugins/follow/include/golos/plugins/follow/follow_operations.hpp b/plugins/follow/include/golos/plugins/follow/follow_operations.hpp index d6006c1bf9..8686704bda 100644 --- a/plugins/follow/include/golos/plugins/follow/follow_operations.hpp +++ b/plugins/follow/include/golos/plugins/follow/follow_operations.hpp @@ -20,7 +20,7 @@ namespace golos { } }; - struct reblog_operation : base_operation{ + struct reblog_operation : base_operation { protocol::account_name_type account; protocol::account_name_type author; std::string permlink; @@ -31,7 +31,18 @@ namespace golos { } }; - using follow_plugin_operation = fc::static_variant; + struct delete_reblog_operation : base_operation { + protocol::account_name_type account; + protocol::account_name_type author; + std::string permlink; + + void validate() const; + void get_required_posting_authorities(flat_set& a) const { + a.insert(account); + } + }; + + using follow_plugin_operation = fc::static_variant; } } @@ -39,6 +50,7 @@ namespace golos { FC_REFLECT((golos::plugins::follow::follow_operation), (follower)(following)(what)); FC_REFLECT((golos::plugins::follow::reblog_operation), (account)(author)(permlink)); +FC_REFLECT((golos::plugins::follow::delete_reblog_operation), (account)(author)(permlink)); FC_REFLECT_TYPENAME((golos::plugins::follow::follow_plugin_operation)); DECLARE_OPERATION_TYPE(golos::plugins::follow::follow_plugin_operation) diff --git a/plugins/follow/include/golos/plugins/follow/plugin.hpp b/plugins/follow/include/golos/plugins/follow/plugin.hpp index da43114e6a..65983437d9 100644 --- a/plugins/follow/include/golos/plugins/follow/plugin.hpp +++ b/plugins/follow/include/golos/plugins/follow/plugin.hpp @@ -13,9 +13,11 @@ namespace golos { namespace plugins { namespace follow { enum error_type { cannot_follow_yourself, cannot_reblog_own_content, + cannot_delete_reblog_of_own_content, cannot_follow_and_ignore_simultaneously, only_top_level_posts_reblogged, account_already_reblogged_this_post, + account_has_not_reblogged_this_post, }; }; @@ -41,14 +43,14 @@ namespace golos { namespace plugins { namespace follow { class plugin final : public appbase::plugin { public: - constexpr static const char *plugin_name = "follow"; + constexpr static const char* plugin_name = "follow"; APPBASE_PLUGIN_REQUIRES( (chain::plugin) (json_rpc::plugin) ) - static const std::string &name() { + static const std::string& name() { static std::string name = plugin_name; return name; } @@ -70,10 +72,10 @@ namespace golos { namespace plugins { namespace follow { plugin(); - void set_program_options(boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) override; + void set_program_options(boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) override; - void plugin_initialize(const boost::program_options::variables_map &options) override; + void plugin_initialize(const boost::program_options::variables_map& options) override; uint32_t max_feed_size(); @@ -93,7 +95,9 @@ namespace golos { namespace plugins { namespace follow { FC_REFLECT_ENUM(golos::plugins::follow::logic_errors::error_type, (cannot_follow_yourself) (cannot_reblog_own_content) + (cannot_delete_reblog_of_own_content) (cannot_follow_and_ignore_simultaneously) (only_top_level_posts_reblogged) (account_already_reblogged_this_post) + (account_has_not_reblogged_this_post) ); diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index 86febf794d..a003b9d354 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -44,7 +44,7 @@ namespace golos { return; } - auto &rep_idx = db.get_index().indices().get(); + auto& rep_idx = db.get_index().indices().get(); auto itr = rep_idx.find(account); if (rep_idx.end() != itr) { reputation = itr->reputation; @@ -54,47 +54,47 @@ namespace golos { } struct pre_operation_visitor { - plugin &_plugin; - golos::chain::database &db; + plugin& _plugin; + golos::chain::database& db; - pre_operation_visitor(plugin &plugin, golos::chain::database &db) : _plugin(plugin), db(db) { + pre_operation_visitor(plugin& plugin, golos::chain::database& db) : _plugin(plugin), db(db) { } typedef void result_type; template - void operator()(const T &) const { + void operator()(const T&) const { } - void operator()(const vote_operation &op) const { + void operator()(const vote_operation& op) const { try { - const auto &c = db.get_comment(op.author, op.permlink); + const auto& c = db.get_comment(op.author, op.permlink); if (db.calculate_discussion_payout_time(c) == fc::time_point_sec::maximum()) { return; } - const auto &cv_idx = db.get_index().indices().get(); + const auto& cv_idx = db.get_index().indices().get(); auto cv = cv_idx.find(std::make_tuple(c.id, db.get_account(op.voter).id)); if (cv != cv_idx.end()) { - const auto &rep_idx = db.get_index().indices().get(); + const auto& rep_idx = db.get_index().indices().get(); auto rep = rep_idx.find(op.author); if (rep != rep_idx.end()) { - db.modify(*rep, [&](reputation_object &r) { + db.modify(*rep, [&](reputation_object& r) { r.reputation -= (cv->rshares >> 6); // Shift away precision from vests. It is noise }); } } - } catch (const fc::exception &e) { + } catch (const fc::exception& e) { } } - void operator()(const delete_comment_operation &op) const { + void operator()(const delete_comment_operation& op) const { try { - const auto *comment = db.find_comment(op.author, op.permlink); + const auto* comment = db.find_comment(op.author, op.permlink); if (comment == nullptr) { return; @@ -103,20 +103,20 @@ namespace golos { return; } - const auto &feed_idx = db.get_index().indices().get(); + const auto& feed_idx = db.get_index().indices().get(); auto itr = feed_idx.lower_bound(comment->id); while (itr != feed_idx.end() && itr->comment == comment->id) { - const auto &old_feed = *itr; + const auto& old_feed = *itr; ++itr; db.remove(old_feed); } - const auto &blog_idx = db.get_index().indices().get(); + const auto& blog_idx = db.get_index().indices().get(); auto blog_itr = blog_idx.lower_bound(comment->id); while (blog_itr != blog_idx.end() && blog_itr->comment == comment->id) { - const auto &old_blog = *blog_itr; + const auto& old_blog = *blog_itr; ++blog_itr; db.remove(old_blog); } @@ -125,19 +125,19 @@ namespace golos { }; struct post_operation_visitor { - plugin &_plugin; - database &db; + plugin& _plugin; + database& db; - post_operation_visitor(plugin &plugin, database &db) : _plugin(plugin), db(db) { + post_operation_visitor(plugin& plugin, database& db) : _plugin(plugin), db(db) { } typedef void result_type; template - void operator()(const T &) const { + void operator()(const T&) const { } - void operator()(const custom_json_operation &op) const { + void operator()(const custom_json_operation& op) const { try { if (op.id == plugin::plugin_name) { custom_json_operation new_cop; @@ -149,7 +149,7 @@ namespace golos { try { fop = fc::json::from_string(op.json).as(); - } catch (const fc::exception &) { + } catch (const fc::exception&) { return; } @@ -161,23 +161,23 @@ namespace golos { } FC_CAPTURE_AND_RETHROW() } - void operator()(const comment_operation &op) const { + void operator()(const comment_operation& op) const { try { if (op.parent_author.size() > 0) { return; } - const auto &c = db.get_comment(op.author, op.permlink); + const auto& c = db.get_comment(op.author, op.permlink); if (c.created != db.head_block_time()) { return; } - const auto &idx = db.get_index().indices().get(); - const auto &comment_idx = db.get_index().indices().get(); + const auto& idx = db.get_index().indices().get(); + const auto& comment_idx = db.get_index().indices().get(); auto itr = idx.find(op.author); - const auto &feed_idx = db.get_index().indices().get(); + const auto& feed_idx = db.get_index().indices().get(); while (itr != idx.end() && itr->following == op.author) { if (itr->what & (1 << blog)) { @@ -189,13 +189,13 @@ namespace golos { } if (comment_idx.find(boost::make_tuple(c.id, itr->follower)) == comment_idx.end()) { - db.create([&](feed_object &f) { + db.create([&](feed_object& f) { f.account = itr->follower; f.comment = c.id; f.account_feed_id = next_id; }); - const auto &old_feed_idx = db.get_index().indices().get(); + const auto& old_feed_idx = db.get_index().indices().get(); auto old_feed = old_feed_idx.lower_bound(itr->follower); while (old_feed->account == itr->follower && @@ -209,8 +209,8 @@ namespace golos { ++itr; } - const auto &blog_idx = db.get_index().indices().get(); - const auto &comment_blog_idx = db.get_index().indices().get(); + const auto& blog_idx = db.get_index().indices().get(); + const auto& comment_blog_idx = db.get_index().indices().get(); auto last_blog = blog_idx.lower_bound(op.author); uint32_t next_id = 0; @@ -219,13 +219,13 @@ namespace golos { } if (comment_blog_idx.find(boost::make_tuple(c.id, op.author)) == comment_blog_idx.end()) { - db.create([&](blog_object &b) { + db.create([&](blog_object& b) { b.account = op.author; b.comment = c.id; b.blog_feed_id = next_id; }); - const auto &old_blog_idx = db.get_index().indices().get(); + const auto& old_blog_idx = db.get_index().indices().get(); auto old_blog = old_blog_idx.lower_bound(op.author); while (old_blog->account == op.author && @@ -237,18 +237,18 @@ namespace golos { } FC_LOG_AND_RETHROW() } - void operator()(const vote_operation &op) const { + void operator()(const vote_operation& op) const { try { - const auto &comment = db.get_comment(op.author, op.permlink); + const auto& comment = db.get_comment(op.author, op.permlink); if (db.calculate_discussion_payout_time(comment) == fc::time_point_sec::maximum()) { return; } - const auto &cv_idx = db.get_index().indices().get(); + const auto& cv_idx = db.get_index().indices().get(); auto cv = cv_idx.find(boost::make_tuple(comment.id, db.get_account(op.voter).id)); - const auto &rep_idx = db.get_index().indices().get(); + const auto& rep_idx = db.get_index().indices().get(); auto voter_rep = rep_idx.find(op.voter); auto author_rep = rep_idx.find(op.author); @@ -265,7 +265,7 @@ namespace golos { return; } - db.create([&](reputation_object &r) { + db.create([&](reputation_object& r) { r.account = op.author; r.reputation = (cv->rshares >> 6); // Shift away precision from vests. It is noise }); @@ -276,7 +276,7 @@ namespace golos { return; } - db.modify(*author_rep, [&](reputation_object &r) { + db.modify(*author_rep, [&](reputation_object& r) { r.reputation += (cv->rshares >> 6); // Shift away precision from vests. It is noise }); } @@ -284,7 +284,7 @@ namespace golos { } }; - inline void set_what(std::vector &what, uint16_t bitmask) { + inline void set_what(std::vector& what, uint16_t bitmask) { if (bitmask & 1 << blog) { what.push_back(blog); } @@ -307,7 +307,7 @@ namespace golos { ~impl() { }; - void plugin_initialize(plugin &self) { + void plugin_initialize(plugin& self) { // Each plugin needs its own evaluator registry. _custom_operation_interpreter = std::make_shared< generic_custom_operation_interpreter>(database()); @@ -315,27 +315,28 @@ namespace golos { // Add each operation evaluator to the registry _custom_operation_interpreter->register_evaluator(&self); _custom_operation_interpreter->register_evaluator(&self); + _custom_operation_interpreter->register_evaluator(&self); // Add the registry to the database so the database can delegate custom ops to the plugin database().set_custom_operation_interpreter(plugin_name, _custom_operation_interpreter); } - golos::chain::database &database() { + golos::chain::database& database() { return database_; } - void pre_operation(const operation_notification &op_obj, plugin &self) { + void pre_operation(const operation_notification& op_obj, plugin& self) { try { op_obj.op.visit(pre_operation_visitor(self, database())); - } catch (const fc::assert_exception &) { + } catch (const fc::assert_exception&) { if (database().is_producing()) { throw; } } } - void post_operation(const operation_notification &op_obj, plugin &self) { + void post_operation(const operation_notification& op_obj, plugin& self) { try { op_obj.op.visit(post_operation_visitor(self, database())); } catch (fc::assert_exception) { @@ -388,7 +389,7 @@ namespace golos { blog_authors_r get_blog_authors(account_name_type ); - golos::chain::database &database_; + golos::chain::database& database_; uint32_t max_feed_size_ = 500; @@ -402,25 +403,25 @@ namespace golos { } - void plugin::set_program_options(boost::program_options::options_description &cli, - boost::program_options::options_description &cfg) { + void plugin::set_program_options(boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) { cli.add_options() ("follow-max-feed-size", boost::program_options::value()->default_value(500), "Set the maximum size of cached feed for an account"); cfg.add(cli); } - void plugin::plugin_initialize(const boost::program_options::variables_map &options) { + void plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { ilog("Intializing follow plugin"); pimpl.reset(new impl()); - auto &db = pimpl->database(); + auto& db = pimpl->database(); pimpl->plugin_initialize(*this); - db.pre_apply_operation.connect([&](operation_notification &o) { + db.pre_apply_operation.connect([&](operation_notification& o) { pimpl->pre_operation(o, *this); }); - db.post_apply_operation.connect([&](const operation_notification &o) { + db.post_apply_operation.connect([&](const operation_notification& o) { pimpl->post_operation(o, *this); }); golos::chain::add_plugin_index(db); @@ -461,7 +462,7 @@ namespace golos { std::vector result; result.reserve(limit); - const auto &idx = database().get_index().indices().get(); + const auto& idx = database().get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(account, start)); while (itr != idx.end() && result.size() < limit && itr->following == account) { if (type == undefined || itr->what & (1 << type)) { @@ -486,7 +487,7 @@ namespace golos { GOLOS_CHECK_LIMIT_PARAM(limit, 100); std::vector result; - const auto &idx = database().get_index().indices().get(); + const auto& idx = database().get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(account, start)); while (itr != idx.end() && result.size() < limit && itr->follower == account) { if (type == undefined || itr->what & (1 << type)) { @@ -529,19 +530,19 @@ namespace golos { std::vector result; result.reserve(limit); - const auto &db = database(); - const auto &feed_idx = db.get_index().indices().get(); + const auto& db = database(); + const auto& feed_idx = db.get_index().indices().get(); auto itr = feed_idx.lower_bound(boost::make_tuple(account, entry_id)); while (itr != feed_idx.end() && itr->account == account && result.size() < limit) { - const auto &comment = db.get(itr->comment); + const auto& comment = db.get(itr->comment); feed_entry entry; entry.author = comment.author; entry.permlink = to_string(comment.permlink); entry.entry_id = itr->account_feed_id; if (itr->first_reblogged_by != account_name_type()) { entry.reblog_by.reserve(itr->reblogged_by.size()); - for (const auto &a : itr->reblogged_by) { + for (const auto& a : itr->reblogged_by) { entry.reblog_by.push_back(a); } //entry.reblog_by = itr->first_reblogged_by; @@ -568,19 +569,19 @@ namespace golos { std::vector result; result.reserve(limit); - const auto &db = database(); - const auto &feed_idx = db.get_index().indices().get(); + const auto& db = database(); + const auto& feed_idx = db.get_index().indices().get(); auto itr = feed_idx.lower_bound(boost::make_tuple(account, entry_id)); - while (itr != feed_idx.end() && itr->account == account && result.size() < limit) { - const auto &comment = db.get(itr->comment); + while (itr != feed_idx.end() /*&& itr->account == account*/ && result.size() < limit) { + const auto& comment = db.get(itr->comment); comment_feed_entry entry; entry.comment = helper->create_comment_api_object(comment); entry.entry_id = itr->account_feed_id; if (itr->first_reblogged_by != account_name_type()) { //entry.reblog_by = itr->first_reblogged_by; entry.reblog_by.reserve(itr->reblogged_by.size()); - for (const auto &a : itr->reblogged_by) { + for (const auto& a : itr->reblogged_by) { entry.reblog_by.push_back(a); } entry.reblog_on = itr->first_reblogged_on; @@ -606,12 +607,12 @@ namespace golos { std::vector result; result.reserve(limit); - const auto &db = database(); - const auto &blog_idx = db.get_index().indices().get(); + const auto& db = database(); + const auto& blog_idx = db.get_index().indices().get(); auto itr = blog_idx.lower_bound(boost::make_tuple(account, entry_id)); while (itr != blog_idx.end() && itr->account == account && result.size() < limit) { - const auto &comment = db.get(itr->comment); + const auto& comment = db.get(itr->comment); blog_entry entry; entry.author = comment.author; entry.permlink = to_string(comment.permlink); @@ -640,12 +641,12 @@ namespace golos { std::vector result; result.reserve(limit); - const auto &db = database(); - const auto &blog_idx = db.get_index().indices().get(); + const auto& db = database(); + const auto& blog_idx = db.get_index().indices().get(); auto itr = blog_idx.lower_bound(boost::make_tuple(account, entry_id)); while (itr != blog_idx.end() && itr->account == account && result.size() < limit) { - const auto &comment = db.get(itr->comment); + const auto& comment = db.get(itr->comment); comment_blog_entry entry; entry.comment = helper->create_comment_api_object(comment); entry.blog = account; @@ -667,7 +668,7 @@ namespace golos { GOLOS_CHECK_PARAM(accounts, GOLOS_CHECK_VALUE(accounts.size() <= 100, "Cannot retrieve more than 100 account reputations at a time.")); - const auto &idx = database().get_index().indices().get(); + const auto& idx = database().get_index().indices().get(); size_t acc_count = accounts.size(); @@ -697,10 +698,10 @@ namespace golos { account_name_type author, std::string permlink ) { - auto &db = database(); + auto& db = database(); std::vector result; - const auto &post = db.get_comment(author, permlink); - const auto &blog_idx = db.get_index(); + const auto& post = db.get_comment(author, permlink); + const auto& blog_idx = db.get_index(); auto itr = blog_idx.lower_bound(post.id); while (itr != blog_idx.end() && itr->comment == post.id && result.size() < 2000) { result.push_back(itr->account); @@ -710,9 +711,9 @@ namespace golos { } blog_authors_r plugin::impl::get_blog_authors(account_name_type blog_account) { - auto &db = database(); + auto& db = database(); blog_authors_r result; - const auto &stats_idx = db.get_index(); + const auto& stats_idx = db.get_index(); auto itr = stats_idx.lower_bound(boost::make_tuple(blog_account)); while (itr != stats_idx.end() && itr->blogger == blog_account && result.size()) { result.emplace_back(itr->guest, itr->count); From 3fa69addbdd8301e3d4f74ec130e93cab79ec250 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 14:23:17 +0700 Subject: [PATCH 227/250] Fix checking of hardfork on update cashout_time. #908 --- libraries/chain/steem_evaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index b32380c99d..b7d74f1cd9 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1540,10 +1540,10 @@ namespace golos { namespace chain { _db.modify(root, [&](comment_object &c) { c.children_abs_rshares += abs_rshares; + if (!_db.has_hardfork(STEEMIT_HARDFORK_0_17__431)) { if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__177) && c.last_payout > fc::time_point_sec::min() ) { - if (!_db.has_hardfork(STEEMIT_HARDFORK_0_17__431)) { c.cashout_time = c.last_payout + STEEMIT_SECOND_CASHOUT_WINDOW; } else { c.cashout_time = fc::time_point_sec(std::min( From 9cef06c979673a45369053aa663b72cd8f5d9dce Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 15:17:52 +0700 Subject: [PATCH 228/250] Increase tags limit to 15. #752 --- plugins/tags/tag_visitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tags/tag_visitor.cpp b/plugins/tags/tag_visitor.cpp index e2944ac184..6597b4c0f2 100644 --- a/plugins/tags/tag_visitor.cpp +++ b/plugins/tags/tag_visitor.cpp @@ -19,7 +19,7 @@ namespace golos { namespace plugins { namespace tags { std::set lower_tags; - std::size_t tag_limit = 5; + std::size_t tag_limit = 15; for (const auto& name : meta.tags) { if (lower_tags.size() > tag_limit) { break; From 93745931336874105ae73dcfa7620f4df86f20f2 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:14:43 +0700 Subject: [PATCH 229/250] Fix timestamp from block in mongodb. #912 --- .../golos/plugins/mongo_db/mongo_db_state.hpp | 6 ++---- plugins/mongo_db/mongo_db_state.cpp | 14 ++++++-------- plugins/mongo_db/mongo_db_writer.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp index 122e6ee301..987814cd1b 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp @@ -84,11 +84,9 @@ namespace mongo_db { result_type operator()(const return_vesting_delegation_operation& op); result_type operator()(const chain_properties_update_operation& op); - void write_global_property_object(const dynamic_global_property_object& dgpo, - const signed_block& current_block, bool history); + void write_global_property_object(const dynamic_global_property_object& dgpo, bool history); - void write_witness_schedule_object(const witness_schedule_object& wso, - const signed_block& current_block, bool history); + void write_witness_schedule_object(const witness_schedule_object& wso, bool history); private: database &db_; diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index dcd4dcbfb6..4679c6e4bd 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -1717,12 +1717,11 @@ namespace mongo_db { } } - void state_writer::write_global_property_object(const dynamic_global_property_object& dgpo, - const signed_block& current_block, bool history) { + void state_writer::write_global_property_object(const dynamic_global_property_object& dgpo, bool history) { try { std::string oid; if (history) { - oid = current_block.timestamp; + oid = state_block.timestamp; } else { oid = MONGO_ID_SINGLE; } @@ -1739,7 +1738,7 @@ namespace mongo_db { format_oid(body, oid); if (history) { - format_value(body, "timestamp", current_block.timestamp); + format_value(body, "timestamp", state_block.timestamp); } format_value(body, "head_block_number", dgpo.head_block_number); format_value(body, "head_block_id", dgpo.head_block_id.str()); @@ -1792,12 +1791,11 @@ namespace mongo_db { } } - void state_writer::write_witness_schedule_object(const witness_schedule_object& wso, - const signed_block& current_block, bool history) { + void state_writer::write_witness_schedule_object(const witness_schedule_object& wso, bool history) { try { std::string oid; if (history) { - oid = current_block.timestamp; + oid = state_block.timestamp; } else { oid = MONGO_ID_SINGLE; } @@ -1814,7 +1812,7 @@ namespace mongo_db { format_oid(body, oid); if (history) { - format_value(body, "timestamp", current_block.timestamp); + format_value(body, "timestamp", state_block.timestamp); } format_value(body, "current_virtual_time", wso.current_virtual_time); format_value(body, "next_shuffle_block_num", wso.next_shuffle_block_num); diff --git a/plugins/mongo_db/mongo_db_writer.cpp b/plugins/mongo_db/mongo_db_writer.cpp index 89bb67d9be..11453a900a 100644 --- a/plugins/mongo_db/mongo_db_writer.cpp +++ b/plugins/mongo_db/mongo_db_writer.cpp @@ -93,17 +93,17 @@ namespace mongo_db { write_raw_block(head_iter->second, virtual_ops[head_iter->first]); } - state_writer st_writer(all_docs, block); + state_writer st_writer(all_docs, head_iter->second); if (store_history_mode_dgp != 0 && (head_iter->second.block_num() % store_history_mode_dgp == 0)) { - st_writer.write_global_property_object(dgp_s[head_iter->first], head_iter->second, true); + st_writer.write_global_property_object(dgp_s[head_iter->first], true); } - st_writer.write_global_property_object(dgp_s[head_iter->first], head_iter->second, false); + st_writer.write_global_property_object(dgp_s[head_iter->first], false); if (store_history_mode_wso != 0 && (head_iter->second.block_num() % store_history_mode_wso == 0)) { - st_writer.write_witness_schedule_object(wso_s[head_iter->first], head_iter->second, true); + st_writer.write_witness_schedule_object(wso_s[head_iter->first], true); } - st_writer.write_witness_schedule_object(wso_s[head_iter->first], head_iter->second, false); + st_writer.write_witness_schedule_object(wso_s[head_iter->first], false); // Parsing all transactions. st_writer writes all results to all_docs From 7e24bac787e90a2d437b7b925f455bcd3d1b7f36 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:16:39 +0700 Subject: [PATCH 230/250] Typo fix in mongodb. #912 --- plugins/mongo_db/mongo_db_state.cpp | 24 ++++++++++++------------ plugins/mongo_db/mongo_db_types.cpp | 10 ++++++---- plugins/mongo_db/mongo_db_writer.cpp | 3 +-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 4679c6e4bd..81fc617d1f 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -351,15 +351,15 @@ namespace mongo_db { std::string band_type; switch (type) { - case post: - band_type = "post"; - break; - case forum: - band_type = "forum"; - break; - case market: - band_type = "market"; - break; + case post: + band_type = "post"; + break; + case forum: + band_type = "forum"; + break; + case market: + band_type = "market"; + break; } auto oid = std::string(band->account).append("/").append(band_type); @@ -763,13 +763,13 @@ namespace mongo_db { auto state_writer::operator()(const delete_comment_operation& op) -> result_type { - std::string author = op.author; + std::string author = op.author; auto comment_oid = std::string(op.author).append("/").append(op.permlink); auto comment_oid_hash = hash_oid(comment_oid); // Will be updated with the following fields. If no one - created with these fields. - auto comment = create_document("comment_object", "_id", comment_oid_hash); + auto comment = create_document("comment_object", "_id", comment_oid_hash); auto& body = comment.doc; @@ -787,7 +787,7 @@ namespace mongo_db { bmi_insert_or_replace(all_docs, std::move(comment)); // Will be updated with removed = true. If no one - nothing to do. - auto comment_vote = create_removal_document("comment_vote_object", "comment", comment_oid_hash); + auto comment_vote = create_removal_document("comment_vote_object", "comment", comment_oid_hash); bmi_insert_or_replace(all_docs, std::move(comment_vote)); } diff --git a/plugins/mongo_db/mongo_db_types.cpp b/plugins/mongo_db/mongo_db_types.cpp index 1d08a1c49f..9750f5ef7d 100644 --- a/plugins/mongo_db/mongo_db_types.cpp +++ b/plugins/mongo_db/mongo_db_types.cpp @@ -5,12 +5,14 @@ namespace plugins { namespace mongo_db { void bmi_insert_or_replace(db_map& bmi, named_document doc) { - auto it = bmi.get().find(std::make_tuple( + auto& idx = bmi.get(); + auto it = idx.find(std::make_tuple( doc.collection_name, doc.key, doc.keyval, doc.is_removal)); - if (it != bmi.get().end()) - bmi.get().erase(it); - bmi.push_back(std::move(doc)); + if (it != idx.end()) { + idx.erase(it); + } + idx.emplace(std::move(doc)); } } } diff --git a/plugins/mongo_db/mongo_db_writer.cpp b/plugins/mongo_db/mongo_db_writer.cpp index 11453a900a..51824fbd98 100644 --- a/plugins/mongo_db/mongo_db_writer.cpp +++ b/plugins/mongo_db/mongo_db_writer.cpp @@ -239,8 +239,7 @@ namespace mongo_db { filter << "_id" << bsoncxx::oid(named_doc.keyval); - mongocxx::model::update_one msg{filter.view(), - view}; + mongocxx::model::update_one msg{filter.view(), view}; msg.upsert(true); formatted_blocks[named_doc.collection_name]->append(msg); } From 7f92d648033416d6fe780cc1c5543e4bec3dc0b3 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:17:08 +0700 Subject: [PATCH 231/250] Add timestamp to mongodb. #912 --- plugins/mongo_db/mongo_db_state.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 81fc617d1f..936d9d20c7 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -465,6 +465,7 @@ namespace mongo_db { format_value(body, "delegatee", delegation.delegatee); format_value(body, "vesting_shares", delegation.vesting_shares); format_value(body, "min_delegation_time", delegation.min_delegation_time); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -527,6 +528,7 @@ namespace mongo_db { format_value(body, "to_approved", escrow.to_approved); format_value(body, "agent_approved", escrow.agent_approved); format_value(body, "disputed", escrow.disputed); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -573,6 +575,7 @@ namespace mongo_db { format_value(body, "title", proposal.title); format_value(body, "memo", proposal.memo); + format_value(body, "timestamp", state_block.timestamp); if (proposal.review_period_time.valid()) { format_value(body, "review_period_time", *(proposal.review_period_time)); @@ -800,6 +803,7 @@ namespace mongo_db { format_value(body, "to", op.to); format_value(body, "amount", op.amount); format_value(body, "memo", op.memo); + format_value(body, "timestamp", state_block.timestamp); std::vector part; auto path = op.memo; @@ -842,6 +846,7 @@ namespace mongo_db { format_value(body, "to", op.to); format_oid(body, "to_id", op.to); format_value(body, "amount", op.amount); + format_value(body, "timestamp", state_block.timestamp); asset amount_gests; amount_gests.amount = op.amount.amount / @@ -858,7 +863,17 @@ namespace mongo_db { } auto state_writer::operator()(const withdraw_vesting_operation& op) -> result_type { + auto doc = create_document("withdraw_vesting", "", ""); + + auto& body = doc.doc; + + format_value(body, "account", op.account); + format_value(body, "vesting_shares", op.vesting_shares); + format_value(body, "timestamp", state_block.timestamp); + format_account(op.account); + + all_docs.push_back(std::move(doc)); } auto state_writer::operator()(const limit_order_create_operation& op) -> result_type { @@ -882,6 +897,7 @@ namespace mongo_db { format_value(body, "orderid", loo.orderid); format_value(body, "for_sale", loo.for_sale); format_value(body, "sell_price", loo.sell_price); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -1073,6 +1089,7 @@ namespace mongo_db { format_value(body, "to_account", std::string(to_account.name)); format_value(body, "percent", wvro.percent); format_value(body, "auto_vest", wvro.auto_vest); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -1105,6 +1122,7 @@ namespace mongo_db { format_value(body, "orderid", loo.orderid); format_value(body, "for_sale", loo.for_sale); format_value(body, "sell_price", loo.sell_price); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -1266,6 +1284,7 @@ namespace mongo_db { format_oid(body, "to_id", op.to); format_value(body, "amount", op.amount); format_value(body, "memo", op.memo); + format_value(body, "timestamp", state_block.timestamp); all_docs.push_back(std::move(doc)); } @@ -1296,6 +1315,7 @@ namespace mongo_db { format_value(body, "request_id", swo.request_id); format_value(body, "amount", op.amount); format_value(body, "complete", swo.complete); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -1450,6 +1470,7 @@ namespace mongo_db { format_value(body, "filled", true); format_value(body, "amount_out", op.amount_out); + format_value(body, "timestamp", state_block.timestamp); body << close_document; @@ -1486,6 +1507,7 @@ namespace mongo_db { format_oid(body, "owner_id", op.owner); format_value(body, "owner", op.owner); format_value(body, "interest", op.interest); + format_value(body, "timestamp", state_block.timestamp); all_docs.push_back(std::move(doc)); } @@ -1512,6 +1534,7 @@ namespace mongo_db { format_value(body, "filled", true); format_value(body, "withdrawn", op.withdrawn); format_value(body, "deposited", op.deposited); + format_value(body, "timestamp", state_block.timestamp); body << close_document; From 331ff2cf976a0ae78d6f5b07f312fdab0fe448b8 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:17:21 +0700 Subject: [PATCH 232/250] Convert proposal operations to string. #912 --- plugins/mongo_db/mongo_db_state.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 936d9d20c7..bd63fee46c 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -583,8 +583,9 @@ namespace mongo_db { if (!proposal.proposed_operations.empty()) { array ops_array; - for (auto& op: proposal.proposed_operations) { - ops_array << op; + auto operations = proposal.operations(); + for (auto& op: operations) { + ops_array << fc::json::to_string(op); } body << "proposed_operations" << ops_array; } From 2ab9cf12bfb2ee7214a50b9daeaee3391a6731c8 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:17:32 +0700 Subject: [PATCH 233/250] Add converting json to bson in mongodb. #912 --- .../include/golos/plugins/mongo_db/mongo_db_types.hpp | 9 +++++++++ plugins/mongo_db/mongo_db_state.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp index 4ffc39451b..3535545437 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp @@ -143,6 +143,15 @@ namespace mongo_db { doc << name << to_string(value); } + inline void format_json(document& doc, const std::string& name, const shared_string& value) { + auto str_value = to_string(value); + try { + doc << name << bsoncxx::from_json(str_value); + } catch (...) { + doc << name << str_value; + } + } + template inline void format_value(document& doc, const std::string& name, const fc::fixed_string& value) { doc << name << static_cast(value); diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index bd63fee46c..37b576ce22 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -128,7 +128,7 @@ namespace mongo_db { if (con_itr != con_idx.end()) { format_value(body, "title", con_itr->title); format_value(body, "body", con_itr->body); - format_value(body, "json_metadata", con_itr->json_metadata); + format_json(body, "json_metadata", con_itr->json_metadata); } } @@ -264,7 +264,7 @@ namespace mongo_db { auto account_metadata = db_.find(account.name); if (account_metadata != nullptr) { - format_value(body, "json_metadata", account_metadata->json_metadata); + format_json(body, "json_metadata", account_metadata->json_metadata); } body << close_document; From 377ecbbc33cd40340349a15cdf2d5d684099ab20 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:17:44 +0700 Subject: [PATCH 234/250] Fix compilation warning in mongodb. #912 --- plugins/mongo_db/mongo_db_operations.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/mongo_db/mongo_db_operations.cpp b/plugins/mongo_db/mongo_db_operations.cpp index bbed9ead64..f65ace3285 100644 --- a/plugins/mongo_db/mongo_db_operations.cpp +++ b/plugins/mongo_db/mongo_db_operations.cpp @@ -695,7 +695,8 @@ namespace mongo_db { } auto operation_writer::operator()(const producer_reward_operation& op) -> result_type { - + result_type body; + return body; } auto operation_writer::operator()(const comment_payout_update_operation& op) -> result_type { From 3ee53d1f1753384ec6ced171b607d07b13f7f8dd Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:18:16 +0700 Subject: [PATCH 235/250] Store date in mongodb. #912 --- .../include/golos/plugins/mongo_db/mongo_db_types.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp index 3535545437..095d950442 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp @@ -136,7 +136,10 @@ namespace mongo_db { } inline void format_value(document& doc, const std::string& name, const fc::time_point_sec& value) { - doc << name << value.to_iso_string(); + doc << name + << bsoncxx::types::b_date{ + std::chrono::milliseconds( + std::chrono::seconds(value.sec_since_epoch()))}; } inline void format_value(document& doc, const std::string& name, const shared_string& value) { From 8fea1c0107ab721f8b081d4bec5aa47135e4ea81 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:18:30 +0700 Subject: [PATCH 236/250] Fix memory allocation in mongodb. #912 --- .../include/golos/plugins/mongo_db/mongo_db_types.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp index 095d950442..ba1d6f10ce 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_types.hpp @@ -74,8 +74,6 @@ namespace mongo_db { void bmi_insert_or_replace(db_map& bmi, named_document doc); - using named_document_ptr = std::unique_ptr; - inline std::string hex_md5(const std::string& input) { uint8_t digest[16]; @@ -92,7 +90,7 @@ namespace mongo_db { } digest_str[sizeof digest_str - 1] = '\0'; - return std::string(bson_strdup (digest_str)); + return std::string(digest_str); } inline std::string hash_oid(const std::string& value) { From 70b1de772b4a04ea64d1339f5a9356653243eb45 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 16:18:40 +0700 Subject: [PATCH 237/250] Change default settings for mongodb. #912 --- plugins/mongo_db/mongo_db_plugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/mongo_db/mongo_db_plugin.cpp b/plugins/mongo_db/mongo_db_plugin.cpp index 712218db67..80bed5b068 100644 --- a/plugins/mongo_db/mongo_db_plugin.cpp +++ b/plugins/mongo_db/mongo_db_plugin.cpp @@ -60,16 +60,16 @@ namespace mongo_db { boost::program_options::value()->default_value("mongodb://127.0.0.1:27017/Golos"), "Mongo DB connection string") ("mongodb-write-raw-blocks", - boost::program_options::value()->default_value(true), + boost::program_options::value()->default_value(false), "Write raw blocks into mongo or not") ("mongodb-write-operations", boost::program_options::value>()->multitoken()->zero_tokens()->composing(), "List of operations to write into mongo") ("mongodb-store-dgp-history", - boost::program_options::value()->default_value(10), + boost::program_options::value()->default_value(100), "Mode of storing global_property_object history for each N block") ("mongodb-store-wso-history", - boost::program_options::value()->default_value(10), + boost::program_options::value()->default_value(100), "Mode of storing witness_schedule_object history for each N block"); cfg.add(cli); } From 541ea01da7bf4bbafb3ed4333ecb0eeeed97c1a3 Mon Sep 17 00:00:00 2001 From: maslenitsa93 Date: Fri, 3 Aug 2018 13:24:51 +0300 Subject: [PATCH 238/250] validate_permlink #751 --- plugins/follow/follow_operations.cpp | 10 ++++++++++ plugins/follow/plugin.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/follow/follow_operations.cpp b/plugins/follow/follow_operations.cpp index be9725e134..e0895975a4 100644 --- a/plugins/follow/follow_operations.cpp +++ b/plugins/follow/follow_operations.cpp @@ -5,6 +5,14 @@ namespace golos { namespace plugins { namespace follow { + /// TODO: after the hardfork, we can rename this method validate_permlink because it is strictily less restrictive than before + /// Issue #56 contains the justificiation for allowing any UTF-8 string to serve as a permlink, content will be grouped by tags + /// going forward. + inline void validate_permlink(const string &permlink) { + GOLOS_CHECK_VALUE(permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH, "permlink is too long"); + GOLOS_CHECK_VALUE(fc::is_utf8(permlink), "permlink not formatted in UTF8"); + } + void follow_operation::validate() const { GOLOS_CHECK_LOGIC(follower != following, logic_errors::cannot_follow_yourself, @@ -15,12 +23,14 @@ namespace golos { GOLOS_CHECK_LOGIC(account != author, logic_errors::cannot_reblog_own_content, "You cannot reblog your own content"); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); } void delete_reblog_operation::validate() const { GOLOS_CHECK_LOGIC(account != author, logic_errors::cannot_delete_reblog_of_own_content, "You cannot delete reblog of your own content"); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); } } diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index a003b9d354..e52f363c69 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -573,7 +573,7 @@ namespace golos { const auto& feed_idx = db.get_index().indices().get(); auto itr = feed_idx.lower_bound(boost::make_tuple(account, entry_id)); - while (itr != feed_idx.end() /*&& itr->account == account*/ && result.size() < limit) { + while (itr != feed_idx.end() && itr->account == account && result.size() < limit) { const auto& comment = db.get(itr->comment); comment_feed_entry entry; entry.comment = helper->create_comment_api_object(comment); From c9e2064653cab8fc9cfe625eddea2e8e8f90d929 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Wed, 11 Jul 2018 12:20:00 +0300 Subject: [PATCH 239/250] Add account_history filter #742 --- .../golos/chain/operation_notification.hpp | 2 +- .../account_history/history_object.hpp | 48 +- .../golos/plugins/account_history/plugin.hpp | 27 +- plugins/account_history/plugin.cpp | 446 ++++++++++++------ plugins/follow/plugin.cpp | 2 +- .../operation_history/history_object.hpp | 2 +- .../plugins/operation_history/plugin.hpp | 1 - .../golos/plugins/tags/discussion_query.hpp | 2 +- tests/common/database_fixture.cpp | 6 - tests/common/database_fixture.hpp | 46 +- tests/plugin_tests/account_history.cpp | 142 +++++- tests/tests/block_tests.cpp | 4 + tests/tests/main.cpp | 9 - thirdparty/fc | 2 +- 14 files changed, 500 insertions(+), 239 deletions(-) diff --git a/libraries/chain/include/golos/chain/operation_notification.hpp b/libraries/chain/include/golos/chain/operation_notification.hpp index 4fd34c5acd..254709e839 100644 --- a/libraries/chain/include/golos/chain/operation_notification.hpp +++ b/libraries/chain/include/golos/chain/operation_notification.hpp @@ -18,7 +18,7 @@ struct operation_notification { uint32_t trx_in_block = 0; uint16_t op_in_trx = 0; uint32_t virtual_op = 0; - const operation &op; + const operation& op; }; } } // golos::chain diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index bce7aa4d82..838ebf0e86 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -35,6 +35,19 @@ namespace golos { namespace plugins { namespace account_history { account_history_object_type = (ACCOUNT_HISTORY_SPACE_ID << 8) }; + enum operation_direction : uint8_t { + any = 0, + sender, + receiver, + dual, + }; + + struct account_history_query final { + fc::optional> select_ops; + fc::optional> filter_ops; + fc::optional direction; + }; + using namespace golos::chain; using namespace chainbase; @@ -43,7 +56,7 @@ namespace golos { namespace plugins { namespace account_history { class account_history_object final: public object { public: template - account_history_object(Constructor &&c, allocator a) { + account_history_object(Constructor&& c, allocator a) { c(*this); } @@ -52,11 +65,19 @@ namespace golos { namespace plugins { namespace account_history { account_name_type account; uint32_t block = 0; uint32_t sequence = 0; + uint8_t op_tag; + operation_direction dir; + operation_id_type op; }; +static_assert(protocol::operation::count() >= 0 && protocol::operation::count() <= 0xFF, + "There are more ops than u8 type can handle. Update op_tag type"); + using account_history_id_type = object_id; + // struct by_direction; + struct by_operation; struct by_location; struct by_account; using account_history_index = multi_index_container< @@ -67,9 +88,23 @@ namespace golos { namespace plugins { namespace account_history { member>, ordered_non_unique< tag, - composite_key< - account_history_object, - member>>, + member>, + ordered_unique< + tag, + composite_key, + member, + member, + member>, + composite_key_compare< + std::less, std::less, std::less, std::greater>>, + // ordered_unique< + // tag, + // composite_key, + // member, + // member>, + // composite_key_compare, std::less, std::greater>>, ordered_unique< tag, composite_key -#include - #include - #include #include - #include #include - #include + namespace golos { namespace plugins { namespace account_history { using namespace chain; - using golos::plugins::operation_history::applied_operation; - - using get_account_history_return_type = std::map; - - using plugins::json_rpc::void_type; using plugins::json_rpc::msg_pack; - using plugins::json_rpc::msg_pack_transfer; - DEFINE_API_ARGS(get_account_history, msg_pack, get_account_history_return_type) + using history_operations = std::map; + + DEFINE_API_ARGS(get_account_history, msg_pack, history_operations) /** * This plugin is designed to track a range of operations by account so that one node @@ -81,11 +73,18 @@ namespace golos { namespace plugins { namespace account_history { DECLARE_API( /** - * Account operations have sequence numbers from 0 to N where N is the most recent operation. This method - * returns operations in the range [from-limit, from] + * Account operations have sequence numbers from 0 to N where N is the most recent operation. + * This method returns operations in the range [from-limit, from] * + * @param account - name of account, which history requested. * @param from - the absolute sequence number, -1 means most recent, limit is the number of operations before from. * @param limit - the maximum number of items that can be queried (0 to 1000], must be less than from + * @param query - filtering query - object with following optional fields: + * { + * select_ops - list of operations to include. special values: ALL, REAL, VIRTUAL. if skipped = ALL + * filter_ops - blacklist. if skipped = empty list (nothing blacklisted) + * dir - direction of operation in relation to account: any, sender, receiver, dual. Experimental + * } */ (get_account_history) ) diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 5c1c8d1a65..c29ebb1a58 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -1,54 +1,69 @@ +#include +#include +#include #include #include - #include +#include -#include -#include +#include -#include -#define STEEM_NAMESPACE_PREFIX "golos::protocol::" +#define ACCOUNT_HISTORY_MAX_LIMIT 1000 +#define GOLOS_OP_NAMESPACE "golos::protocol::" -namespace golos { namespace plugins { namespace account_history { - struct operation_visitor_filter; - void operation_get_impacted_accounts(const operation &op, flat_set &result); +namespace golos { namespace plugins { namespace account_history { using namespace golos::protocol; using namespace golos::chain; -// +namespace bpo = boost::program_options; +using impacted_accounts = fc::flat_map; + +struct operation_visitor_filter; +void operation_get_impacted_accounts(const operation& op, impacted_accounts& result); + + template T dejsonify(const string &s) { return fc::json::from_string(s).as(); } -#define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value)) #define LOAD_VALUE_SET(options, name, container, type) \ if (options.count(name)) { \ const std::vector& ops = options[name].as>(); \ std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &dejsonify); \ } -// + + struct op_name_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + return fc::get_typename::name(); + } + }; struct operation_visitor final { operation_visitor( golos::chain::database& db, const golos::chain::operation_notification& op_note, - std::string op_account) - : database(db), + std::string op_account, + operation_direction dir) + : db(db), note(op_note), - account(op_account){ + account(op_account), + dir(dir) { } using result_type = void; - golos::chain::database& database; + golos::chain::database& db; const golos::chain::operation_notification& note; std::string account; + operation_direction dir; template void operator()(Op &&) const { - const auto& idx = database.get_index().indices().get(); + const auto& idx = db.get_index().indices().get(); auto itr = idx.lower_bound(std::make_tuple(account, uint32_t(-1))); uint32_t sequence = 0; @@ -56,10 +71,12 @@ if (options.count(name)) { \ sequence = itr->sequence + 1; } - database.create([&](account_history_object& history) { + db.create([&](account_history_object& history) { history.block = note.block; history.account = account; history.sequence = sequence; + history.dir = dir; + history.op_tag = note.op.which(); history.op = operation_history::operation_id_type(note.db_id); }); } @@ -67,22 +84,21 @@ if (options.count(name)) { \ struct plugin::plugin_impl final { public: - plugin_impl( ) - : database(appbase::app().get_plugin().db()) { + plugin_impl(): db(appbase::app().get_plugin().db()) { } ~plugin_impl() = default; void erase_old_blocks() { - uint32_t head_block = database.head_block_num(); + uint32_t head_block = db.head_block_num(); if (history_blocks <= head_block) { uint32_t need_block = head_block - history_blocks; - const auto& idx = database.get_index().indices().get(); + const auto& idx = db.get_index().indices().get(); auto it = idx.begin(); while (it != idx.end() && it->block <= need_block) { auto next_it = it; ++next_it; - database.remove(*it); + db.remove(*it); it = next_it; } } @@ -93,60 +109,161 @@ if (options.count(name)) { \ return; } - fc::flat_set impacted; + impacted_accounts impacted; operation_get_impacted_accounts(note.op, impacted); for (const auto& item : impacted) { - auto itr = tracked_accounts.lower_bound(item); + auto itr = tracked_accounts.lower_bound(item.first); if (!tracked_accounts.size() || - (itr != tracked_accounts.end() && itr->first <= item && item <= itr->second) + (itr != tracked_accounts.end() && itr->first <= item.first && item.first <= itr->second) ) { - note.op.visit(operation_visitor(database, note, item)); + note.op.visit(operation_visitor(db, note, item.first, item.second)); + } + } + } + + /////////////////////////////////////////////////////// + // API + history_operations fetch_unfiltered(string account, uint32_t from, uint32_t limit) { + history_operations result; + const auto& idx = db.get_index().indices().get(); + auto itr = idx.lower_bound(std::make_tuple(account, from)); + auto end = idx.upper_bound(std::make_tuple(account, std::max(int64_t(0), int64_t(itr->sequence) - limit))); + for (; itr != end; ++itr) { + result[itr->sequence] = db.get(itr->op); + } + return result; + } + + using op_tag_type = int; + using op_tags = fc::flat_set; + using op_names = fc::flat_set; + + op_tags op_names_to_tags(op_names names) { + op_tags result; + for (const auto& n: names) { + int from = 0, to = 0; + if (n == "ALL") { + to = operation::count(); + } else if (n == "REAL") { + to = virtual_op_tag; + } else if (n == "VIRTUAL") { + from = virtual_op_tag; + to = operation::count(); + } + if (to > 0) { + for (; from < to; from++) { + result.insert(from); + } + } else { + GOLOS_CHECK_VALUE(op_name2tag.count(n), "Unknown operation: ${o}", ("o",n)); + result.insert(op_name2tag[n]); } } + return result; } + bool is_all_ops(op_tags x) { + return x.size() == operation::count(); + } + + struct sequenced_itr { + // TODO: if possible, change this decltypes to something more readable + using op_idx_type = decltype(database().get_index().indices().get()); + using op_itr_type = decltype( + database().get_index().indices().get() + .lower_bound(std::make_tuple("",uint8_t(0),operation_direction::any,uint32_t(0)))); + + op_itr_type itr; + + sequenced_itr(op_idx_type idx, account_name_type a, uint8_t o, operation_direction d, uint32_t s) { + itr = idx.lower_bound(std::make_tuple(a, o, d, s)); + } + + // reconstruct to put next value into queue (can't reuse previous because const in queue) + sequenced_itr(op_itr_type itr): itr(itr) { + } + + bool operator<(const sequenced_itr& other) const { + return itr->sequence < other.itr->sequence; + } + }; - std::map get_account_history( + history_operations get_account_history( std::string account, - uint64_t from, - uint32_t limit + uint32_t from, + uint32_t limit, + account_history_query query ) { - GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, 10000)); + GOLOS_CHECK_LIMIT_PARAM(limit, ACCOUNT_HISTORY_MAX_LIMIT); GOLOS_CHECK_PARAM(from, GOLOS_CHECK_VALUE(from >= limit, "From must be greater then limit")); - // idump((account)(from)(limit)); - const auto& idx = database.get_index().indices().get(); - auto itr = idx.lower_bound(std::make_tuple(account, from)); - // if( itr != idx.end() ) idump((*itr)); - auto end = idx.upper_bound(std::make_tuple(account, std::max(int64_t(0), int64_t(itr->sequence) - limit))); - // if( end != idx.end() ) idump((*end)); + op_tags select_ops; + GOLOS_CHECK_PARAM(query, { + select_ops = op_names_to_tags(query.select_ops ? *query.select_ops : op_names({"ALL"})); + auto filter_ops = op_names_to_tags(query.filter_ops ? *query.filter_ops : op_names({})); + for (auto t: filter_ops) { + select_ops.erase(t); + } + GOLOS_CHECK_VALUE(!select_ops.empty(), "Query contains no operations to select"); + }); + auto dir = query.direction ? *query.direction : operation_direction::any; - std::map result; - for (; itr != end; ++itr) { - result[itr->sequence] = database.get(itr->op); + if (is_all_ops(select_ops) && dir == operation_direction::any) { + return fetch_unfiltered(account, from, limit); + } + std::priority_queue itrs; + const auto& idx = db.get_index().indices().get(); + const auto& end = idx.end(); + + auto put_itr = [&](op_tag_type o, operation_direction d, bool force = false) { + if (force || operation_direction::any == dir || d == dir) { + auto i = sequenced_itr(idx, account, uint8_t(o), d, from); + if (i.itr != end && i.itr->op_tag == o && i.itr->dir == d) + itrs.push(i); + } + }; + for (const auto o: select_ops) { + put_itr(o, operation_direction::sender); + put_itr(o, operation_direction::receiver); + put_itr(o, operation_direction::dual, dir == sender || dir == receiver); + } + + history_operations result; + while (!itrs.empty() && result.size() <= limit) { + auto itr = itrs.top().itr; + itrs.pop(); + result[itr->sequence] = db.get(itr->op); + auto o = itr->op_tag; + auto d = itr->dir; + auto next = sequenced_itr(++itr); + if (next.itr != end && next.itr->op_tag == o && next.itr->dir == d) + itrs.push(next); } return result; } + op_tag_type virtual_op_tag = -1; // all operations >= this value are virtual + fc::flat_map op_name2tag; fc::flat_map tracked_accounts; - golos::chain::database& database; + golos::chain::database& db; uint32_t history_blocks = UINT32_MAX; }; DEFINE_API(plugin, get_account_history) { - GOLOS_CHECK_ARGS_COUNT(args.args, 3); - GOLOS_DECLARE_PARAM(account, args.args->at(0).as()); - GOLOS_DECLARE_PARAM(from, args.args->at(1).as()); - GOLOS_DECLARE_PARAM(limit, args.args->at(2).as()); - - return pimpl->database.with_weak_read_lock([&]() { - return pimpl->get_account_history(account, from, limit); + PLUGIN_API_VALIDATE_ARGS( + (account_name_type, account) + (uint32_t, from, 0xFFFFFFFF) + (uint32_t, limit, 100) + (account_history_query, query, account_history_query()) + ); + return pimpl->db.with_weak_read_lock([&]() { + return pimpl->get_account_history(account, from, limit, query); }); } struct get_impacted_account_visitor final { - fc::flat_set& impacted; + impacted_accounts& impacted; - get_impacted_account_visitor(fc::flat_set& impact) + get_impacted_account_visitor(impacted_accounts& impact) : impacted(impact) { } @@ -154,251 +271,285 @@ if (options.count(name)) { \ template void operator()(const T& op) { - op.get_required_posting_authorities(impacted); - op.get_required_active_authorities(impacted); - op.get_required_owner_authorities(impacted); + fc::flat_set impd; + op.get_required_posting_authorities(impd); + op.get_required_active_authorities(impd); + op.get_required_owner_authorities(impd); + for (auto i : impd) { + impacted.insert(make_pair(i, operation_direction::dual)); + } } void operator()(const account_create_operation& op) { - impacted.insert(op.new_account_name); - impacted.insert(op.creator); + impacted.insert(make_pair(op.new_account_name, operation_direction::receiver)); + impacted.insert(make_pair(op.creator, operation_direction::sender)); } void operator()(const account_create_with_delegation_operation& op) { - impacted.insert(op.new_account_name); - impacted.insert(op.creator); + impacted.insert(make_pair(op.new_account_name, operation_direction::receiver)); + impacted.insert(make_pair(op.creator, operation_direction::sender)); } void operator()(const account_update_operation& op) { - impacted.insert(op.account); + impacted.insert(make_pair(op.account, operation_direction::dual)); } void operator()(const account_metadata_operation& op) { - impacted.insert(op.account); + impacted.insert(make_pair(op.account, operation_direction::dual)); } void operator()(const comment_operation& op) { - impacted.insert(op.author); - if (op.parent_author.size()) { - impacted.insert(op.parent_author); + if (op.author == op.parent_author) { + impacted.insert(make_pair(op.author, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.author, operation_direction::sender)); + if (op.parent_author.size()) { + impacted.insert(make_pair(op.parent_author, operation_direction::receiver)); + } } } void operator()(const delete_comment_operation& op) { - impacted.insert(op.author); + impacted.insert(make_pair(op.author, operation_direction::dual)); } void operator()(const vote_operation& op) { - impacted.insert(op.voter); - impacted.insert(op.author); + if (op.voter == op.author) { + impacted.insert(make_pair(op.voter, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.voter, operation_direction::sender)); + impacted.insert(make_pair(op.author, operation_direction::receiver)); + } } void operator()(const author_reward_operation& op) { - impacted.insert(op.author); + impacted.insert(make_pair(op.author, operation_direction::receiver)); } void operator()(const curation_reward_operation& op) { - impacted.insert(op.curator); + impacted.insert(make_pair(op.curator, operation_direction::receiver)); } void operator()(const liquidity_reward_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const interest_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const fill_convert_request_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); + } + + template + void insert_from_to_direction(const op_type& op) { + if (op.from == op.to) { + impacted.insert(make_pair(op.to, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.from, operation_direction::sender)); + impacted.insert(make_pair(op.to, operation_direction::receiver)); + } } void operator()(const transfer_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); + insert_from_to_direction(op); } void operator()(const transfer_to_vesting_operation& op) { - impacted.insert(op.from); - - if (op.to != golos::chain::account_name_type() && op.to != op.from) { - impacted.insert(op.to); + if (op.from == op.to) { + impacted.insert(make_pair(op.to, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.from, operation_direction::sender)); + if (op.to != golos::chain::account_name_type() && op.to != op.from) { + impacted.insert(make_pair(op.from, operation_direction::receiver)); + } } } void operator()(const withdraw_vesting_operation& op) { - impacted.insert(op.account); + impacted.insert(make_pair(op.account, operation_direction::dual)); } void operator()(const witness_update_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const account_witness_vote_operation& op) { - impacted.insert(op.account); - impacted.insert(op.witness); + impacted.insert(make_pair(op.account, operation_direction::sender)); + impacted.insert(make_pair(op.witness, operation_direction::receiver)); } void operator()(const account_witness_proxy_operation& op) { - impacted.insert(op.account); - impacted.insert(op.proxy); + impacted.insert(make_pair(op.account, operation_direction::sender)); + impacted.insert(make_pair(op.proxy, operation_direction::receiver)); } void operator()(const feed_publish_operation& op) { - impacted.insert(op.publisher); + impacted.insert(make_pair(op.publisher, operation_direction::dual)); } void operator()(const limit_order_create_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const fill_order_operation& op) { - impacted.insert(op.current_owner); - impacted.insert(op.open_owner); + impacted.insert(make_pair(op.current_owner, operation_direction::sender)); + impacted.insert(make_pair(op.open_owner, operation_direction::receiver)); } void operator()(const limit_order_cancel_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const pow_operation& op) { - impacted.insert(op.worker_account); + impacted.insert(make_pair(op.worker_account, operation_direction::dual)); } void operator()(const fill_vesting_withdraw_operation& op) { - impacted.insert(op.from_account); - impacted.insert(op.to_account); + if (op.from_account == op.to_account) { + impacted.insert(make_pair(op.to_account, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.from_account, operation_direction::sender)); + impacted.insert(make_pair(op.to_account, operation_direction::receiver)); + } } void operator()(const shutdown_witness_operation& op) { - impacted.insert(op.owner); + impacted.insert(make_pair(op.owner, operation_direction::dual)); } void operator()(const custom_operation& op) { for (auto& s: op.required_auths) { - impacted.insert(s); + impacted.insert(make_pair(s, operation_direction::dual)); } } void operator()(const request_account_recovery_operation& op) { - impacted.insert(op.account_to_recover); + impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); } void operator()(const recover_account_operation& op) { - impacted.insert(op.account_to_recover); + impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); } void operator()(const change_recovery_account_operation& op) { - impacted.insert(op.account_to_recover); + impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); + impacted.insert(make_pair(op.new_recovery_account, operation_direction::dual)); + } + + template + void insert_from_to_agent_direction(const Op& op) { + impacted.insert(make_pair(op.from, operation_direction::sender)); + impacted.insert(make_pair(op.to, operation_direction::receiver)); + impacted.insert(make_pair(op.agent, operation_direction::receiver)); } void operator()(const escrow_transfer_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); - impacted.insert(op.agent); + insert_from_to_agent_direction(op); } void operator()(const escrow_approve_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); - impacted.insert(op.agent); + insert_from_to_agent_direction(op); } void operator()(const escrow_dispute_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); - impacted.insert(op.agent); + insert_from_to_agent_direction(op); } void operator()(const escrow_release_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); - impacted.insert(op.agent); + insert_from_to_agent_direction(op); } void operator()(const transfer_to_savings_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); + insert_from_to_direction(op); } void operator()(const transfer_from_savings_operation& op) { - impacted.insert(op.from); - impacted.insert(op.to); + insert_from_to_direction(op); } void operator()(const cancel_transfer_from_savings_operation& op) { - impacted.insert(op.from); + impacted.insert(make_pair(op.from, operation_direction::dual)); } void operator()(const decline_voting_rights_operation& op) { - impacted.insert(op.account); + impacted.insert(make_pair(op.account, operation_direction::dual)); } void operator()(const comment_benefactor_reward_operation& op) { - impacted.insert(op.benefactor); - impacted.insert(op.author); + if (op.benefactor == op.author) { + impacted.insert(make_pair(op.author, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.benefactor, operation_direction::receiver)); + impacted.insert(make_pair(op.author, operation_direction::sender)); + } } void operator()(const producer_reward_operation& op) { - impacted.insert(op.producer); + impacted.insert(make_pair(op.producer, operation_direction::receiver)); } void operator()(const delegate_vesting_shares_operation& op) { - impacted.insert(op.delegator); - impacted.insert(op.delegatee); + impacted.insert(make_pair(op.delegator, operation_direction::sender)); + impacted.insert(make_pair(op.delegatee, operation_direction::receiver)); } void operator()(const return_vesting_delegation_operation& op) { - impacted.insert(op.account); + impacted.insert(make_pair(op.account, operation_direction::receiver)); } void operator()(const proposal_create_operation& op) { - impacted.insert(op.author); + impacted.insert(make_pair(op.author, operation_direction::dual)); } void operator()(const proposal_update_operation& op) { - impacted.insert(op.active_approvals_to_add.begin(), op.active_approvals_to_add.end()); - impacted.insert(op.owner_approvals_to_add.begin(), op.owner_approvals_to_add.end()); - impacted.insert(op.posting_approvals_to_add.begin(), op.posting_approvals_to_add.end()); - impacted.insert(op.active_approvals_to_remove.begin(), op.active_approvals_to_remove.end()); - impacted.insert(op.owner_approvals_to_remove.begin(), op.owner_approvals_to_remove.end()); - impacted.insert(op.posting_approvals_to_remove.begin(), op.posting_approvals_to_remove.end()); + auto insert_fn = [this](const fc::flat_set& impd) { + for (auto i : impd) { + impacted.insert(make_pair(i, operation_direction::dual)); + } + }; + insert_fn(op.active_approvals_to_add); + insert_fn(op.owner_approvals_to_add); + insert_fn(op.posting_approvals_to_add); + insert_fn(op.active_approvals_to_remove); + insert_fn(op.owner_approvals_to_remove); + insert_fn(op.posting_approvals_to_remove); } void operator()(const proposal_delete_operation& op) { - impacted.insert(op.requester); + if (op.author == op.requester) { + impacted.insert(make_pair(op.author, operation_direction::dual)); + } else { + impacted.insert(make_pair(op.author, operation_direction::receiver)); + impacted.insert(make_pair(op.requester, operation_direction::sender)); + } } - //void operator()( const operation& op ){} }; - void operation_get_impacted_accounts( - const operation& op, fc::flat_set& result - ) { + void operation_get_impacted_accounts(const operation& op, impacted_accounts& result) { get_impacted_account_visitor vtor = get_impacted_account_visitor(result); op.visit(vtor); } - void plugin::set_program_options( - boost::program_options::options_description& cli, - boost::program_options::options_description& cfg - ) { + void plugin::set_program_options(bpo::options_description& cli, bpo::options_description& cfg) { cli.add_options()( "track-account-range", - boost::program_options::value>()->composing()->multitoken(), + bpo::value>()->composing()->multitoken(), "Defines a range of accounts to track as a json pair [\"from\",\"to\"] [from,to]. " "Can be specified multiple times" ); cfg.add(cli); } - void plugin::plugin_initialize(const boost::program_options::variables_map& options) { + void plugin::plugin_initialize(const bpo::variables_map& options) { ilog("account_history plugin: plugin_initialize() begin"); pimpl = std::make_unique(); if (options.count("history-blocks")) { uint32_t history_blocks = options.at("history-blocks").as(); pimpl->history_blocks = history_blocks; - pimpl->database.applied_block.connect([&](const signed_block& block){ + pimpl->db.applied_block.connect([&](const signed_block& block){ pimpl->erase_old_blocks(); }); } else { @@ -407,17 +558,34 @@ if (options.count(name)) { \ ilog("account_history: history-blocks ${s}", ("s", pimpl->history_blocks)); // this is worked, because the appbase initialize required plugins at first - pimpl->database.pre_apply_operation.connect([&](golos::chain::operation_notification& note){ + pimpl->db.pre_apply_operation.connect([&](operation_notification& note) { pimpl->on_operation(note); }); - golos::chain::add_plugin_index(pimpl->database); + add_plugin_index(pimpl->db); using pairstring = std::pair; LOAD_VALUE_SET(options, "track-account-range", pimpl->tracked_accounts, pairstring); ilog("account_history: tracked_accounts ${s}", ("s", pimpl->tracked_accounts)); + // prepare map to convert operation name to operation tag + pimpl->op_name2tag = {}; + op_name_visitor nvisit; + operation op; + auto count = operation::count(); + for (auto i = 0; i < count; i++) { + op.set_which(i); + auto name = op.visit(nvisit); + name = name.substr(sizeof(GOLOS_OP_NAMESPACE) - 1); // cut "golos::protocol::" + pimpl->op_name2tag[name] = i; + name = name.substr(0, name.size() + 1 - sizeof("_operation")); // support names without "_operation" too + pimpl->op_name2tag[name] = i; + if (pimpl->virtual_op_tag == -1 && is_virtual_operation(op)) { + pimpl->virtual_op_tag = i; + } + } + JSON_RPC_REGISTER_API(name()); ilog("account_history plugin: plugin_initialize() end"); } diff --git a/plugins/follow/plugin.cpp b/plugins/follow/plugin.cpp index e52f363c69..161eff7cd1 100644 --- a/plugins/follow/plugin.cpp +++ b/plugins/follow/plugin.cpp @@ -665,7 +665,7 @@ namespace golos { std::vector < account_name_type > accounts ) { - GOLOS_CHECK_PARAM(accounts, + GOLOS_CHECK_PARAM(accounts, GOLOS_CHECK_VALUE(accounts.size() <= 100, "Cannot retrieve more than 100 account reputations at a time.")); const auto& idx = database().get_index().indices().get(); diff --git a/plugins/operation_history/include/golos/plugins/operation_history/history_object.hpp b/plugins/operation_history/include/golos/plugins/operation_history/history_object.hpp index 4cdf867455..c23d2858b2 100644 --- a/plugins/operation_history/include/golos/plugins/operation_history/history_object.hpp +++ b/plugins/operation_history/include/golos/plugins/operation_history/history_object.hpp @@ -29,7 +29,7 @@ namespace golos { namespace plugins { namespace operation_history { - enum account_object_types { + enum operation_object_types { operation_object_type = (OPERATION_HISTORY_SPACE_ID << 8), }; diff --git a/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp b/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp index a20facd76a..662f90fa99 100644 --- a/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp +++ b/plugins/operation_history/include/golos/plugins/operation_history/plugin.hpp @@ -79,7 +79,6 @@ namespace golos { namespace plugins { namespace operation_history { (get_ops_in_block) (get_transaction) - ) private: struct plugin_impl; diff --git a/plugins/tags/include/golos/plugins/tags/discussion_query.hpp b/plugins/tags/include/golos/plugins/tags/discussion_query.hpp index b01a48d8ef..7bac1eccd4 100644 --- a/plugins/tags/include/golos/plugins/tags/discussion_query.hpp +++ b/plugins/tags/include/golos/plugins/tags/discussion_query.hpp @@ -25,7 +25,7 @@ namespace golos { namespace plugins { namespace tags { using golos::chain::comment_object; using golos::api::comment_api_object; using golos::api::discussion; - + /** * @class discussion_query * @brief The discussion_query structure implements the RPC API param set. diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 6432d3844a..9bd6b8b0e2 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -328,12 +328,6 @@ namespace golos { namespace chain { return fc::ecc::private_key::regenerate(fc::sha256::hash(seed)); } - string database_fixture::generate_anon_acct_name() { - // names of the form "anon-acct-x123" ; the "x" is necessary - // to workaround issue #46 - return "anon-acct-x" + std::to_string(anon_acct_count++); - } - void database_fixture::startup(bool generate_hardfork) { generate_block(); if (generate_hardfork) { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 57a76eaafd..1004f9085e 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -17,48 +17,11 @@ #define INITIAL_TEST_SUPPLY (10000000000ll) -extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); +extern uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP; -#define PUSH_TX \ - golos::chain::test::_push_transaction - -#define PUSH_BLOCK \ - golos::chain::test::_push_block - -// See below -#define REQUIRE_OP_VALIDATION_SUCCESS(op, field, value) { \ - const auto temp = op.field; \ - op.field = value; \ - op.validate(); \ - op.field = temp; \ -} -#define REQUIRE_OP_EVALUATION_SUCCESS(op, field, value) { \ - const auto temp = op.field; \ - op.field = value; \ - trx.operations.back() = op; \ - op.field = temp; \ - db.push_transaction( trx, ~0 ); \ -} - -/*#define STEEMIT_REQUIRE_THROW( expr, exc_type ) { \ - std::string req_throw_info = fc::json::to_string( \ - fc::mutable_variant_object() \ - ("source_file", __FILE__) \ - ("source_lineno", __LINE__) \ - ("expr", #expr) \ - ("exc_type", #exc_type) \ - ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "STEEMIT_REQUIRE_THROW begin " \ - << req_throw_info << std::endl; \ - BOOST_REQUIRE_THROW( expr, exc_type ); \ - if( fc::enable_record_assert_trip ) \ - std::cout << "STEEMIT_REQUIRE_THROW end " \ - << req_throw_info << std::endl; \ -}*/ #define STEEMIT_REQUIRE_THROW(expr, exc_type) \ - BOOST_REQUIRE_THROW( expr, exc_type ); + BOOST_REQUIRE_THROW(expr, exc_type); #define STEEMIT_CHECK_THROW(expr, exc_type) { \ std::string req_throw_info = fc::json::to_string( \ @@ -464,8 +427,6 @@ namespace golos { namespace chain { optional data_dir; bool skip_key_index_test = false; - uint32_t anon_acct_count; - database_fixture() { } @@ -473,8 +434,6 @@ namespace golos { namespace chain { static fc::ecc::private_key generate_private_key(string seed); - string generate_anon_acct_name(); - template Plugin* find_plugin() { return dynamic_cast(appbase::app().find_plugin()); @@ -685,7 +644,6 @@ namespace golos { namespace chain { } operations_map add_operations(); - operation_history_plugin* oh_plugin = nullptr; }; diff --git a/tests/plugin_tests/account_history.cpp b/tests/plugin_tests/account_history.cpp index 394a7ac403..001c5420ac 100644 --- a/tests/plugin_tests/account_history.cpp +++ b/tests/plugin_tests/account_history.cpp @@ -1,40 +1,36 @@ -#include -#include - #include -#include +#include #include "database_fixture.hpp" -#include "comment_reward.hpp" -using golos::chain::account_name_set; +using namespace golos::chain; using golos::plugins::json_rpc::msg_pack; +using golos::plugins::operation_history::applied_operation; +using namespace golos::plugins::account_history; -struct account_history_fixture : public golos::chain::add_operations_database_fixture { - typedef std::map> checked_accounts_map; ///< pair { [block], [account names] } +struct account_history_fixture : public add_operations_database_fixture { + using checked_accounts_map = std::map>; // pair { [block], [[account names] operations]} checked_accounts_map check(const account_name_set& names) { - uint32_t head_block_num = db->head_block_num(); - ilog("Check history accounts, block num is " + std::to_string(head_block_num)); - checked_accounts_map _founded_accs; + checked_accounts_map _found_accs; for (auto n : names) { msg_pack mp; mp.args = std::vector({fc::variant(n), fc::variant(100), fc::variant(100)}); auto accs = ah_plugin->get_account_history(mp); for (auto a : accs) { - auto it = _founded_accs.find(a.second.block); - if (it == _founded_accs.end()) { + auto it = _found_accs.find(a.second.block); + if (it == _found_accs.end()) { std::set set; set.insert(n); - _founded_accs.insert(std::make_pair(a.second.block, set)); + _found_accs.insert(std::make_pair(a.second.block, set)); } else { it->second.insert(n); } } } - return _founded_accs; + return _found_accs; } }; @@ -48,10 +44,10 @@ BOOST_AUTO_TEST_CASE(account_history_blocks) { add_operations(); account_name_set names = {"alice", "bob", "sam", "dave"}; - auto _founded_accs = check(names); + auto _found_accs = check(names); std::set blocks; - for (auto a : _founded_accs) { + for (auto a : _found_accs) { for (auto n : a.second) { ilog("block:" + std::to_string(a.first) + ", \"" + n + "\""); auto iter = names.find(n); @@ -67,4 +63,116 @@ BOOST_AUTO_TEST_CASE(account_history_blocks) { BOOST_CHECK_EQUAL(blocks.size(), HISTORY_BLOCKS); } + +/////////////////////////////////////////////////////////////// +// filtering +/////////////////////////////////////////////////////////////// +struct accounts_filter_fixture : public add_operations_database_fixture { + accounts_filter_fixture() {}; + ~accounts_filter_fixture() {}; +}; + + +struct op_name_visitor { + using result_type = std::string; + template + std::string operator()(const T&) const { + auto n = std::string(fc::get_typename::name()); + auto prefix_len = sizeof("golos::protocol::") - 1; + return n.substr(prefix_len, n.size() - prefix_len + 1 - sizeof("_operation")); + } +}; + +BOOST_AUTO_TEST_CASE(account_history_filter) { + initialize(); + +# define INITIAL_OPS "account_create|transfer|transfer_to_vesting" + using op_names = fc::flat_set; + + auto get_history = [this](const std::string& acc, const int from, const int limit, const account_history_query& q) { + msg_pack mp; + mp.args = std::vector({ + fc::variant(acc), fc::variant(from), fc::variant(limit), fc::variant(q)}); + auto ops = ah_plugin->get_account_history(mp); + return ops; + }; + + BOOST_TEST_MESSAGE("Testing: account_history_filter"); + + // NOTE: this test depends on operations generated with add_operations() + add_operations(); + + auto check_ops = [](const history_operations& ops, const std::string& expected) { + op_name_visitor ovisit; + std::vector chk; + if (!expected.empty()) { + boost::split(chk, expected, boost::is_any_of("|")); + } + BOOST_CHECK_EQUAL(chk.size(), ops.size()); + int i = 0; + for (const auto& o : ops) { + const auto got_op = o.second.op.visit(ovisit); + BOOST_CHECK_EQUAL(got_op, chk[i++]); + } + }; + + auto q = account_history_query(); + BOOST_TEST_MESSAGE("--- Test non-filtered history"); + auto alice_all = get_history("alice", -1, 10, q); + check_ops(alice_all, INITIAL_OPS "|vote"); + + auto bob_all = get_history("bob", -1, 10, q); + check_ops(bob_all, INITIAL_OPS "|comment|vote|vote|vote|delete_comment"); + + auto sam_all = get_history("sam", -1, 10, q); + check_ops(sam_all, INITIAL_OPS "|vote"); + + auto dave_all = get_history("dave", -1, 10, q); + check_ops(dave_all, "account_create"); + + auto cf_all = get_history("cyberfounder", -1, 10, q); + BOOST_CHECK_EQUAL(11, cf_all.size()); + check_ops(cf_all, "account_create|account_create|account_create|transfer|transfer|transfer|" + "producer_reward|producer_reward|producer_reward|account_create|producer_reward"); + + BOOST_TEST_MESSAGE("--- Test 'sender' direction"); + q.direction = operation_direction::sender; + auto bob_sender = get_history("bob", -1, 10, q); + check_ops(bob_sender, "transfer_to_vesting|comment|vote|delete_comment"); + + BOOST_TEST_MESSAGE("--- Test 'receiver' direction"); + q.direction = operation_direction::receiver; + auto dave_receiver = get_history("dave", -1, 10, q); + check_ops(dave_receiver, "account_create"); + + BOOST_TEST_MESSAGE("--- Test 'dual' direction"); + q.direction = operation_direction::dual; + auto bob_dual = get_history("bob", -1, 10, q); + check_ops(bob_dual, "vote|delete_comment"); + + BOOST_TEST_MESSAGE("--- Test virtual only select"); + q.direction = operation_direction::any; + q.select_ops = op_names({"VIRTUAL"}); + auto cf_vops = get_history("cyberfounder", -1, 10, q); + check_ops(cf_vops, "producer_reward|producer_reward|producer_reward|producer_reward|producer_reward|producer_reward"); + + BOOST_TEST_MESSAGE("--- Test virtual select with filtered op"); + q.filter_ops = op_names({"producer_reward_operation"}); + auto cf_vops2 = get_history("cyberfounder", -1, 10, q); + check_ops(cf_vops2, ""); + + BOOST_TEST_MESSAGE("--- Test pagination"); + generate_blocks(3); + q.select_ops = op_names({"REAL", "producer_reward"}); + q.filter_ops = op_names({"account_create", "transfer"}); + auto cf_ops = get_history("cyberfounder", -1, 6, q); + check_ops(cf_ops, "producer_reward|producer_reward|producer_reward|producer_reward|producer_reward|producer_reward|producer_reward"); + for (const auto& i: cf_ops) { + uint32_t page2 = i.first; + auto cf_ops2 = get_history("cyberfounder", page2, std::min(page2, uint32_t(6)), q); + check_ops(cf_ops2, "producer_reward|custom|producer_reward|transfer_to_vesting|producer_reward"); + break; + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 3910c51b06..7c3bb76fb1 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -46,6 +46,10 @@ using namespace golos::plugins; #define TEST_SHARED_MEM_SIZE (1024 * 1024 * 8) +#define PUSH_TX golos::chain::test::_push_transaction +#define PUSH_BLOCK golos::chain::test::_push_block + + BOOST_AUTO_TEST_SUITE(block_tests) BOOST_AUTO_TEST_CASE(generate_empty_blocks) { diff --git a/tests/tests/main.cpp b/tests/tests/main.cpp index eac82a29a8..6a931b5d96 100644 --- a/tests/tests/main.cpp +++ b/tests/tests/main.cpp @@ -32,7 +32,6 @@ #include #endif -// extern uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP; boost::unit_test::test_suite *init_unit_test_suite(int argc, char *argv[]) { fc::configure_logging(fc::logging_config::default_config(fc::log_level::error)); @@ -40,13 +39,5 @@ boost::unit_test::test_suite *init_unit_test_suite(int argc, char *argv[]) { std::srand(time(NULL)); std::cout << "Random number generator seeded to " << time(NULL) << std::endl; -/* - const char* genesis_timestamp_str = getenv("STEEMIT_TESTING_GENESIS_TIMESTAMP"); - if( genesis_timestamp_str != nullptr ) - { - STEEMIT_TESTING_GENESIS_TIMESTAMP = std::stoul( genesis_timestamp_str ); - } - std::cout << "STEEMIT_TESTING_GENESIS_TIMESTAMP is " << STEEMIT_TESTING_GENESIS_TIMESTAMP << std::endl; -*/ return nullptr; } \ No newline at end of file diff --git a/thirdparty/fc b/thirdparty/fc index eec4ed2af9..afa113d86e 160000 --- a/thirdparty/fc +++ b/thirdparty/fc @@ -1 +1 @@ -Subproject commit eec4ed2af95c4a37f4e1bf05c6eb96dfd17d923f +Subproject commit afa113d86e1e7ba91c62e9fe256de921f375b608 From 663180ed3d3e6e64c2fb694fc5f247622041294c Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 3 Aug 2018 20:49:21 +0300 Subject: [PATCH 240/250] Fix social_network clang compilation & remove unused args macro #742 --- .../include/golos/protocol/exceptions.hpp | 10 ---------- .../social_network/social_network_types.hpp | 4 ++-- plugins/social_network/social_network.cpp | 16 ++++++++-------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/libraries/protocol/include/golos/protocol/exceptions.hpp b/libraries/protocol/include/golos/protocol/exceptions.hpp index 158ef231da..15514068ff 100644 --- a/libraries/protocol/include/golos/protocol/exceptions.hpp +++ b/libraries/protocol/include/golos/protocol/exceptions.hpp @@ -116,16 +116,6 @@ #define GOLOS_CHECK_LIMIT_PARAM(limit, max_value) \ GOLOS_CHECK_PARAM(limit, GOLOS_CHECK_LIMIT(limit, max_value)) -#define GOLOS_CHECK_ARGS_COUNT(args, required) \ - GOLOS_ASSERT( (args)->size() == (required), invalid_arguments_count, \ - "Expected ${required} argument(s), was ${count}", \ - ("count", (args)->size())("required", required) ); - -#define GOLOS_CHECK_OPT_ARGS_COUNT(args, min, max) \ - GOLOS_ASSERT( (args)->size() >= (min) && (args)->size() <= max, invalid_arguments_count, \ - "Expected ${min}..${max} argument(s), was ${count}", \ - ("count", (args)->size())("min", min)("max", max) ); - #define GOLOS_THROW_MISSING_OBJECT(type, id, ...) \ FC_THROW_EXCEPTION(golos::missing_object, "Missing ${type} with id \"${id}\"", \ diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp index d49ba998da..de6a8a0d11 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp @@ -2,7 +2,7 @@ namespace golos { namespace plugins { namespace social_network { using namespace golos::chain; - + #ifndef SOCIAL_NETWORK_SPACE_ID #define SOCIAL_NETWORK_SPACE_ID 10 #endif @@ -138,7 +138,7 @@ namespace golos { namespace plugins { namespace social_network { CHAINBASE_SET_INDEX_TYPE( - golos::plugins::social_network::comment_content_object, + golos::plugins::social_network::comment_content_object, golos::plugins::social_network::comment_content_index ) diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 8f5e978bc7..b7c3f87404 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -115,7 +115,7 @@ namespace golos { namespace plugins { namespace social_network { discussion get_content(std::string author, std::string permlink, uint32_t limit) const; discussion get_discussion(const comment_object& c, uint32_t vote_limit) const; - + void set_depth_parameters(const comment_depth_params& params); // Looks for a comment_operation, fills the comment_content state objects. @@ -187,14 +187,14 @@ namespace golos { namespace plugins { namespace social_network { if (set_last_update) { clu.last_update = clu.active; } - }); + }); return true; } else { db.create([&](comment_last_update_object& clu) { clu.comment = comment.id; clu.author = comment.author; clu.parent_author = comment.parent_author; - clu.active = active; + clu.active = active; if (set_last_update) { clu.last_update = clu.active; } @@ -314,7 +314,7 @@ namespace golos { namespace plugins { namespace social_network { // Set depth null if needed (this parameter is given in config) if (dp.set_null_after_update) { con.block_number = db.head_block_num(); - } + } }); } else { // Creation case @@ -323,7 +323,7 @@ namespace golos { namespace plugins { namespace social_network { if (!dp.has_comment_title_depth || dp.comment_title_depth > 0) { from_string(con.title, o.title); } - + if ((!dp.has_comment_body_depth || dp.comment_body_depth > 0) && o.body.size() < 1024*1024*128) { from_string(con.body, o.body); } @@ -382,10 +382,10 @@ namespace golos { namespace plugins { namespace social_network { asset curator_payout_golos = impl.curator_payout_gests * vesting_sp; asset curator_payout_gbg = db.to_sbd(curator_payout_golos); - const auto& cr_idx = db.get_index().indices().get(); + const auto& cr_idx = db.get_index().indices().template get(); auto cr_itr = cr_idx.find(comment.id); if (cr_itr == cr_idx.end()) { - db.create([&](golos::plugins::social_network::comment_reward_object& cr) { + db.create([&](comment_reward_object& cr) { cr.comment = comment.id; cr.author_rewards = author_rewards; cr.author_gbg_payout_value = impl.author_gbg_payout_value; @@ -495,7 +495,7 @@ namespace golos { namespace plugins { namespace social_network { ++itr; auto& comment = db.get_comment(clu.comment); - + auto delta = head_block_num - clu.block_number; if (comment.mode == archived && depth_parameters.should_delete_last_update_object(delta)) { db.remove(clu); From ab9693bc7480a8f15fdb2c6b56967630d6ced63a Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Fri, 3 Aug 2018 23:04:11 +0300 Subject: [PATCH 241/250] Fix ops directions and make impacted visitor less wordy #742 --- plugins/account_history/plugin.cpp | 185 +++++++++++-------------- tests/plugin_tests/account_history.cpp | 2 +- 2 files changed, 85 insertions(+), 102 deletions(-) diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index c29ebb1a58..9f1fff42e2 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -280,250 +280,233 @@ if (options.count(name)) { \ } } + void insert_account(account_name_type a, operation_direction d) { + impacted.insert(make_pair(a, d)); + } + void insert_sender(account_name_type a) { + insert_account(a, operation_direction::sender); + } + void insert_receiver(account_name_type a) { + insert_account(a, operation_direction::receiver); + } + void insert_dual(account_name_type a) { + insert_account(a, operation_direction::dual); + } + + void insert_pair(account_name_type sender, account_name_type receiver, bool have_receiver = true) { + if (sender == receiver) { + insert_dual(sender); + } else { + insert_sender(sender); + if (have_receiver) + insert_receiver(receiver); + } + } + void operator()(const account_create_operation& op) { - impacted.insert(make_pair(op.new_account_name, operation_direction::receiver)); - impacted.insert(make_pair(op.creator, operation_direction::sender)); + insert_pair(op.creator, op.new_account_name); } void operator()(const account_create_with_delegation_operation& op) { - impacted.insert(make_pair(op.new_account_name, operation_direction::receiver)); - impacted.insert(make_pair(op.creator, operation_direction::sender)); + insert_pair(op.creator, op.new_account_name); } void operator()(const account_update_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::dual)); + insert_dual(op.account); } void operator()(const account_metadata_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::dual)); + insert_dual(op.account); } void operator()(const comment_operation& op) { - if (op.author == op.parent_author) { - impacted.insert(make_pair(op.author, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.author, operation_direction::sender)); - if (op.parent_author.size()) { - impacted.insert(make_pair(op.parent_author, operation_direction::receiver)); - } - } + insert_pair(op.author, op.parent_author, op.parent_author.size()); } void operator()(const delete_comment_operation& op) { - impacted.insert(make_pair(op.author, operation_direction::dual)); + insert_dual(op.author); } void operator()(const vote_operation& op) { - if (op.voter == op.author) { - impacted.insert(make_pair(op.voter, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.voter, operation_direction::sender)); - impacted.insert(make_pair(op.author, operation_direction::receiver)); - } + insert_pair(op.voter, op.author); } void operator()(const author_reward_operation& op) { - impacted.insert(make_pair(op.author, operation_direction::receiver)); + insert_receiver(op.author); } void operator()(const curation_reward_operation& op) { - impacted.insert(make_pair(op.curator, operation_direction::receiver)); + insert_receiver(op.curator); } void operator()(const liquidity_reward_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); } void operator()(const interest_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); } void operator()(const fill_convert_request_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); - } - - template - void insert_from_to_direction(const op_type& op) { - if (op.from == op.to) { - impacted.insert(make_pair(op.to, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.from, operation_direction::sender)); - impacted.insert(make_pair(op.to, operation_direction::receiver)); - } + insert_dual(op.owner); } void operator()(const transfer_operation& op) { - insert_from_to_direction(op); + insert_pair(op.from, op.to); } void operator()(const transfer_to_vesting_operation& op) { - if (op.from == op.to) { - impacted.insert(make_pair(op.to, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.from, operation_direction::sender)); - if (op.to != golos::chain::account_name_type() && op.to != op.from) { - impacted.insert(make_pair(op.from, operation_direction::receiver)); - } - } + auto have_to = op.to != account_name_type(); + insert_pair(op.from, have_to ? op.to: op.from); } void operator()(const withdraw_vesting_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::dual)); + insert_dual(op.account); } void operator()(const witness_update_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); + } + + void operator()(const chain_properties_update_operation& op) { + insert_dual(op.owner); } void operator()(const account_witness_vote_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::sender)); - impacted.insert(make_pair(op.witness, operation_direction::receiver)); + insert_pair(op.account, op.witness); } void operator()(const account_witness_proxy_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::sender)); - impacted.insert(make_pair(op.proxy, operation_direction::receiver)); + insert_pair(op.account, op.proxy); } void operator()(const feed_publish_operation& op) { - impacted.insert(make_pair(op.publisher, operation_direction::dual)); + insert_dual(op.publisher); } void operator()(const limit_order_create_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); } void operator()(const fill_order_operation& op) { - impacted.insert(make_pair(op.current_owner, operation_direction::sender)); - impacted.insert(make_pair(op.open_owner, operation_direction::receiver)); + insert_pair(op.current_owner, op.open_owner); } void operator()(const limit_order_cancel_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); } void operator()(const pow_operation& op) { - impacted.insert(make_pair(op.worker_account, operation_direction::dual)); + insert_dual(op.worker_account); } void operator()(const fill_vesting_withdraw_operation& op) { - if (op.from_account == op.to_account) { - impacted.insert(make_pair(op.to_account, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.from_account, operation_direction::sender)); - impacted.insert(make_pair(op.to_account, operation_direction::receiver)); - } + insert_pair(op.from_account, op.to_account); } void operator()(const shutdown_witness_operation& op) { - impacted.insert(make_pair(op.owner, operation_direction::dual)); + insert_dual(op.owner); } void operator()(const custom_operation& op) { for (auto& s: op.required_auths) { - impacted.insert(make_pair(s, operation_direction::dual)); + insert_dual(s); } } void operator()(const request_account_recovery_operation& op) { - impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); + insert_dual(op.account_to_recover); } void operator()(const recover_account_operation& op) { - impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); + insert_dual(op.account_to_recover); } void operator()(const change_recovery_account_operation& op) { - impacted.insert(make_pair(op.account_to_recover, operation_direction::dual)); - impacted.insert(make_pair(op.new_recovery_account, operation_direction::dual)); + insert_pair(op.account_to_recover, op.new_recovery_account); } template void insert_from_to_agent_direction(const Op& op) { - impacted.insert(make_pair(op.from, operation_direction::sender)); - impacted.insert(make_pair(op.to, operation_direction::receiver)); - impacted.insert(make_pair(op.agent, operation_direction::receiver)); + insert_sender(op.from); + insert_receiver(op.to); + insert_receiver(op.agent); } void operator()(const escrow_transfer_operation& op) { insert_from_to_agent_direction(op); } + // note: the initiator (signer) of escrow_approve_operation is who. he can be either to or agent void operator()(const escrow_approve_operation& op) { insert_from_to_agent_direction(op); } + // note: the initiator (signer) of escrow_dispute_operation is who. he can be either from or to void operator()(const escrow_dispute_operation& op) { insert_from_to_agent_direction(op); } + // note: the initiator (signer) of escrow_release_operation is who. he can be either from or to or agent. + // the receiver receives funds, he can be either from or to void operator()(const escrow_release_operation& op) { insert_from_to_agent_direction(op); } void operator()(const transfer_to_savings_operation& op) { - insert_from_to_direction(op); + insert_pair(op.from, op.to); } void operator()(const transfer_from_savings_operation& op) { - insert_from_to_direction(op); + insert_pair(op.from, op.to); } void operator()(const cancel_transfer_from_savings_operation& op) { - impacted.insert(make_pair(op.from, operation_direction::dual)); + insert_dual(op.from); } void operator()(const decline_voting_rights_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::dual)); + insert_dual(op.account); } void operator()(const comment_benefactor_reward_operation& op) { - if (op.benefactor == op.author) { - impacted.insert(make_pair(op.author, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.benefactor, operation_direction::receiver)); - impacted.insert(make_pair(op.author, operation_direction::sender)); - } + insert_pair(op.author, op.benefactor); } void operator()(const producer_reward_operation& op) { - impacted.insert(make_pair(op.producer, operation_direction::receiver)); + insert_receiver(op.producer); } void operator()(const delegate_vesting_shares_operation& op) { - impacted.insert(make_pair(op.delegator, operation_direction::sender)); - impacted.insert(make_pair(op.delegatee, operation_direction::receiver)); + insert_pair(op.delegator, op.delegatee); } void operator()(const return_vesting_delegation_operation& op) { - impacted.insert(make_pair(op.account, operation_direction::receiver)); + insert_receiver(op.account); } + // todo: proposal tx signers are receivers void operator()(const proposal_create_operation& op) { - impacted.insert(make_pair(op.author, operation_direction::dual)); + insert_dual(op.author); } void operator()(const proposal_update_operation& op) { - auto insert_fn = [this](const fc::flat_set& impd) { + insert_receiver(op.author); + auto insert_set = [this](const fc::flat_set& impd) { for (auto i : impd) { - impacted.insert(make_pair(i, operation_direction::dual)); + insert_dual(i); } }; - insert_fn(op.active_approvals_to_add); - insert_fn(op.owner_approvals_to_add); - insert_fn(op.posting_approvals_to_add); - insert_fn(op.active_approvals_to_remove); - insert_fn(op.owner_approvals_to_remove); - insert_fn(op.posting_approvals_to_remove); + insert_set(op.active_approvals_to_add); + insert_set(op.owner_approvals_to_add); + insert_set(op.posting_approvals_to_add); + insert_set(op.active_approvals_to_remove); + insert_set(op.owner_approvals_to_remove); + insert_set(op.posting_approvals_to_remove); } void operator()(const proposal_delete_operation& op) { - if (op.author == op.requester) { - impacted.insert(make_pair(op.author, operation_direction::dual)); - } else { - impacted.insert(make_pair(op.author, operation_direction::receiver)); - impacted.insert(make_pair(op.requester, operation_direction::sender)); - } + insert_pair(op.requester, op.author); } }; diff --git a/tests/plugin_tests/account_history.cpp b/tests/plugin_tests/account_history.cpp index 001c5420ac..b56a65a206 100644 --- a/tests/plugin_tests/account_history.cpp +++ b/tests/plugin_tests/account_history.cpp @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(account_history_filter) { BOOST_TEST_MESSAGE("--- Test 'dual' direction"); q.direction = operation_direction::dual; auto bob_dual = get_history("bob", -1, 10, q); - check_ops(bob_dual, "vote|delete_comment"); + check_ops(bob_dual, "transfer_to_vesting|vote|delete_comment"); BOOST_TEST_MESSAGE("--- Test virtual only select"); q.direction = operation_direction::any; From f26faab9c5f2787d6544df1cecf6335dd2deaa78 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 20:26:59 +0700 Subject: [PATCH 242/250] Remove lowmem mode. #914 --- .travis.yml | 1 - CMakeLists.txt | 17 --- Dockerfile | 1 - documentation/building.md | 6 - libraries/chain/database.cpp | 4 - libraries/chain/steem_evaluator.cpp | 16 --- programs/build_helpers/configure_build.py | 11 +- share/golosd/docker/Dockerfile-lowmem | 133 ------------------- share/golosd/docker/Dockerfile-lowmem-small | 126 ------------------ share/golosd/docker/Dockerfile-mongo | 1 - share/golosd/docker/Dockerfile-small | 1 - share/golosd/docker/Dockerfile-test | 2 - share/golosd/docker/Dockerfile-testnet | 1 - share/golosd/docker/Dockerfile-testnet-mongo | 1 - tests/tests/operation_tests.cpp | 24 ++-- 15 files changed, 11 insertions(+), 334 deletions(-) delete mode 100644 share/golosd/docker/Dockerfile-lowmem delete mode 100644 share/golosd/docker/Dockerfile-lowmem-small diff --git a/.travis.yml b/.travis.yml index cc1009773e..c2282268c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ env: - DOCKERFILE=Dockerfile DOCKERNAME="" - DOCKERFILE=share/golosd/docker/Dockerfile-test DOCKERNAME="-test" - DOCKERFILE=share/golosd/docker/Dockerfile-testnet DOCKERNAME="-testnet" - - DOCKERFILE=share/golosd/docker/Dockerfile-lowmem DOCKERNAME="-lowmem" - DOCKERFILE=share/golosd/docker/Dockerfile-mongo DOCKERNAME="-mongo" matrix: diff --git a/CMakeLists.txt b/CMakeLists.txt index e7d54dc2a8..6ac1ce119a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,16 +73,6 @@ if(MAX_19_VOTED_WITNESSES AND BUILD_GOLOS_TESTNET) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSTEEMIT_MAX_VOTED_WITNESSES=19") endif() -option(LOW_MEMORY_NODE "Build source for low memory node (ON OR OFF)" FALSE) -message(STATUS "LOW_MEMORY_NODE: ${LOW_MEMORY_NODE}") -if(LOW_MEMORY_NODE) - message(STATUS " ") - message(STATUS " CONFIGURING FOR LOW MEMORY NODE ") - message(STATUS " ") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIS_LOW_MEM") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DIS_LOW_MEM") -endif() - option(CHAINBASE_CHECK_LOCKING "Check locks in chainbase (ON or OFF)" TRUE) message(STATUS "CHAINBASE_CHECK_LOCKING: ${CHAINBASE_CHECK_LOCKING}") if(CHAINBASE_CHECK_LOCKING) @@ -285,10 +275,3 @@ else() message(STATUS "\n\n CONFIGURED FOR GOLOS NETWORK \n\n") endif() -if(LOW_MEMORY_NODE) - message(STATUS "\n\n CONFIGURED FOR LOW MEMORY NODE \n\n") -else() - message(STATUS "\n\n CONFIGURED FOR FULL NODE \n\n") -endif() - - diff --git a/Dockerfile b/Dockerfile index f1c8d4b665..9d1040fbed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,6 @@ RUN \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_GOLOS_TESTNET=FALSE \ -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=FALSE \ -DCHAINBASE_CHECK_LOCKING=FALSE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. \ diff --git a/documentation/building.md b/documentation/building.md index 064b7db189..c90039d6a4 100644 --- a/documentation/building.md +++ b/documentation/building.md @@ -8,12 +8,6 @@ Specifies whether to build with or without optimization and without or with the symbol table for debugging. Unless you are specifically debugging or running tests, it is recommended to build as release. -### LOW_MEMORY_NODE=[FALSE/TRUE] - -Builds golosd to be a consensus-only low memory node. Data and fields not -needed for consensus are not stored in the object database. This option is -recommended for witnesses and seed-nodes. - ### BUILD_GOLOS_TESTNET=[FALSE/TRUE] Builds golos for use in a private testnet. Also required for building unit tests. diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index d4f0be9664..3da8706bde 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2266,11 +2266,9 @@ namespace golos { namespace chain { push_virtual_operation(curation_reward_operation(voter.name, reward, c.author, to_string(c.permlink))); -#ifndef IS_LOW_MEM modify(voter, [&](account_object &a) { a.curation_rewards += claim; }); -#endif } else { break; } @@ -2335,11 +2333,9 @@ namespace golos { namespace chain { push_virtual_operation(author_reward_operation(comment.author, to_string(comment.permlink), sbd_payout.first, sbd_payout.second, vest_created)); push_virtual_operation(comment_reward_operation(comment.author, to_string(comment.permlink), total_payout)); -#ifndef IS_LOW_MEM modify(get_account(comment.author), [&](account_object &a) { a.posting_rewards += author_tokens; }); -#endif } fc::uint128_t old_rshares2 = calculate_vshares(comment.net_rshares.value); diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index b7d74f1cd9..98f50681cc 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -4,22 +4,6 @@ #include #include -#ifndef IS_LOW_MEM - -#include - -using boost::locale::conv::utf_to_utf; - -std::wstring utf8_to_wstring(const std::string &str) { - return utf_to_utf(str.c_str(), str.c_str() + str.size()); -} - -std::string wstring_to_utf8(const std::wstring &str) { - return utf_to_utf(str.c_str(), str.c_str() + str.size()); -} - -#endif - #define GOLOS_CHECK_BALANCE(ACCOUNT, TYPE, REQUIRED ...) \ FC_EXPAND_MACRO( \ FC_MULTILINE_MACRO_BEGIN \ diff --git a/programs/build_helpers/configure_build.py b/programs/build_helpers/configure_build.py index 919108761f..46e39b4b98 100755 --- a/programs/build_helpers/configure_build.py +++ b/programs/build_helpers/configure_build.py @@ -76,14 +76,7 @@ def try_default_dir_from_env(args, flag_name, metavar_name, env_name=None): parser.add_argument("--openssl-dir", metavar="OPENSSL_ROOT", type=convert_to_dir, default=argparse.SUPPRESS, help="OpenSSL root directory (can alternatively specify with OPENSSL_ROOT_DIR environment variable)") - node_type = parser.add_mutually_exclusive_group() - node_type.add_argument("-f", "--full", dest="low_mem_node", - action="store_false", default=argparse.SUPPRESS, - help="build with LOW_MEMORY_NODE=OFF (default)") - node_type.add_argument("-w", "--witness", dest="low_mem_node", - action="store_true", default=argparse.SUPPRESS, - help="build with LOW_MEMORY_NODE=ON") - build_type = parser.add_mutually_exclusive_group() + build_type = parser.add_mutually_exclusive_group() build_type.add_argument("-r", "--release", dest="release", action="store_true", default=argparse.SUPPRESS, help="build with CMAKE_BUILD_TYPE=RELEASE (default)") @@ -178,8 +171,6 @@ def main(args): command.append("-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY") # Add Golos flags - command.append( - "-DLOW_MEMORY_NODE=" + ("ON" if args.low_mem_node else "OFF")) command.append( "-DCMAKE_BUILD_TYPE=" + ("RELEASE" if args.release else "DEBUG")) diff --git a/share/golosd/docker/Dockerfile-lowmem b/share/golosd/docker/Dockerfile-lowmem deleted file mode 100644 index 5ee50f95dc..0000000000 --- a/share/golosd/docker/Dockerfile-lowmem +++ /dev/null @@ -1,133 +0,0 @@ -FROM phusion/baseimage:0.9.19 - -ENV LANG=en_US.UTF-8 - -RUN \ - apt-get update && \ - apt-get install -y \ - autoconf \ - automake \ - autotools-dev \ - bsdmainutils \ - build-essential \ - cmake \ - doxygen \ - git \ - ccache\ - libboost-all-dev \ - libreadline-dev \ - libssl-dev \ - libtool \ - ncurses-dev \ - pbzip2 \ - pkg-config \ - python3 \ - python3-dev \ - python3-pip \ - && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ - pip3 install gcovr - -ADD . /usr/local/src/golos - -RUN \ - cd /usr/local/src/golos && \ - git submodule deinit -f . && \ - git submodule update --init --recursive -f && \ - mkdir build && \ - cd build && \ - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_GOLOS_TESTNET=FALSE \ - -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=TRUE \ - -DCHAINBASE_CHECK_LOCKING=FALSE \ - -DENABLE_MONGO_PLUGIN=FALSE \ - .. \ - && \ - make -j$(nproc) && \ - make install && \ - rm -rf /usr/local/src/golos - -RUN \ - apt-get remove -y \ - automake \ - autotools-dev \ - bsdmainutils \ - build-essential \ - cmake \ - doxygen \ - dpkg-dev \ - git \ - libboost-all-dev \ - libc6-dev \ - libexpat1-dev \ - libgcc-5-dev \ - libhwloc-dev \ - libibverbs-dev \ - libicu-dev \ - libltdl-dev \ - libncurses5-dev \ - libnuma-dev \ - libopenmpi-dev \ - libpython-dev \ - libpython2.7-dev \ - libreadline-dev \ - libreadline6-dev \ - libssl-dev \ - libstdc++-5-dev \ - libtinfo-dev \ - libtool \ - linux-libc-dev \ - m4 \ - make \ - manpages \ - manpages-dev \ - mpi-default-dev \ - python-dev \ - python2.7-dev \ - python3-dev \ - && \ - apt-get autoremove -y && \ - rm -rf \ - /var/lib/apt/lists/* \ - /tmp/* \ - /var/tmp/* \ - /var/cache/* \ - /usr/include \ - /usr/local/include - -ADD share/golosd/golosdctl /usr/local/bin/golosdctl -RUN chmod +x /usr/local/bin/golosdctl - -RUN useradd -s /bin/bash -m -d /var/lib/golosd golosd - -RUN mkdir /var/cache/golosd && \ - chown golosd:golosd -R /var/cache/golosd - -# add blockchain cache to image -#ADD $STEEMD_BLOCKCHAIN /var/cache/golosd/blocks.tbz2 - -ENV HOME /var/lib/golosd -RUN chown golosd:golosd -R /var/lib/golosd - -ADD share/golosd/snapshot5392323.json /var/lib/golosd - -# rpc service: -# http -EXPOSE 8090 -# ws -EXPOSE 8091 -# p2p service: -EXPOSE 4243 - -RUN mkdir -p /etc/service/golosd -ADD share/golosd/golosd.sh /etc/service/golosd/run -RUN chmod +x /etc/service/golosd/run - -# add seednodes from documentation to image -ADD share/golosd/seednodes /etc/golosd/seednodes - -# the following adds lots of logging info to stdout -ADD share/golosd/config/config.ini /etc/golosd/config.ini diff --git a/share/golosd/docker/Dockerfile-lowmem-small b/share/golosd/docker/Dockerfile-lowmem-small deleted file mode 100644 index 37ccec02e1..0000000000 --- a/share/golosd/docker/Dockerfile-lowmem-small +++ /dev/null @@ -1,126 +0,0 @@ -FROM phusion/baseimage:0.9.19 - -ENV LANG=en_US.UTF-8 - -ADD . /usr/local/src/golos - -RUN \ - apt-get update && \ - apt-get install -y \ - autoconf \ - automake \ - autotools-dev \ - bsdmainutils \ - build-essential \ - cmake \ - doxygen \ - git \ - ccache\ - libboost-all-dev \ - libreadline-dev \ - libssl-dev \ - libtool \ - ncurses-dev \ - pbzip2 \ - pkg-config \ - python3 \ - python3-dev \ - python3-pip \ - && \ - pip3 install gcovr && \ - # build golosd - cd /usr/local/src/golos && \ - git submodule deinit -f . && \ - git submodule update --init --recursive -f && \ - mkdir build && \ - cd build && \ - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_GOLOS_TESTNET=FALSE \ - -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=TRUE \ - -DCHAINBASE_CHECK_LOCKING=FALSE \ - -DENABLE_MONGO_PLUGIN=FALSE \ - .. \ - && \ - make -j$(nproc) && \ - make install && \ - # perform cleanup - rm -rf /usr/local/src/golos && \ - apt-get remove -y \ - automake \ - autotools-dev \ - bsdmainutils \ - build-essential \ - cmake \ - doxygen \ - dpkg-dev \ - git \ - libboost-all-dev \ - libc6-dev \ - libexpat1-dev \ - libgcc-5-dev \ - libhwloc-dev \ - libibverbs-dev \ - libicu-dev \ - libltdl-dev \ - libncurses5-dev \ - libnuma-dev \ - libopenmpi-dev \ - libpython-dev \ - libpython2.7-dev \ - libreadline-dev \ - libreadline6-dev \ - libssl-dev \ - libstdc++-5-dev \ - libtinfo-dev \ - libtool \ - linux-libc-dev \ - m4 \ - make \ - manpages \ - manpages-dev \ - mpi-default-dev \ - python-dev \ - python2.7-dev \ - python3-dev \ - && \ - apt-get autoremove -y && \ - rm -rf \ - /var/lib/apt/lists/* \ - /tmp/* \ - /var/tmp/* \ - /var/cache/* \ - /usr/include \ - /usr/local/include && \ - # add pseudouser - useradd -s /bin/bash -m -d /var/lib/golosd golosd && \ - # prepare cache directory - mkdir /var/cache/golosd && \ - chown golosd:golosd -R /var/cache/golosd - -ADD share/golosd/golosdctl /usr/local/bin/golosdctl -RUN chmod +x /usr/local/bin/golosdctl - -ENV HOME /var/lib/golosd -RUN chown golosd:golosd -R /var/lib/golosd - -ADD share/golosd/snapshot5392323.json /var/lib/golosd - -# rpc service: -# http -EXPOSE 8090 -# ws -EXPOSE 8091 -# p2p service: -EXPOSE 4243 - -RUN mkdir -p /etc/service/golosd -ADD share/golosd/golosd.sh /etc/service/golosd/run -RUN chmod +x /etc/service/golosd/run - -# add seednodes from documentation to image -ADD share/golosd/seednodes /etc/golosd/seednodes - -# the following adds lots of logging info to stdout -ADD share/golosd/config/config.ini /etc/golosd/config.ini diff --git a/share/golosd/docker/Dockerfile-mongo b/share/golosd/docker/Dockerfile-mongo index 96c4f10c53..51e55940b0 100644 --- a/share/golosd/docker/Dockerfile-mongo +++ b/share/golosd/docker/Dockerfile-mongo @@ -70,7 +70,6 @@ RUN \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_GOLOS_TESTNET=FALSE \ -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=FALSE \ -DCHAINBASE_CHECK_LOCKING=FALSE \ -DENABLE_MONGO_PLUGIN=TRUE \ .. \ diff --git a/share/golosd/docker/Dockerfile-small b/share/golosd/docker/Dockerfile-small index 1d4adc41b3..c764f699c8 100644 --- a/share/golosd/docker/Dockerfile-small +++ b/share/golosd/docker/Dockerfile-small @@ -38,7 +38,6 @@ RUN \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_GOLOS_TESTNET=FALSE \ -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=FALSE \ -DCHAINBASE_CHECK_LOCKING=FALSE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. \ diff --git a/share/golosd/docker/Dockerfile-test b/share/golosd/docker/Dockerfile-test index 909c98ecf5..3c2d9da061 100644 --- a/share/golosd/docker/Dockerfile-test +++ b/share/golosd/docker/Dockerfile-test @@ -40,7 +40,6 @@ RUN \ cmake \ -DCMAKE_BUILD_TYPE=Debug \ -DBUILD_GOLOS_TESTNET=TRUE \ - -DLOW_MEMORY_NODE=FALSE \ -DMAX_19_VOTED_WITNESSES=TRUE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. && \ @@ -60,7 +59,6 @@ RUN \ # -DCMAKE_BUILD_TYPE=Debug \ # -DENABLE_COVERAGE_TESTING=TRUE \ # -DBUILD_GOLOS_TESTNET=TRUE \ -# -DLOW_MEMORY_NODE=FALSE \ # -DMAX_19_VOTED_WITNESSES=TRUE \ # -DENABLE_MONGO_PLUGIN=FALSE \ # .. && \ diff --git a/share/golosd/docker/Dockerfile-testnet b/share/golosd/docker/Dockerfile-testnet index 58fc86d921..990e0242bc 100644 --- a/share/golosd/docker/Dockerfile-testnet +++ b/share/golosd/docker/Dockerfile-testnet @@ -40,7 +40,6 @@ RUN \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_GOLOS_TESTNET=TRUE \ -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=FALSE \ -DCHAINBASE_CHECK_LOCKING=FALSE \ -DENABLE_MONGO_PLUGIN=FALSE \ .. \ diff --git a/share/golosd/docker/Dockerfile-testnet-mongo b/share/golosd/docker/Dockerfile-testnet-mongo index 411cd555bd..8d94dffd4f 100644 --- a/share/golosd/docker/Dockerfile-testnet-mongo +++ b/share/golosd/docker/Dockerfile-testnet-mongo @@ -69,7 +69,6 @@ RUN \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_GOLOS_TESTNET=TRUE \ -DBUILD_SHARED_LIBRARIES=FALSE \ - -DLOW_MEMORY_NODE=FALSE \ -DCHAINBASE_CHECK_LOCKING=FALSE \ -DENABLE_MONGO_PLUGIN=TRUE \ .. \ diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 0a55e0b444..ed96a8b676 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -179,13 +179,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(acct.sbd_balance.amount.value, ASSET("0.000 GBG").amount.value); BOOST_CHECK_EQUAL(acct.id._id, acct_auth.id._id); - /* This is being moved out of consensus... - #ifndef IS_LOW_MEM - BOOST_CHECK_EQUAL( acct.json_metadata, op.json_metadata ); - #else - BOOST_CHECK_EQUAL( acct.json_metadata, "" ); - #endif - */ + auto meta = db->find(acct.name); + BOOST_CHECK(nullptr != meta); + if (nullptr != meta) { + BOOST_CHECK_EQUAL(to_string(meta->json_metadata), op.json_metadata); + } /// because init_witness has created vesting shares and blocks have been produced, 100 STEEM is worth less than 100 vesting shares due to rounding BOOST_CHECK_EQUAL(acct.vesting_shares.amount.value, (op.fee * (vest_shares / vests)).amount.value); @@ -374,13 +372,11 @@ BOOST_FIXTURE_TEST_SUITE(operation_tests, clean_database_fixture) BOOST_CHECK_EQUAL(acct_auth.active, authority(2, new_private_key.get_public_key(), 2)); BOOST_CHECK_EQUAL(acct.memo_key, new_private_key.get_public_key()); - /* This is being moved out of consensus - #ifndef IS_LOW_MEM - BOOST_CHECK_EQUAL( acct.json_metadata, "{\"bar\":\"foo\"}" ); - #else - BOOST_CHECK_EQUAL( acct.json_metadata, "" ); - #endif - */ + auto meta = db->find(acct.name); + BOOST_CHECK(nullptr != meta); + if (nullptr != meta) { + BOOST_CHECK_EQUAL(to_string(meta->json_metadata), op.json_metadata); + } validate_database(); From b83d8e9bcbecd7920f55d266cd5f683cd2363e8d Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 6 Aug 2018 11:52:40 +0300 Subject: [PATCH 243/250] Add account_history filtering to cli_wallet + fixes #742 1. cli_wallet now supports filter_account_history command, which accepts account_history_query as 4th argument (get_account_history command behaviour didn't changed) 2. Fixed get_account_history max limit to 10000 as was earlier 3. Some clean-up, removed tailing spaces, includes reorder --- .../include/golos/wallet/remote_node_api.hpp | 31 ++++---- .../wallet/include/golos/wallet/wallet.hpp | 26 ++++++- libraries/wallet/wallet.cpp | 72 +++++++++++-------- .../account_history/history_object.hpp | 9 --- plugins/account_history/plugin.cpp | 22 +++--- 5 files changed, 92 insertions(+), 68 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index 6d7772f1b8..d9d30bad64 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -1,24 +1,26 @@ #pragma once -#include +#include #include +#include #include -#include -#include +#include +#include +#include #include +#include +#include +#include #include -#include #include +#include + +#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include namespace golos { namespace wallet { @@ -28,7 +30,6 @@ using fc::optional; using namespace chain; using namespace plugins; -//using namespace plugins::condenser_api; using namespace plugins::database_api; using namespace plugins::follow; using namespace plugins::social_network; @@ -36,8 +37,9 @@ using namespace plugins::tags; using namespace plugins::market_history; using namespace plugins::network_broadcast_api; using namespace plugins::private_message; -using namespace golos::api; using namespace plugins::witness_api; +using namespace plugins::account_history; +using namespace golos::api; /** * This is a dummy class exists only to provide method signature information to fc::api, not to execute calls. @@ -87,7 +89,8 @@ struct remote_operation_history { * Class is used by wallet to send formatted API calls to operation_history plugin on remote node. */ struct remote_account_history { - map get_account_history( account_name_type, uint64_t, uint32_t ); + map + get_account_history(account_name_type, uint64_t, uint32_t, account_history_query); }; /** diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 37f2f8bf21..7c3b88a82a 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -20,6 +20,8 @@ namespace golos { namespace wallet { using namespace golos::utilities; using namespace golos::protocol; using namespace golos::plugins::private_message; + using namespace golos::plugins::account_history; + using history_operations = map; typedef uint16_t transaction_handle_type; @@ -1095,8 +1097,23 @@ namespace golos { namespace wallet { * @param from - the absolute sequence number, -1 means most recent, limit is the number of operations before from. * @param limit - the maximum number of items that can be queried (0 to 1000], must be less than from */ - map< uint32_t, golos::plugins::operation_history::applied_operation > - get_account_history( string account, uint32_t from, uint32_t limit ); + history_operations get_account_history(string account, uint32_t from, uint32_t limit); + + /** + * Account operations have sequence numbers from 0 to N where N is the most recent operation. + * This method returns operations in the range [from-limit, from] + * + * @param account - name of account, which history requested. + * @param from - the absolute sequence number, -1 means most recent, limit is the number of operations before from. + * @param limit - the maximum number of items that can be queried (0 to 1000], must be less than from + * @param query - filtering query - object with following optional fields: + * { + * select_ops - list of operations to include. special values: ALL, REAL, VIRTUAL. if skipped = ALL + * filter_ops - blacklist. if skipped = empty list (nothing blacklisted) + * dir - direction of operation in relation to account: any, sender, receiver, dual. Experimental + * } + */ + history_operations filter_account_history(string account, uint32_t from, uint32_t limit, account_history_query query); FC_TODO(Supplement API argument description) @@ -1314,6 +1331,10 @@ namespace golos { namespace wallet { annotated_signed_transaction mark_private_messages( const std::string& from, const std::string& to, const std::string& start_date, const std::string& stop_date, bool broadcast); + + private: + void decrypt_history_memos(history_operations& result); + }; struct plain_keys { @@ -1364,6 +1385,7 @@ FC_API( golos::wallet::wallet_api, (get_feed_history) (get_conversion_requests) (get_account_history) + (filter_account_history) (get_withdraw_routes) /// transaction api diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 90ea200797..631c810f06 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -562,7 +562,7 @@ namespace golos { namespace wallet { fc::ecc::private_key get_private_key(const public_key_type& id)const { auto has_key = try_get_private_key( id ); - if (!has_key) + if (!has_key) GOLOS_THROW_MISSING_OBJECT("private_key", id); return *has_key; } @@ -741,14 +741,14 @@ namespace golos { namespace wallet { req_active_approvals.insert(a.first); // collects all keys to common set and accounts to common map - + flat_map approving_account_lut; flat_set approving_key_set; - std::vector active_account_auths; - std::vector owner_account_auths; - std::vector posting_account_auths; + std::vector active_account_auths; + std::vector owner_account_auths; + std::vector posting_account_auths; auto fetch_keys = [&](const authority& auth) { for (const public_key_type& approving_key : auth.get_keys()) { @@ -756,7 +756,7 @@ namespace golos { namespace wallet { approving_key_set.insert( approving_key ); } }; - + if (!req_active_approvals.empty()) { auto req_active_accs =_remote_database_api->get_accounts(std::vector( req_active_approvals.begin(), req_active_approvals.end())); @@ -815,7 +815,7 @@ namespace golos { namespace wallet { auto get_account_from_lut = [&]( const std::string& name ) -> const golos::api::account_api_object& { auto it = approving_account_lut.find( name ); - GOLOS_CHECK_LOGIC( it != approving_account_lut.end(), + GOLOS_CHECK_LOGIC( it != approving_account_lut.end(), logic_errors::no_account_in_lut, "No account in lut: '${name}'", ("name",name) ); return it->second; @@ -925,16 +925,16 @@ namespace golos { namespace wallet { << std::right << std::setw(16) << fc::variant(total_sbd).as_string() <<"\n"; return out.str(); }; - m["get_account_history"] = []( variant result, const fc::variants& a ) { + auto acc_history_formatter = [](variant result, const fc::variants& a) { std::stringstream ss; - ss << std::left << std::setw( 5 ) << "#" << " "; - ss << std::left << std::setw( 10 ) << "BLOCK #" << " "; - ss << std::left << std::setw( 15 ) << "TRX ID" << " "; - ss << std::left << std::setw( 20 ) << "OPERATION" << " "; - ss << std::left << std::setw( 50 ) << "DETAILS" << "\n"; + ss << std::left << std::setw(5) << "#" << " "; + ss << std::left << std::setw(10) << "BLOCK #" << " "; + ss << std::left << std::setw(15) << "TRX ID" << " "; + ss << std::left << std::setw(20) << "OPERATION" << " "; + ss << std::left << std::setw(50) << "DETAILS" << "\n"; ss << "-------------------------------------------------------------------------------\n"; const auto& results = result.get_array(); - for( const auto& item : results ) { + for (const auto& item : results) { ss << std::left << std::setw(5) << item.get_array()[0].as_string() << " "; const auto& op = item.get_array()[1].get_object(); ss << std::left << std::setw(10) << op["block"].as_string() << " "; @@ -945,6 +945,9 @@ namespace golos { namespace wallet { } return ss.str(); }; + m["get_account_history"] = acc_history_formatter; + m["filter_account_history"] = acc_history_formatter; + /*m["get_open_orders"] = []( variant result, const fc::variants& a ) { auto orders = result.as>(); @@ -2238,7 +2241,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st for( auto& key_weight_pair : account.owner.key_auths ) { for( auto& key : keys ) - GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, logic_errors::detected_private_key_in_memo, "Detected ${type} private key in memo field", ("type","owner")); @@ -2247,7 +2250,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st for( auto& key_weight_pair : account.active.key_auths ) { for( auto& key : keys ) - GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, logic_errors::detected_private_key_in_memo, "Detected ${type} private key in memo field", ("type","active")); @@ -2256,7 +2259,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st for( auto& key_weight_pair : account.posting.key_auths ) { for( auto& key : keys ) - GOLOS_CHECK_LOGIC(key_weight_pair.first != key, + GOLOS_CHECK_LOGIC(key_weight_pair.first != key, logic_errors::detected_private_key_in_memo, "Detected ${type} private key in memo field", ("type","posting")); @@ -2264,7 +2267,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st const auto& memo_key = account.memo_key; for( auto& key : keys ) - GOLOS_CHECK_LOGIC(memo_key != key, + GOLOS_CHECK_LOGIC(memo_key != key, logic_errors::detected_private_key_in_memo, "Detected ${type} private key in memo field", ("type","memo")); @@ -2273,7 +2276,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st for( auto& key_pair : my->_keys ) { for( auto& key : keys ) - GOLOS_CHECK_LOGIC(key_pair.first != key, + GOLOS_CHECK_LOGIC(key_pair.first != key, logic_errors::detected_private_key_in_memo, "Detected ${type} private key in memo field", ("type","imported")); @@ -2620,25 +2623,34 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st return my->sign_transaction( tx, broadcast ); } - map< uint32_t, golos::plugins::operation_history::applied_operation> wallet_api::get_account_history( string account, uint32_t from, uint32_t limit ) { - auto result = my->_remote_account_history->get_account_history( account, from, limit ); - if( !is_locked() ) { - for( auto& item : result ) { - if( item.second.op.which() == operation::tag::value ) { + history_operations wallet_api::get_account_history(string account, uint32_t from, uint32_t limit) { + auto result = my->_remote_account_history->get_account_history(account, from, limit, account_history_query()); + decrypt_history_memos(result); + return result; + } + history_operations wallet_api::filter_account_history(string account, uint32_t from, uint32_t limit, account_history_query q) { + auto result = my->_remote_account_history->get_account_history(account, from, limit, q); + decrypt_history_memos(result); + return result; + } + + void wallet_api::decrypt_history_memos(history_operations& result) { + if (!is_locked()) { + for (auto& item : result) { + if (item.second.op.which() == operation::tag::value) { auto& top = item.second.op.get(); - top.memo = decrypt_memo( top.memo ); + top.memo = decrypt_memo(top.memo); } - else if( item.second.op.which() == operation::tag::value ) { + else if (item.second.op.which() == operation::tag::value) { auto& top = item.second.op.get(); - top.memo = decrypt_memo( top.memo ); + top.memo = decrypt_memo(top.memo); } - else if( item.second.op.which() == operation::tag::value ) { + else if (item.second.op.which() == operation::tag::value) { auto& top = item.second.op.get(); - top.memo = decrypt_memo( top.memo ); + top.memo = decrypt_memo(top.memo); } } } - return result; } vector< database_api::withdraw_vesting_route_api_object > wallet_api::get_withdraw_routes( string account, database_api::withdraw_route_type type )const { diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index 838ebf0e86..dd8fb92a9f 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -76,7 +76,6 @@ static_assert(protocol::operation::count() >= 0 && protocol::operation::count() using account_history_id_type = object_id; - // struct by_direction; struct by_operation; struct by_location; struct by_account; @@ -98,13 +97,6 @@ static_assert(protocol::operation::count() >= 0 && protocol::operation::count() member>, composite_key_compare< std::less, std::less, std::less, std::greater>>, - // ordered_unique< - // tag, - // composite_key, - // member, - // member>, - // composite_key_compare, std::less, std::greater>>, ordered_unique< tag, composite_key -#define ACCOUNT_HISTORY_MAX_LIMIT 1000 +#define ACCOUNT_HISTORY_MAX_LIMIT 10000 +#define ACCOUNT_HISTORY_DEFAULT_LIMIT 100 #define GOLOS_OP_NAMESPACE "golos::protocol::" @@ -162,21 +163,15 @@ if (options.count(name)) { \ } return result; } - bool is_all_ops(op_tags x) { - return x.size() == operation::count(); - } struct sequenced_itr { - // TODO: if possible, change this decltypes to something more readable - using op_idx_type = decltype(database().get_index().indices().get()); - using op_itr_type = decltype( - database().get_index().indices().get() - .lower_bound(std::make_tuple("",uint8_t(0),operation_direction::any,uint32_t(0)))); + using op_idx_type = account_history_index::index::type; + using op_itr_type = account_history_index::index_const_iterator::type; op_itr_type itr; - sequenced_itr(op_idx_type idx, account_name_type a, uint8_t o, operation_direction d, uint32_t s) { - itr = idx.lower_bound(std::make_tuple(a, o, d, s)); + sequenced_itr(const op_idx_type& idx, account_name_type a, uint8_t o, operation_direction d, uint32_t s) + : itr(idx.lower_bound(std::make_tuple(a, o, d, s))) { } // reconstruct to put next value into queue (can't reuse previous because const in queue) @@ -207,7 +202,8 @@ if (options.count(name)) { \ }); auto dir = query.direction ? *query.direction : operation_direction::any; - if (is_all_ops(select_ops) && dir == operation_direction::any) { + bool is_all_ops = select_ops.size() == operation::count(); + if (is_all_ops && dir == operation_direction::any) { return fetch_unfiltered(account, from, limit); } std::priority_queue itrs; @@ -252,7 +248,7 @@ if (options.count(name)) { \ PLUGIN_API_VALIDATE_ARGS( (account_name_type, account) (uint32_t, from, 0xFFFFFFFF) - (uint32_t, limit, 100) + (uint32_t, limit, ACCOUNT_HISTORY_DEFAULT_LIMIT) (account_history_query, query, account_history_query()) ); return pimpl->db.with_weak_read_lock([&]() { From f94ea2ece0267ee2551d2850a3db3ae1b3bfd577 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 20:27:19 +0700 Subject: [PATCH 244/250] Don't store zero rewards. #915 --- plugins/mongo_db/mongo_db_state.cpp | 10 +++ .../social_network/social_network_types.hpp | 7 +- plugins/social_network/social_network.cpp | 87 ++++++++++++------- tests/tests/operation_time_tests.cpp | 3 +- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 37b576ce22..d6312acb56 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -154,6 +154,16 @@ namespace mongo_db { format_value(body, "curator_payout", cr_itr->curator_payout_value); format_value(body, "curator_gests_payout", cr_itr->curator_gests_payout_value); format_value(body, "total_payout", cr_itr->total_payout_value); + } else { + format_value(body, "author_rewards", 0); + format_value(body, "author_gbg_payout", asset(0, SBD_SYMBOL)); + format_value(body, "author_golos_payout", asset(0, STEEM_SYMBOL)); + format_value(body, "author_gests_payout", asset(0, VESTS_SYMBOL)); + format_value(body, "beneficiary_payout", asset(0, SBD_SYMBOL)); + format_value(body, "beneficiary_gests_payout", asset(0, VESTS_SYMBOL)); + format_value(body, "curator_payout", asset(0, SBD_SYMBOL)); + format_value(body, "curator_gests_payout", asset(0, VESTS_SYMBOL)); + format_value(body, "total_payout", asset(0, SBD_SYMBOL)); } } diff --git a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp index d49ba998da..7ebaaafcb0 100644 --- a/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp +++ b/plugins/social_network/include/golos/plugins/social_network/social_network_types.hpp @@ -125,15 +125,14 @@ namespace golos { namespace plugins { namespace social_network { asset curator_gests_payout_value{0, VESTS_SYMBOL}; }; - typedef object_id comment_reward_id_type; + using comment_reward_id_type = object_id; - typedef multi_index_container< + using comment_reward_index = multi_index_container< comment_reward_object, indexed_by< ordered_unique, member>, ordered_unique, member>>, - allocator - > comment_reward_index; + allocator>; } } } diff --git a/plugins/social_network/social_network.cpp b/plugins/social_network/social_network.cpp index 8f5e978bc7..0cfdeaeee0 100644 --- a/plugins/social_network/social_network.cpp +++ b/plugins/social_network/social_network.cpp @@ -247,6 +247,20 @@ namespace golos { namespace plugins { namespace social_network { } impl.activate_parent_comments(comment); + + auto& idx = impl.db.template get_index().indices().template get(); + auto itr = idx.find(comment.id); + if (idx.end() != itr) { + impl.db.remove(*itr); + } + } + + if (impl.db.template has_index()) { + auto& idx = impl.db.template get_index().indices().template get(); + auto itr = idx.find(comment.id); + if (idx.end() != itr) { + impl.db.remove(*itr); + } } } }; @@ -382,33 +396,36 @@ namespace golos { namespace plugins { namespace social_network { asset curator_payout_golos = impl.curator_payout_gests * vesting_sp; asset curator_payout_gbg = db.to_sbd(curator_payout_golos); - const auto& cr_idx = db.get_index().indices().get(); - auto cr_itr = cr_idx.find(comment.id); - if (cr_itr == cr_idx.end()) { - db.create([&](golos::plugins::social_network::comment_reward_object& cr) { - cr.comment = comment.id; - cr.author_rewards = author_rewards; - cr.author_gbg_payout_value = impl.author_gbg_payout_value; - cr.author_golos_payout_value = impl.author_golos_payout_value; - cr.author_gests_payout_value = impl.author_gests_payout_value; - cr.total_payout_value = total_payout_gbg; - cr.beneficiary_payout_value = benef_payout_gbg; - cr.beneficiary_gests_payout_value = impl.benef_payout_gests; - cr.curator_payout_value = curator_payout_gbg; - cr.curator_gests_payout_value = impl.curator_payout_gests; - }); - } else { - db.modify(*cr_itr, [&](comment_reward_object& cr) { - cr.author_rewards += author_rewards; - cr.author_gbg_payout_value += impl.author_gbg_payout_value; - cr.author_golos_payout_value += impl.author_golos_payout_value; - cr.author_gests_payout_value += impl.author_gests_payout_value; - cr.total_payout_value += total_payout_gbg; - cr.beneficiary_payout_value += benef_payout_gbg; - cr.beneficiary_gests_payout_value = impl.benef_payout_gests; - cr.curator_payout_value += curator_payout_gbg; - cr.curator_gests_payout_value += impl.curator_payout_gests; - }); + if (total_payout_golos.amount.value || benef_payout_golos.amount.value || curator_payout_golos.amount.value ) { + const auto& cr_idx = db.get_index().indices() + .get(); + auto cr_itr = cr_idx.find(comment.id); + if (cr_itr == cr_idx.end()) { + db.create([&](golos::plugins::social_network::comment_reward_object& cr) { + cr.comment = comment.id; + cr.author_rewards = author_rewards; + cr.author_gbg_payout_value = impl.author_gbg_payout_value; + cr.author_golos_payout_value = impl.author_golos_payout_value; + cr.author_gests_payout_value = impl.author_gests_payout_value; + cr.total_payout_value = total_payout_gbg; + cr.beneficiary_payout_value = benef_payout_gbg; + cr.beneficiary_gests_payout_value = impl.benef_payout_gests; + cr.curator_payout_value = curator_payout_gbg; + cr.curator_gests_payout_value = impl.curator_payout_gests; + }); + } else { + db.modify(*cr_itr, [&](comment_reward_object& cr) { + cr.author_rewards += author_rewards; + cr.author_gbg_payout_value += impl.author_gbg_payout_value; + cr.author_golos_payout_value += impl.author_golos_payout_value; + cr.author_gests_payout_value += impl.author_gests_payout_value; + cr.total_payout_value += total_payout_gbg; + cr.beneficiary_payout_value += benef_payout_gbg; + cr.beneficiary_gests_payout_value = impl.benef_payout_gests; + cr.curator_payout_value += curator_payout_gbg; + cr.curator_gests_payout_value += impl.curator_payout_gests; + }); + } } impl.author_gbg_payout_value.amount = 0; @@ -528,13 +545,13 @@ namespace golos { namespace plugins { namespace social_network { config_file_options.add_options() ( // Depth of comment_content information storage history. "comment-title-depth", boost::program_options::value(), - "max count of storing records of comment.title" + "If set, remove comment titles older than specified number of blocks" ) ( "comment-body-depth", boost::program_options::value(), - "max count of storing records of comment.body" + "If set, remove comment bodies older than specified number of blocks." ) ( "comment-json-metadata-depth", boost::program_options::value(), - "max count of storing records of comment.json_metadata" + "If set, remove comment json-metadatas older than specified number of blocks." ) ( "set-content-storing-depth-null-after-update", boost::program_options::value()->default_value(false), "should content's depth be set to null after update" @@ -849,6 +866,16 @@ namespace golos { namespace plugins { namespace social_network { con.beneficiary_gests_payout_value = reward->beneficiary_gests_payout_value; con.curator_payout_value = reward->curator_payout_value; con.curator_gests_payout_value = reward->curator_gests_payout_value; + } else { + con.author_rewards = 0; + con.author_gbg_payout_value = asset(0, SBD_SYMBOL); + con.author_golos_payout_value = asset(0, STEEM_SYMBOL); + con.author_gests_payout_value = asset(0, VESTS_SYMBOL); + con.total_payout_value = asset(0, SBD_SYMBOL); + con.beneficiary_payout_value = asset(0, SBD_SYMBOL); + con.beneficiary_gests_payout_value = asset(0, VESTS_SYMBOL); + con.curator_payout_value = asset(0, SBD_SYMBOL); + con.curator_gests_payout_value = asset(0, VESTS_SYMBOL); } } } diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 1e6ae4ed93..a89c57a6e0 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -601,8 +601,7 @@ BOOST_FIXTURE_TEST_SUITE(operation_time_tests, clean_database_fixture) BOOST_CHECK(bob_cr_itr != cr_idx.end()); BOOST_CHECK_EQUAL(bob_cr_itr->total_payout_value, bob_comment_reward.total_payout()); auto sam_cr_itr = cr_idx.find(sam_comment.id); - BOOST_CHECK(sam_cr_itr != cr_idx.end()); - BOOST_CHECK_EQUAL(sam_cr_itr->total_payout_value.amount.value, 0); + BOOST_CHECK(sam_cr_itr == cr_idx.end()); auto dave_cr_itr = cr_idx.find(dave_comment.id); BOOST_CHECK(dave_cr_itr != cr_idx.end()); BOOST_CHECK_EQUAL(dave_cr_itr->total_payout_value, dave_comment_reward.total_payout()); From 3ce26242152a7b7a95d6354b6dd836636322c71d Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Fri, 3 Aug 2018 20:27:59 +0700 Subject: [PATCH 245/250] Add new params to configuration files. #915 --- share/golosd/config/config.ini | 43 +++++++++++++++++ share/golosd/config/config_debug.ini | 43 +++++++++++++++++ share/golosd/config/config_debug_mongo.ini | 43 +++++++++++++++++ share/golosd/config/config_mongo.ini | 43 +++++++++++++++++ share/golosd/config/config_stock_exchange.ini | 46 +++++++++++++++++++ share/golosd/config/config_witness.ini | 46 +++++++++++++++++++ 6 files changed, 264 insertions(+) diff --git a/share/golosd/config/config.ini b/share/golosd/config/config.ini index d67c3095e0..c11c664a10 100644 --- a/share/golosd/config/config.ini +++ b/share/golosd/config/config.ini @@ -71,6 +71,46 @@ plugin = chain p2p json_rpc webserver network_broadcast_api witness test_api dat # Remove votes before defined block, should increase performance clear-votes-before-block = 4294967295 # clear votes after each cashout +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = false @@ -98,6 +138,9 @@ history-per-size = 5760 # Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) # pm-account-range = +# Defines a list of accounts to private messages to/from +# pm-account-list = + # Enable block production, even if the chain is stale. enable-stale-production = false diff --git a/share/golosd/config/config_debug.ini b/share/golosd/config/config_debug.ini index 74562ac3fa..e53c84b751 100644 --- a/share/golosd/config/config_debug.ini +++ b/share/golosd/config/config_debug.ini @@ -71,6 +71,46 @@ plugin = chain p2p json_rpc webserver network_broadcast_api witness test_api dat # Remove votes before defined block, should increase performance clear-votes-before-block = 0 # don't clear votes +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = false @@ -98,6 +138,9 @@ history-per-size = 5760 # Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) # pm-account-range = +# Defines a list of accounts to private messages to/from +pm-account-list = + # Enable block production, even if the chain is stale. enable-stale-production = true diff --git a/share/golosd/config/config_debug_mongo.ini b/share/golosd/config/config_debug_mongo.ini index 65e629d1f5..9215d3bcf3 100644 --- a/share/golosd/config/config_debug_mongo.ini +++ b/share/golosd/config/config_debug_mongo.ini @@ -74,6 +74,46 @@ mongodb-uri = mongodb://172.17.0.1:27017/Golos # Remove votes before defined block, should increase performance clear-votes-before-block = 0 # don't clear votes +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = false @@ -101,6 +141,9 @@ history-per-size = 5760 # Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) # pm-account-range = +# Defines a list of accounts to private messages to/from +# pm-account-list = + # Enable block production, even if the chain is stale. enable-stale-production = true diff --git a/share/golosd/config/config_mongo.ini b/share/golosd/config/config_mongo.ini index f8ac3fcf25..ecf22c471a 100644 --- a/share/golosd/config/config_mongo.ini +++ b/share/golosd/config/config_mongo.ini @@ -74,6 +74,46 @@ mongodb-uri = mongodb://172.17.0.1:27017/Golos # Remove votes before defined block, should increase performance clear-votes-before-block = 4294967295 # clear votes after each cashout +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = false @@ -101,6 +141,9 @@ history-per-size = 5760 # Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) # pm-account-range = +# Defines a list of accounts to private messages to/from +# pm-account-list = + # Enable block production, even if the chain is stale. enable-stale-production = false diff --git a/share/golosd/config/config_stock_exchange.ini b/share/golosd/config/config_stock_exchange.ini index 42895b314d..943d7558d8 100644 --- a/share/golosd/config/config_stock_exchange.ini +++ b/share/golosd/config/config_stock_exchange.ini @@ -71,6 +71,46 @@ plugin = chain p2p json_rpc webserver network_broadcast_api witness database_api # Remove votes before defined block, should increase performance clear-votes-before-block = 4294967295 # clear votes after each cashout +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = true @@ -92,6 +132,12 @@ bucket-size = [15,60,300,3600,86400] # How far back in time to track history for each bucket size, measured in the number of buckets (default: 5760) history-per-size = 5760 +# Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) +# pm-account-range = + +# Defines a list of accounts to private messages to/from +pm-account-list = + # Enable block production, even if the chain is stale. enable-stale-production = false diff --git a/share/golosd/config/config_witness.ini b/share/golosd/config/config_witness.ini index 1fa73044f3..dd2c4dd33e 100644 --- a/share/golosd/config/config_witness.ini +++ b/share/golosd/config/config_witness.ini @@ -70,6 +70,46 @@ plugin = chain p2p json_rpc webserver network_broadcast_api witness database_api # Remove votes before defined block, should increase performance clear-votes-before-block = 4294967295 # clear votes after each cashout +# If set, remove votes older than specified number of blocks. +# -1 = do not remove; +# 0 = remove after cashout; +# any other value N - remove votes older than N blocks. +# Note: votes don't removed before post cashout +# clear-votes-older-n-blocks = 0 + +# Store account metadata for all accounts if true, for no one if else. +# store-account-metadata = true + +# Names of accounts to store metadata +# store-account-metadata-list = + +# Store memo for all savings withdraws +# store-memo-in-savings-withdraws = true + +# If set, remove comment titles older than specified number of blocks. +# comment-title-depth = + +# If set, remove comment bodies older than specified number of blocks. +# comment-body-depth = + +# If set, remove comment json-metadatas older than specified number of blocks. +# comment-json-metadata-depth = + +# should content's depth be set to null after update +# set-content-storing-depth-null-after-update = false + +# Mode of storing records of comment.active and comment.last_update: +# -1 = store all +# 0 = do not store +# N = storing N blocks depth +# comment-last-update-depth = -1 + +# Store comment rewards +# store-comment-rewards = true + +# Replay all blocks if shared memory is corrupted +replay-if-corrupted = true + # Virtual operations will not be passed to the plugins, enabling of the option helps to save some memory. skip-virtual-ops = true @@ -79,6 +119,12 @@ enable-stale-production = false # Percent of witnesses (0-99) that must be participating in order to produce blocks required-participation = 0 +# Defines a range of accounts to private messages to/from as a json pair ["from","to"] [from,to) +# pm-account-range = + +# Defines a list of accounts to private messages to/from +pm-account-list = + # name of witness controlled by this node (e.g. initwitness ) witness = "cyberfounder" From 1c3ed51d30bdcc1674ce719de4e99f87a9095797 Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Mon, 6 Aug 2018 20:02:12 +0700 Subject: [PATCH 246/250] Remove warnings in witness_update_evaluators --- libraries/chain/chain_properties_evaluators.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/libraries/chain/chain_properties_evaluators.cpp b/libraries/chain/chain_properties_evaluators.cpp index 37f20bea46..0d0cca5e91 100644 --- a/libraries/chain/chain_properties_evaluators.cpp +++ b/libraries/chain/chain_properties_evaluators.cpp @@ -19,19 +19,6 @@ namespace golos { namespace chain { const bool has_hf18 = _db.has_hardfork(STEEMIT_HARDFORK_0_18__673); - // TODO: remove this after HF 18 - if (has_hf18) { - if (o.props.account_creation_fee.amount.value != STEEMIT_MIN_ACCOUNT_CREATION_FEE) { - wlog("The chain_properties_update_operation should be used to update account_creation_fee"); - } - if (o.props.sbd_interest_rate != STEEMIT_DEFAULT_SBD_INTEREST_RATE) { - wlog("The chain_properties_update_operation should be used to update sbd_interest_rate"); - } - if (o.props.maximum_block_size != STEEMIT_MIN_BLOCK_SIZE_LIMIT * 2) { - wlog("The chain_properties_update_operation should be used to update maximum_block_size"); - } - } - auto update_witness = [&](witness_object& w) { from_string(w.url, o.url); w.signing_key = o.block_signing_key; From 553ac6e64811d6bdbc3204f8e89309bb81745e6c Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 6 Aug 2018 16:17:21 +0300 Subject: [PATCH 247/250] Add option to track individual accounts history + review fixes #742, #701 --- .../include/golos/wallet/remote_node_api.hpp | 5 ++- .../wallet/include/golos/wallet/wallet.hpp | 3 +- .../account_history/history_object.hpp | 7 ++-- .../golos/plugins/account_history/plugin.hpp | 4 +-- plugins/account_history/plugin.cpp | 34 +++++++++++++++++-- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/libraries/wallet/include/golos/wallet/remote_node_api.hpp b/libraries/wallet/include/golos/wallet/remote_node_api.hpp index d9d30bad64..8ab1dfd3d5 100644 --- a/libraries/wallet/include/golos/wallet/remote_node_api.hpp +++ b/libraries/wallet/include/golos/wallet/remote_node_api.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -89,8 +89,7 @@ struct remote_operation_history { * Class is used by wallet to send formatted API calls to operation_history plugin on remote node. */ struct remote_account_history { - map - get_account_history(account_name_type, uint64_t, uint32_t, account_history_query); + history_operations get_account_history(account_name_type, uint64_t, uint32_t, account_history_query); }; /** diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 7c3b88a82a..3dd5738189 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -21,7 +21,6 @@ namespace golos { namespace wallet { using namespace golos::protocol; using namespace golos::plugins::private_message; using namespace golos::plugins::account_history; - using history_operations = map; typedef uint16_t transaction_handle_type; diff --git a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp index dd8fb92a9f..96c8002f2f 100644 --- a/plugins/account_history/include/golos/plugins/account_history/history_object.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/history_object.hpp @@ -3,13 +3,10 @@ #include #include #include - -#include - +#include #include #include - -#include +#include #include diff --git a/plugins/account_history/include/golos/plugins/account_history/plugin.hpp b/plugins/account_history/include/golos/plugins/account_history/plugin.hpp index 5dca5e8bf0..31e3bd6982 100644 --- a/plugins/account_history/include/golos/plugins/account_history/plugin.hpp +++ b/plugins/account_history/include/golos/plugins/account_history/plugin.hpp @@ -23,8 +23,6 @@ */ #pragma once -#include - #include #include @@ -34,6 +32,8 @@ #include #include +#include + namespace golos { namespace plugins { namespace account_history { using namespace chain; diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 0d0b64b2d8..c505912cbc 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #define ACCOUNT_HISTORY_MAX_LIMIT 10000 @@ -517,6 +518,12 @@ if (options.count(name)) { \ bpo::value>()->composing()->multitoken(), "Defines a range of accounts to track as a json pair [\"from\",\"to\"] [from,to]. " "Can be specified multiple times" + ) + ( + "track-account", + bpo::value>()->composing(), + "Defines a individual account to track (in addition to ranges). " + "Can be specified multiple times" ); cfg.add(cli); } @@ -544,8 +551,31 @@ if (options.count(name)) { \ add_plugin_index(pimpl->db); using pairstring = std::pair; - LOAD_VALUE_SET(options, "track-account-range", pimpl->tracked_accounts, pairstring); - + fc::flat_map ranges; + LOAD_VALUE_SET(options, "track-account-range", ranges, pairstring); + + if (options.count("track-account") > 0) { + auto accounts = options.at("track-account").as>(); + for (auto& a : accounts) { + std::vector names; + boost::split(names, a, boost::is_any_of(" \t,")); + for (auto& n : names) { + if (!n.empty()) + ranges[n] = n; // construct "range" with 1 account name in it + } + } + } + // exclude embedded ranges (fix #701) + const auto end = ranges.end(); + for (auto i = ranges.begin(); i < end; ++i) { + bool bad = false; + for (auto j = ranges.begin(); !bad && j < end && j->first <= i->second; ++j) { + if (j == i) continue; + bad = i->first >= j->first && i->second <= j->second; + } + if (!bad) + pimpl->tracked_accounts[i->first] = i->second; + } ilog("account_history: tracked_accounts ${s}", ("s", pimpl->tracked_accounts)); // prepare map to convert operation name to operation tag From 8a78d0d3bbf27592298808f0a6c05107e2bfa681 Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 6 Aug 2018 17:35:38 +0300 Subject: [PATCH 248/250] Fix cli_wallet help autogeneration #858 --- libraries/wallet/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/wallet/CMakeLists.txt b/libraries/wallet/CMakeLists.txt index bab0aa623b..6cc1b9ae93 100644 --- a/libraries/wallet/CMakeLists.txt +++ b/libraries/wallet/CMakeLists.txt @@ -8,7 +8,7 @@ if(PERL_FOUND AND DOXYGEN_FOUND AND NOT "${CMAKE_GENERATOR}" STREQUAL "Ninja") add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/doxygen/perlmod/DoxyDocs.pm WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${DOXYGEN_EXECUTABLE} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/include/steemit/wallet/wallet.hpp) + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/include/golos/wallet/wallet.hpp) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/api_documentation.cpp COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate_api_documentation.pl ${CMAKE_CURRENT_BINARY_DIR}/api_documentation.cpp.new @@ -30,7 +30,9 @@ list(APPEND ${CURRENT_TARGET}_HEADERS include/golos/wallet/wallet.hpp ) +# don't remove "api_documentation.cpp", it's required to auto-generate help list(APPEND ${CURRENT_TARGET}_SOURCES + api_documentation.cpp api_documentation_standin.cpp wallet.cpp ) From 145a54792c0a986781895a4b7aa692332bc76e8a Mon Sep 17 00:00:00 2001 From: zxcat <550974+zxcat@users.noreply.github.com> Date: Mon, 6 Aug 2018 18:12:43 +0300 Subject: [PATCH 249/250] Fix cli_wallet api_documentation.cpp path & doxygen warnings #858 --- libraries/wallet/CMakeLists.txt | 2 +- libraries/wallet/include/golos/wallet/wallet.hpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/wallet/CMakeLists.txt b/libraries/wallet/CMakeLists.txt index 6cc1b9ae93..dd18237500 100644 --- a/libraries/wallet/CMakeLists.txt +++ b/libraries/wallet/CMakeLists.txt @@ -32,7 +32,7 @@ list(APPEND ${CURRENT_TARGET}_HEADERS # don't remove "api_documentation.cpp", it's required to auto-generate help list(APPEND ${CURRENT_TARGET}_SOURCES - api_documentation.cpp + ${CMAKE_CURRENT_BINARY_DIR}/api_documentation.cpp api_documentation_standin.cpp wallet.cpp ) diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 3dd5738189..0a93512ca3 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -1182,7 +1182,7 @@ namespace golos { namespace wallet { * @return the signed version of the transaction */ annotated_signed_transaction set_private_settings( - const std::string& owner, const settings_api_object& s, bool broadcast); + const std::string& owner, const settings_api_object& settings, bool broadcast); /** * Get settings for private messages @@ -1203,7 +1203,7 @@ namespace golos { namespace wallet { * @return the signed version of the transaction */ annotated_signed_transaction add_private_contact( - const std::string& owner, const std::string& contact, private_contact_type, + const std::string& owner, const std::string& contact, private_contact_type type, fc::optional json_metadata, bool broadcast); /** @@ -1492,9 +1492,9 @@ FC_REFLECT((golos::wallet::optional_chain_props), FC_REFLECT( (golos::wallet::message_body), - (subject)(body)); + (subject)(body)) FC_REFLECT_DERIVED( (golos::wallet::extended_message_object), ((golos::plugins::private_message::message_api_object)), - (message)); + (message)) From 59b58b83377020bbcda6e8436065e4e57585435c Mon Sep 17 00:00:00 2001 From: Andrew Falaleev Date: Tue, 7 Aug 2018 14:08:35 +0700 Subject: [PATCH 250/250] Update blockchain version to 0.18.4. --- libraries/protocol/include/golos/protocol/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/protocol/include/golos/protocol/config.hpp b/libraries/protocol/include/golos/protocol/config.hpp index 54a08bd17a..607ad26178 100644 --- a/libraries/protocol/include/golos/protocol/config.hpp +++ b/libraries/protocol/include/golos/protocol/config.hpp @@ -3,7 +3,7 @@ */ #pragma once -#define STEEMIT_BLOCKCHAIN_VERSION (version(0, 18, 3)) +#define STEEMIT_BLOCKCHAIN_VERSION (version(0, 18, 4)) #define STEEMIT_BLOCKCHAIN_HARDFORK_VERSION (hardfork_version(STEEMIT_BLOCKCHAIN_VERSION)) #ifdef STEEMIT_BUILD_TESTNET