diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 43b2c353c..3287028b7 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -563,6 +563,9 @@ namespace eosiosystem { [[eosio::action]] void setparams( const eosio::blockchain_parameters& params ); + [[eosio::action]] + void setblacklist(namelist, name action, const std::vector& names ); + // functions defined in producer_pay.cpp [[eosio::action]] void claimrewards( const name owner ); diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b8c3bba39..334e2b142 100755 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -7,7 +7,7 @@ #include "voting.cpp" #include "exchange_state.cpp" #include "rex.cpp" - +#include namespace eosiosystem { system_contract::system_contract( name s, name code, datastream ds ) @@ -120,6 +120,46 @@ namespace eosiosystem { check( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); set_blockchain_parameters( params ); } + + void system_contract::setblacklist(name list, name action, const std::vector& names) + { + const int blacklist_limit_size = 100; + enum class list_type:int64_t + { + actor_blacklist_type = 1, + contract_blacklist_type, + resource_greylist_type, + list_type_count + }; + enum class list_action_type:int64_t{ + insert_type = 1, + remove_type, + list_action_type_count + }; + + std::map list_type_to_enum = { + {"actor"_n, list_type::actor_blacklist_type}, + {"contract"_n, list_type::contract_blacklist_type}, + {"resource"_n, list_type::resource_greylist_type}}; + + std::map list_action_type_to_enum = { + {"insert"_n, list_action_type::insert_type}, + {"remove"_n, list_action_type::remove_type}}; + + std::map::iterator itlt = list_type_to_enum.find(list); + std::map::iterator itlat = list_action_type_to_enum.find(action); + + require_auth(_self); + check(3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3"); + check(names.size() < blacklist_limit_size, "the size of 'names' must be less than 100"); + check(itlt != list_type_to_enum.end(), " unknown list type string support 'actor' ,'contract', 'resource'"); + check(itlat != list_action_type_to_enum.end(), " unknown list type string support 'insert' or 'remove'"); + + auto packed_names = pack(names); + + set_blacklist_packed(static_cast(itlt->second), static_cast(itlat->second), packed_names.data(), packed_names.size()); + } + void system_contract::setpriv( name account, uint8_t ispriv ) { require_auth( _self ); @@ -464,7 +504,7 @@ EOSIO_DISPATCH( eosiosystem::system_contract, (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)(setabi) // eosio.system.cpp (init)(setram)(setramrate)(setparams)(setpriv)(setalimits)(setacctram)(setacctnet)(setacctcpu) - (rmvproducer)(updtrevision)(bidname)(bidrefund) + (rmvproducer)(updtrevision)(bidname)(bidrefund)(setblacklist) // rex.cpp (deposit)(withdraw)(buyrex)(unstaketorex)(sellrex)(cnclrexorder)(rentcpu)(rentnet)(fundcpuloan)(fundnetloan) (defcpuloan)(defnetloan)(updaterex)(consolidate)(mvtosavings)(mvfrsavings)(setrex)(rexexec)(closerex) diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index 2463d1212..8d23488e4 100755 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -43,6 +43,12 @@ namespace eosio { [[eosio::action]] void close( name owner, const symbol& symbol ); + [[eosio::action]] + void addblacklist(const std::vector& accounts); + + [[eosio::action]] + void rmblacklist(const std::vector& accounts); + static asset get_supply( name token_contract_account, symbol_code sym_code ) { stats statstable( token_contract_account, sym_code.raw() ); @@ -78,6 +84,14 @@ namespace eosio { uint64_t primary_key()const { return supply.symbol.code().raw(); } }; + struct [[eosio::table]] account_blacklist + { + name account; + uint64_t primary_key() const { return account.value; } + }; + + typedef eosio::multi_index<"blacklist"_n, account_blacklist> blacklist; + static const uint8_t blacklist_limit_size = 100 ; typedef eosio::multi_index< "accounts"_n, account > accounts; typedef eosio::multi_index< "stat"_n, currency_stats > stats; diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index cd1e8bb4f..aa3253eb7 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -89,6 +89,8 @@ void token::transfer( name from, asset quantity, string memo ) { + blacklist blacklisttable(_self, _self.value); + check(blacklisttable.find(from.value) == blacklisttable.end(), "account is on the blacklist"); check( from != to, "cannot transfer to self" ); require_auth( from ); check( is_account( to ), "to account does not exist"); @@ -165,6 +167,46 @@ void token::close( name owner, const symbol& symbol ) acnts.erase( it ); } +void token::addblacklist(const std::vector& accounts) +{ + require_auth("eosio"_n); + + check(blacklist_limit_size >= accounts.size(), "accounts' size must be less than 100."); + static const std::string msg = std::string("account does not exist"); + bool is_executed = false; + for (auto acc : accounts){ + std::string m = acc.to_string() + msg; + check(is_account(acc), m.c_str()); + blacklist blacklisttable(_self, _self.value); + auto it = blacklisttable.find(acc.value); + if (it == blacklisttable.end()) { + blacklisttable.emplace(_self, [&](auto &a) { + a.account = acc; + is_executed = true; + }); + } + } + + eosio_assert( is_executed, "all accounts were on blacklist." ); +} + +void token::rmblacklist(const std::vector& accounts) +{ + require_auth("eosio"_n); + + check( blacklist_limit_size>=accounts.size(), "accounts' size must be less than 100." ); + bool is_executed = false; + for (auto acc : accounts){ + blacklist blacklisttable(_self, _self.value); + auto it = blacklisttable.find(acc.value); + if (it != blacklisttable.end()){ + blacklisttable.erase(it); + is_executed = true; + } + } + + check( is_executed, "all accounts were not on blacklist." ); +} } /// namespace eosio -EOSIO_DISPATCH( eosio::token, (create)(issue)(transfer)(open)(close)(retire) ) +EOSIO_DISPATCH( eosio::token, (create)(issue)(transfer)(open)(close)(retire)(addblacklist)(rmblacklist) ) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index cadbf7d86..c3eccaec3 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -817,6 +817,40 @@ class eosio_system_tester : public TESTER { return msig_abi_ser; } + bool is_full_contains_subset(const shared_vector &allblklst, const std::vector &blklst) + { + std::vector allblacklist = std::vector(allblklst.begin(), allblklst.end()); + std::sort(allblacklist.begin(), allblacklist.end()); + std::vector blacklist = std::vector(blklst.begin(), blklst.end()); + std::sort(blacklist.begin(), blacklist.end()); + + // vector blacklisted; + // blacklisted.reserve(allblacklist.size()); + // set_intersection(allblacklist.begin(), allblacklist.end(), blacklist.begin(), + // blacklist.end(), std::back_inserter(blacklisted)); + + // std::sort(blacklisted.begin(), blacklisted.end()); + vector excluded; + excluded.reserve(blacklist.size()); + std::set_difference( blacklist.begin(), + blacklist.end(),allblacklist.begin(),allblacklist.end(),std::back_inserter(excluded)); + + return excluded.empty(); + } + + bool is_empty_intersection(const shared_vector &allblklst, const std::vector &blklst) + { + std::vector allblacklist = std::vector(allblklst.begin(), allblklst.end()); + std::sort(allblacklist.begin(), allblacklist.end()); + std::vector blacklist = std::vector(blklst.begin(), blklst.end()); + std::sort(blacklist.begin(), blacklist.end()); + + vector excluded; + excluded.reserve(blacklist.size()); + std::set_intersection(blacklist.begin(), blacklist.end(), allblacklist.begin(), allblacklist.end(), std::back_inserter(excluded)); + + return excluded.empty(); + } vector active_and_vote_producers() { //stake more than 15% of total EOS supply to activate chain transfer( "eosio", "alice1111111", core_sym::from_string("650000000.0000"), "eosio" ); diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index d70b74338..d73960908 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3049,6 +3049,474 @@ BOOST_FIXTURE_TEST_CASE( namebid_pending_winner, eosio_system_tester ) try { //despite "perfa" account hasn't been created, we should be able to create "perfb" account create_account_with_resources( N(prefb), N(bob111111111) ); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(actor_blacklist, eosio_system_tester) +try +{ + //install multisig contract + abi_serializer msig_abi_ser = initialize_multisig(); + auto producer_names = active_and_vote_producers(); + + //helper function + auto push_action_msig = [&](const account_name &signer, const action_name &name, const variant_object &data, bool auth = true) -> action_result { + string action_type_name = msig_abi_ser.get_action_type(name); + + action act; + act.account = N(eosio.msig); + act.name = name; + act.data = msig_abi_ser.variant_to_binary(action_type_name, data, abi_serializer_max_time); + + return base_tester::push_action(std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)); + }; + + // test begins + vector prod_perms; + for (auto &x : producer_names) + { + prod_perms.push_back({name(x), config::active_name}); + } + + std::vector actor_blacklist = {N(actorblklst1)}; + + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "actor") + ("action", "insert") + ("names", actor_blacklist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("executer", "alice1111111") + ) + ); + + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool actor = is_full_contains_subset(active_cfg2.actor_blacklist, actor_blacklist); + + BOOST_REQUIRE_EQUAL(actor, true); + + ////remote blacklist check + { + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "actor") + ("action", "remove") + ("names", actor_blacklist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("executer", "alice1111111") + ) + ); + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool actor = is_empty_intersection(active_cfg2.actor_blacklist, actor_blacklist); + + BOOST_REQUIRE_EQUAL(actor, true); + } +} +FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(contract_blacklist, eosio_system_tester) +try +{ + //install multisig contract + abi_serializer msig_abi_ser = initialize_multisig(); + auto producer_names = active_and_vote_producers(); + + //helper function + auto push_action_msig = [&](const account_name &signer, const action_name &name, const variant_object &data, bool auth = true) -> action_result { + string action_type_name = msig_abi_ser.get_action_type(name); + + action act; + act.account = N(eosio.msig); + act.name = name; + act.data = msig_abi_ser.variant_to_binary(action_type_name, data, abi_serializer_max_time); + + return base_tester::push_action(std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)); + }; + + // test begins + vector prod_perms; + for (auto &x : producer_names) + { + prod_perms.push_back({name(x), config::active_name}); + } + + std::vector contract_blacklist = {N(contrblklst1)}; + + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "contract") + ("action", "insert") + ("names", contract_blacklist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("executer", "alice1111111") + ) + ); + + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + // make sure that changed parameters were applied + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool contract = is_full_contains_subset(active_cfg2.contract_blacklist, contract_blacklist); + + BOOST_REQUIRE_EQUAL(contract, true); + + ////remote blacklist check + { + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "contract") + ("action", "remove") + ("names", contract_blacklist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("executer", "alice1111111") + ) + ); + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool contract = is_empty_intersection(active_cfg2.contract_blacklist, contract_blacklist); + + BOOST_REQUIRE_EQUAL(contract, true); + } +} +FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(resource_greylist, eosio_system_tester) +try +{ + //install multisig contract + abi_serializer msig_abi_ser = initialize_multisig(); + auto producer_names = active_and_vote_producers(); + + //helper function + auto push_action_msig = [&](const account_name &signer, const action_name &name, const variant_object &data, bool auth = true) -> action_result { + string action_type_name = msig_abi_ser.get_action_type(name); + + action act; + act.account = N(eosio.msig); + act.name = name; + act.data = msig_abi_ser.variant_to_binary(action_type_name, data, abi_serializer_max_time); + + return base_tester::push_action(std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)); + }; + + // test begins + vector prod_perms; + for (auto &x : producer_names) + { + prod_perms.push_back({name(x), config::active_name}); + } + + std::vector resource_greylist = {N(resgreylst12)}; + + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "resource") + ("action", "insert") + ("names", resource_greylist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist1") + ("executer", "alice1111111") + ) + ); + + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool grey = is_full_contains_subset(active_cfg2.resource_greylist, resource_greylist); + + BOOST_REQUIRE_EQUAL(grey, true); + + ////remote blacklist check + { + transaction trx; + { + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "namelist") + ("authorization", vector{ { config::system_account_name, config::active_name}}) + ("data", fc::mutable_variant_object() + ("list", "resource") + ("action", "remove") + ("names", resource_greylist) + ) + }) + ); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + } + + BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("trx", trx) + ("requested", prod_perms) + ) + ); + + // get 16 approvals + for (size_t i = 0; i < 15; ++i){ + BOOST_REQUIRE_EQUAL(success(), push_action_msig(name(producer_names[i]), N(approve), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("level", permission_level{name(producer_names[i]), config::active_name}) + ) + ); + } + + transaction_trace_ptr trace; + control->applied_transaction.connect([&](const transaction_trace_ptr &t) { if (t->scheduled) { trace = t; } }); + BOOST_REQUIRE_EQUAL(success(), push_action_msig(N(alice1111111), N(exec), mvo() + ("proposer", "alice1111111") + ("proposal_name", "namelist2") + ("executer", "alice1111111") + ) + ); + BOOST_REQUIRE(bool(trace)); + BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + + produce_blocks(250); + + const auto &active_cfg2 = control->get_global_properties2().cfg; + bool grey = is_empty_intersection(active_cfg2.resource_greylist, resource_greylist); + + BOOST_REQUIRE_EQUAL(grey, true); + } +} +FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_producers_in_and_out, eosio_system_tester ) try { diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 8d7d73ff6..54f1e885e 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -22,7 +22,7 @@ class eosio_token_tester : public tester { eosio_token_tester() { produce_blocks( 2 ); - create_accounts( { N(alice), N(bob), N(carol), N(eosio.token) } ); + create_accounts( { N(alice), N(bob), N(carol), N(eosio.token) ,N(boblacklist)} ); produce_blocks( 2 ); set_code( N(eosio.token), contracts::token_wasm() ); @@ -118,6 +118,23 @@ class eosio_token_tester : public tester { ); } + fc::variant get_blacklist( account_name acc) + { + vector data = get_row_by_account( N(eosio.token), N(eosio.token), N(blacklist), acc ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account_blacklist", data, abi_serializer_max_time ); + } + + action_result addblacklist(const vector& list) { + return push_action( N(eosio), N(addblacklist), mvo() + ( "accounts", list ) + ); + } + + action_result rmblacklist(const vector& list) { + return push_action( N(eosio), N(rmblacklist), mvo() + ( "accounts", list ) + ); + } abi_serializer abi_ser; }; @@ -346,6 +363,54 @@ BOOST_FIXTURE_TEST_CASE( transfer_tests, eosio_token_tester ) try { } FC_LOG_AND_RETHROW() +///transfer blacklist +BOOST_FIXTURE_TEST_CASE( transfer_blacklist_tests, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("1000 CERO")); + produce_blocks(1); + + issue( N(alice), N(alice), asset::from_string("1000 CERO"), "hola" ); + + auto stats = get_stats("0,CERO"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "1000 CERO") + ("max_supply", "1000 CERO") + ("issuer", "alice") + ); + + auto alice_balance = get_account(N(alice), "0,CERO"); + REQUIRE_MATCHING_OBJECT( alice_balance, mvo() + ("balance", "1000 CERO") + ); + + transfer( N(alice), N(boblacklist), asset::from_string("300 CERO"), "hola" ); + + std::vector list = {N(boblacklist)}; + addblacklist(list); + produce_blocks(250); + auto blklst = get_blacklist(N(boblacklist)); + REQUIRE_MATCHING_OBJECT(blklst, mvo()("account", "boblacklist")); + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "account is on the blacklist" ), + transfer( N(boblacklist), N(bob), asset::from_string("100 CERO"), "hola" ) + ); + + rmblacklist(list); + produce_blocks(250); + transfer(N(boblacklist), N(bob), asset::from_string("100 CERO"), "hola"); + + produce_blocks(250); + auto boblklst_balance = get_account(N(boblacklist), "0,CERO"); + REQUIRE_MATCHING_OBJECT( boblklst_balance, mvo() + ("balance", "200 CERO") + ); + + auto bob_balance = get_account(N(bob), "0,CERO"); + REQUIRE_MATCHING_OBJECT( bob_balance, mvo() + ("balance", "100 CERO") + ); + + +} FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( open_tests, eosio_token_tester ) try { auto token = create( N(alice), asset::from_string("1000 CERO"));