#include #include #include #include #include #include #include "eosio_system_tester.hpp" using namespace eosio_system; struct eosio_parameters : eosio::chain::chain_config { uint64_t max_ram_size; }; FC_REFLECT_DERIVED(eosio_parameters, (eosio::chain::chain_config), (max_ram_size)); BOOST_AUTO_TEST_SUITE(eosio_system_tests) BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); transfer( "eosio", "alice1111111", core_from_string("1000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( success(), stake( "eosio", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); auto total = get_total_stake( "alice1111111" ); auto init_bytes = total["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("200.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("800.0000"), get_balance( "alice1111111" ) ); total = get_total_stake( "alice1111111" ); auto bytes = total["ram_bytes"].as_uint64(); auto bought_bytes = bytes - init_bytes; wdump((init_bytes)(bought_bytes)(bytes) ); BOOST_REQUIRE_EQUAL( true, 0 < bought_bytes ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); BOOST_REQUIRE_EQUAL( core_from_string("998.0050"), get_balance( "alice1111111" ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( true, total["ram_bytes"].as_uint64() == init_bytes ); transfer( "eosio", "alice1111111", core_from_string("100000000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( core_from_string("100000998.0050"), get_balance( "alice1111111" ) ); // alice buys ram for 10000000.0000, 0.5% = 50000.0000 go to ramfee // after fee 9950000.0000 go to bought bytes // when selling back bought bytes, pay 0.5% fee and get back 99.5% of 9950000.0000 = 9900250.0000 // expected account after that is 90000998.0050 + 9900250.0000 = 99901248.0050 with a difference // of order 0.0001 due to rounding errors BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("90000998.0050"), get_balance( "alice1111111" ) ); total = get_total_stake( "alice1111111" ); bytes = total["ram_bytes"].as_uint64(); bought_bytes = bytes - init_bytes; wdump((init_bytes)(bought_bytes)(bytes) ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); total = get_total_stake( "alice1111111" ); bytes = total["ram_bytes"].as_uint64(); bought_bytes = bytes - init_bytes; wdump((init_bytes)(bought_bytes)(bytes) ); BOOST_REQUIRE_EQUAL( true, total["ram_bytes"].as_uint64() == init_bytes ); BOOST_REQUIRE_EQUAL( core_from_string("99901248.0044"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("30.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("99900688.0044"), get_balance( "alice1111111" ) ); auto newtotal = get_total_stake( "alice1111111" ); auto newbytes = newtotal["ram_bytes"].as_uint64(); bought_bytes = newbytes - bytes; wdump((newbytes)(bytes)(bought_bytes) ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); BOOST_REQUIRE_EQUAL( core_from_string("99901242.4183"), get_balance( "alice1111111" ) ); newtotal = get_total_stake( "alice1111111" ); auto startbytes = newtotal["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("10000000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("100000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("300000.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("49301242.4183"), get_balance( "alice1111111" ) ); auto finaltotal = get_total_stake( "alice1111111" ); auto endbytes = finaltotal["ram_bytes"].as_uint64(); bought_bytes = endbytes - startbytes; wdump((startbytes)(endbytes)(bought_bytes) ); BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); BOOST_REQUIRE_EQUAL( core_from_string("99396507.4147"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); transfer( "eosio", "alice1111111", core_from_string("1000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( core_from_string("1000.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), stake( "eosio", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); auto total = get_total_stake("alice1111111"); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); produce_block( fc::hours(3*24-1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //after 3 days funds should be released produce_block( fc::hours(1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("1000.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); total = get_total_stake("bob111111111"); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000").get_amount(), total["net_weight"].as().get_amount() ); BOOST_REQUIRE_EQUAL( core_from_string("110.0000").get_amount(), total["cpu_weight"].as().get_amount() ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000")), get_voter_info( "alice1111111" ) ); auto bytes = total["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( true, 0 < bytes ); //unstake from bob111111111 BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); total = get_total_stake("bob111111111"); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); produce_block( fc::hours(3*24-1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //after 3 days funds should be released produce_block( fc::hours(1) ); produce_blocks(1); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("0.0000") ), get_voter_info( "alice1111111" ) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("1000.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( stake_unstake_with_transfer, eosio_system_tester ) try { issue( "eosio", core_from_string("1000.0000"), config::system_account_name ); issue( "eosio.stake", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); //eosio stakes for alice with transfer flag transfer( "eosio", "bob111111111", core_from_string("1000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( success(), stake_with_transfer( "bob111111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); //check that alice has both bandwidth and voting power auto total = get_total_stake("alice1111111"); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000")), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); //alice stakes for herself transfer( "eosio", "alice1111111", core_from_string("1000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); //now alice's stake should be equal to transfered from eosio + own stake total = get_total_stake("alice1111111"); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("410.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("600.0000")), get_voter_info( "alice1111111" ) ); //alice can unstake everything (including what was transfered) BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("400.0000"), core_from_string("200.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); edump((get_balance( "eosio.stake" ))); produce_block( fc::hours(3*24-1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //after 3 days funds should be released produce_block( fc::hours(1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("1300.0000"), get_balance( "alice1111111" ) ); //stake should be equal to what was staked in constructor, votring power should be 0 total = get_total_stake("alice1111111"); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("0.0000")), get_voter_info( "alice1111111" ) ); // Now alice stakes to bob with transfer flag BOOST_REQUIRE_EQUAL( success(), stake_with_transfer( "alice1111111", "bob111111111", core_from_string("100.0000"), core_from_string("100.0000") ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( fail_without_auth, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "eosio", "alice1111111", core_from_string("2000.0000"), core_from_string("1000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("10.0000"), core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( error("missing authority of alice1111111"), push_action( N(alice1111111), N(delegatebw), mvo() ("from", "alice1111111") ("receiver", "bob111111111") ("stake_net_quantity", core_from_string("10.0000")) ("stake_cpu_quantity", core_from_string("10.0000")) ("transfer", 0 ) ,false ) ); BOOST_REQUIRE_EQUAL( error("missing authority of alice1111111"), push_action(N(alice1111111), N(undelegatebw), mvo() ("from", "alice1111111") ("receiver", "bob111111111") ("unstake_net_quantity", core_from_string("200.0000")) ("unstake_cpu_quantity", core_from_string("100.0000")) ("transfer", 0 ) ,false ) ); //REQUIRE_MATCHING_OBJECT( , get_voter_info( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( stake_negative, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must stake a positive amount"), stake( "alice1111111", core_from_string("-0.0001"), core_from_string("0.0000") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must stake a positive amount"), stake( "alice1111111", core_from_string("0.0000"), core_from_string("-0.0001") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must stake a positive amount"), stake( "alice1111111", core_from_string("00.0000"), core_from_string("00.0000") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must stake a positive amount"), stake( "alice1111111", core_from_string("0.0000"), core_from_string("00.0000") ) ); BOOST_REQUIRE_EQUAL( true, get_voter_info( "alice1111111" ).is_null() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( unstake_negative, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0001"), core_from_string("100.0001") ) ); auto total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0001"), total["net_weight"].as()); auto vinfo = get_voter_info("alice1111111" ); wdump((vinfo)); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0002") ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must unstake a positive amount"), unstake( "alice1111111", "bob111111111", core_from_string("-1.0000"), core_from_string("0.0000") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must unstake a positive amount"), unstake( "alice1111111", "bob111111111", core_from_string("0.0000"), core_from_string("-1.0000") ) ); //unstake all zeros BOOST_REQUIRE_EQUAL( wasm_assert_msg("must unstake a positive amount"), unstake( "alice1111111", "bob111111111", core_from_string("0.0000"), core_from_string("0.0000") ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( unstake_more_than_at_stake, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); auto total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //trying to unstake more net bandwith than at stake BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked net bandwidth"), unstake( "alice1111111", core_from_string("200.0001"), core_from_string("0.0000") ) ); //trying to unstake more cpu bandwith than at stake BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked cpu bandwidth"), unstake( "alice1111111", core_from_string("0.0000"), core_from_string("100.0001") ) ); //check that nothing has changed total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( delegate_to_another_user, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake ( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); auto total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //all voting power goes to alice1111111 REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); //but not to bob111111111 BOOST_REQUIRE_EQUAL( true, get_voter_info( "bob111111111" ).is_null() ); //bob111111111 should not be able to unstake what was staked by alice1111111 BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked cpu bandwidth"), unstake( "bob111111111", core_from_string("0.0000"), core_from_string("10.0000") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked net bandwidth"), unstake( "bob111111111", core_from_string("10.0000"), core_from_string("0.0000") ) ); issue( "carol1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", "bob111111111", core_from_string("20.0000"), core_from_string("10.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("230.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("120.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("970.0000"), get_balance( "carol1111111" ) ); REQUIRE_MATCHING_OBJECT( voter( "carol1111111", core_from_string("30.0000") ), get_voter_info( "carol1111111" ) ); //alice1111111 should not be able to unstake money staked by carol1111111 BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked net bandwidth"), unstake( "alice1111111", "bob111111111", core_from_string("2001.0000"), core_from_string("1.0000") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient staked cpu bandwidth"), unstake( "alice1111111", "bob111111111", core_from_string("1.0000"), core_from_string("101.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("230.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("120.0000"), total["cpu_weight"].as()); //balance should not change after unsuccessfull attempts to unstake BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //voting power too REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); REQUIRE_MATCHING_OBJECT( voter( "carol1111111", core_from_string("30.0000") ), get_voter_info( "carol1111111" ) ); BOOST_REQUIRE_EQUAL( true, get_voter_info( "bob111111111" ).is_null() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( stake_unstake_separate, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( core_from_string("1000.0000"), get_balance( "alice1111111" ) ); //everything at once BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("10.0000"), core_from_string("20.0000") ) ); auto total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("20.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("30.0000"), total["cpu_weight"].as()); //cpu BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("100.0000"), core_from_string("0.0000") ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("120.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("30.0000"), total["cpu_weight"].as()); //net BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("0.0000"), core_from_string("200.0000") ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("120.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("230.0000"), total["cpu_weight"].as()); //unstake cpu BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("100.0000"), core_from_string("0.0000") ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("20.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("230.0000"), total["cpu_weight"].as()); //unstake net BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("0.0000"), core_from_string("200.0000") ) ); total = get_total_stake( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("20.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("30.0000"), total["cpu_weight"].as()); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( adding_stake_partial_unstake, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("100.0000"), core_from_string("50.0000") ) ); auto total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("310.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("160.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("450.0000") ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("550.0000"), get_balance( "alice1111111" ) ); //unstake a share BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("150.0000"), core_from_string("75.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("160.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("85.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("225.0000") ), get_voter_info( "alice1111111" ) ); //unstake more BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("150.0000") ), get_voter_info( "alice1111111" ) ); //combined amount should be available only in 3 days produce_block( fc::days(2) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("550.0000"), get_balance( "alice1111111" ) ); produce_block( fc::days(1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("850.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( stake_from_refund, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); auto total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("300.0000") ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //unstake a share BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("100.0000"), core_from_string("50.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("60.0000"), total["cpu_weight"].as()); REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_from_string("150.0000") ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); auto refund = get_refund_request( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["net_amount"].as() ); BOOST_REQUIRE_EQUAL( core_from_string( "50.0000"), refund["cpu_amount"].as() ); //XXX auto request_time = refund["request_time"].as_int64(); //stake less than pending refund, entire amount should be traken from refund BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("160.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("85.0000"), total["cpu_weight"].as()); refund = get_refund_request( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("50.0000"), refund["net_amount"].as() ); BOOST_REQUIRE_EQUAL( core_from_string("25.0000"), refund["cpu_amount"].as() ); //request time should stay the same //BOOST_REQUIRE_EQUAL( request_time, refund["request_time"].as_int64() ); //balance shoud stay the same BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //stake exactly pending refund amount BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("50.0000"), core_from_string("25.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); //pending refund should be removed refund = get_refund_request( "alice1111111" ); BOOST_TEST_REQUIRE( refund.is_null() ); //balance shoud stay the same BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); //create pending refund again BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("10.0000"), total["cpu_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); refund = get_refund_request( "alice1111111" ); BOOST_REQUIRE_EQUAL( core_from_string("200.0000"), refund["net_amount"].as() ); BOOST_REQUIRE_EQUAL( core_from_string("100.0000"), refund["cpu_amount"].as() ); //stake more than pending refund BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("300.0000"), core_from_string("200.0000") ) ); total = get_total_stake( "bob111111111" ); BOOST_REQUIRE_EQUAL( core_from_string("310.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["cpu_weight"].as()); refund = get_refund_request( "alice1111111" ); BOOST_TEST_REQUIRE( refund.is_null() ); //200 EOS should be taken from alice's account BOOST_REQUIRE_EQUAL( core_from_string("500.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() // Tests for voting BOOST_FIXTURE_TEST_CASE( producer_register_unregister, eosio_system_tester ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); fc::variant params = producer_parameters_example(1); auto key = fc::crypto::public_key( std::string("EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV") ); BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", key ) ("url", "http://block.one") ("location", "0") ) ); auto info = get_producer_info( "alice1111111" ); BOOST_REQUIRE_EQUAL( "alice1111111", info["owner"].as_string() ); BOOST_REQUIRE_EQUAL( 0, info["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( "http://block.one", info["url"].as_string() ); //call regproducer again to change parameters fc::variant params2 = producer_parameters_example(2); info = get_producer_info( "alice1111111" ); BOOST_REQUIRE_EQUAL( "alice1111111", info["owner"].as_string() ); BOOST_REQUIRE_EQUAL( 0, info["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( "http://block.one", info["url"].as_string() ); //unregister producer BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(unregprod), mvo() ("producer", "alice1111111") ) ); info = get_producer_info( "alice1111111" ); //key should be empty wdump((info)); BOOST_REQUIRE_EQUAL( fc::crypto::public_key(), fc::crypto::public_key(info["producer_key"].as_string()) ); //everything else should stay the same BOOST_REQUIRE_EQUAL( "alice1111111", info["owner"].as_string() ); BOOST_REQUIRE_EQUAL( 0, info["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( "http://block.one", info["url"].as_string() ); //unregister bob111111111 who is not a producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "producer not found" ), push_action( N(bob111111111), N(unregprod), mvo() ("producer", "bob111111111") ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_for_producer, eosio_system_tester, * boost::unit_test::tolerance(1e+5) ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); fc::variant params = producer_parameters_example(1); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url", "http://block.one") ("location", 0 ) ) ); auto prod = get_producer_info( "alice1111111" ); BOOST_REQUIRE_EQUAL( "alice1111111", prod["owner"].as_string() ); BOOST_REQUIRE_EQUAL( 0, prod["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( "http://block.one", prod["url"].as_string() ); issue( "bob111111111", core_from_string("2000.0000"), config::system_account_name ); issue( "carol1111111", core_from_string("3000.0000"), config::system_account_name ); //bob111111111 makes stake BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("11.0000"), core_from_string("0.1111") ) ); BOOST_REQUIRE_EQUAL( core_from_string("1988.8889"), get_balance( "bob111111111" ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("11.1111") ), get_voter_info( "bob111111111" ) ); //bob111111111 votes for alice1111111 BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); //check that producer parameters stay the same after voting prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("11.1111")) == prod["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( "alice1111111", prod["owner"].as_string() ); BOOST_REQUIRE_EQUAL( "http://block.one", prod["url"].as_string() ); //carol1111111 makes stake BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("22.0000"), core_from_string("0.2222") ) ); REQUIRE_MATCHING_OBJECT( voter( "carol1111111", core_from_string("22.2222") ), get_voter_info( "carol1111111" ) ); BOOST_REQUIRE_EQUAL( core_from_string("2977.7778"), get_balance( "carol1111111" ) ); //carol1111111 votes for alice1111111 BOOST_REQUIRE_EQUAL( success(), push_action(N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); //new stake votes be added to alice1111111's total_votes prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("33.3333")) == prod["total_votes"].as_double() ); //bob111111111 increases his stake BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("55.0000"), core_from_string("0.5555") ) ); //should increase alice1111111's total_votes prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("88.8888")) == prod["total_votes"].as_double() ); //carol1111111 unstakes part of the stake BOOST_REQUIRE_EQUAL( success(), unstake( "carol1111111", core_from_string("2.0000"), core_from_string("0.0002")/*"2.0000 EOS", "0.0002 EOS"*/ ) ); //should decrease alice1111111's total_votes prod = get_producer_info( "alice1111111" ); wdump((prod)); BOOST_TEST_REQUIRE( stake2votes(core_from_string("86.8886")) == prod["total_votes"].as_double() ); //bob111111111 revokes his vote BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector() ) ) ); //should decrease alice1111111's total_votes prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("20.2220")) == prod["total_votes"].as_double() ); //but eos should still be at stake BOOST_REQUIRE_EQUAL( core_from_string("1933.3334"), get_balance( "bob111111111" ) ); //carol1111111 unstakes rest of eos BOOST_REQUIRE_EQUAL( success(), unstake( "carol1111111", core_from_string("20.0000"), core_from_string("0.2220") ) ); //should decrease alice1111111's total_votes to zero prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( 0.0 == prod["total_votes"].as_double() ); //carol1111111 should receive funds in 3 days produce_block( fc::days(3) ); produce_block(); BOOST_REQUIRE_EQUAL( core_from_string("3000.0000"), get_balance( "carol1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( unregistered_producer_voting, eosio_system_tester, * boost::unit_test::tolerance(1e+5) ) try { issue( "bob111111111", core_from_string("2000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("13.0000"), core_from_string("0.5791") ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("13.5791") ), get_voter_info( "bob111111111" ) ); //bob111111111 should not be able to vote for alice1111111 who is not a producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "producer is not registered" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); //alice1111111 registers as a producer issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); fc::variant params = producer_parameters_example(1); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url", "") ("location", 0) ) ); //and then unregisters BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(unregprod), mvo() ("producer", "alice1111111") ) ); //key should be empty auto prod = get_producer_info( "alice1111111" ); BOOST_REQUIRE_EQUAL( fc::crypto::public_key(), fc::crypto::public_key(prod["producer_key"].as_string()) ); //bob111111111 should not be able to vote for alice1111111 who is an unregistered producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "producer is not currently registered" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( more_than_30_producer_voting, eosio_system_tester ) try { issue( "bob111111111", core_from_string("2000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("13.0000"), core_from_string("0.5791") ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("13.5791") ), get_voter_info( "bob111111111" ) ); //bob111111111 should not be able to vote for alice1111111 who is not a producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "attempt to vote for too many producers" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector(31, N(alice1111111)) ) ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_same_producer_30_times, eosio_system_tester ) try { issue( "bob111111111", core_from_string("2000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("50.0000"), core_from_string("50.0000") ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("100.0000") ), get_voter_info( "bob111111111" ) ); //alice1111111 becomes a producer issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); fc::variant params = producer_parameters_example(1); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key(N(alice1111111), "active") ) ("url", "") ("location", 0) ) ); //bob111111111 should not be able to vote for alice1111111 who is not a producer BOOST_REQUIRE_EQUAL( wasm_assert_msg( "producer votes must be unique and sorted" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector(30, N(alice1111111)) ) ) ); auto prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( 0 == prod["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( producer_keep_votes, eosio_system_tester, * boost::unit_test::tolerance(1e+5) ) try { issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); fc::variant params = producer_parameters_example(1); vector key = fc::raw::pack( get_public_key( N(alice1111111), "active" ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url", "") ("location", 0) ) ); //bob111111111 makes stake issue( "bob111111111", core_from_string("2000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("13.0000"), core_from_string("0.5791") ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("13.5791") ), get_voter_info( "bob111111111" ) ); //bob111111111 votes for alice1111111 BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); auto prod = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("13.5791")) == prod["total_votes"].as_double() ); //unregister producer BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(unregprod), mvo() ("producer", "alice1111111") ) ); prod = get_producer_info( "alice1111111" ); //key should be empty BOOST_REQUIRE_EQUAL( fc::crypto::public_key(), fc::crypto::public_key(prod["producer_key"].as_string()) ); //check parameters just in case //REQUIRE_MATCHING_OBJECT( params, prod["prefs"]); //votes should stay the same BOOST_TEST_REQUIRE( stake2votes(core_from_string("13.5791")), prod["total_votes"].as_double() ); //regtister the same producer again params = producer_parameters_example(2); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url", "") ("location", 0) ) ); prod = get_producer_info( "alice1111111" ); //votes should stay the same BOOST_TEST_REQUIRE( stake2votes(core_from_string("13.5791")), prod["total_votes"].as_double() ); //change parameters params = producer_parameters_example(3); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url","") ("location", 0) ) ); prod = get_producer_info( "alice1111111" ); //votes should stay the same BOOST_TEST_REQUIRE( stake2votes(core_from_string("13.5791")), prod["total_votes"].as_double() ); //check parameters just in case //REQUIRE_MATCHING_OBJECT( params, prod["prefs"]); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_for_two_producers, eosio_system_tester, * boost::unit_test::tolerance(1e+5) ) try { //alice1111111 becomes a producer fc::variant params = producer_parameters_example(1); auto key = get_public_key( N(alice1111111), "active" ); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproducer), mvo() ("producer", "alice1111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url","") ("location", 0) ) ); //bob111111111 becomes a producer params = producer_parameters_example(2); key = get_public_key( N(bob111111111), "active" ); BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(regproducer), mvo() ("producer", "bob111111111") ("producer_key", get_public_key( N(alice1111111), "active") ) ("url","") ("location", 0) ) ); //carol1111111 votes for alice1111111 and bob111111111 issue( "carol1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("15.0005"), core_from_string("5.0000") ) ); BOOST_REQUIRE_EQUAL( success(), push_action(N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111), N(bob111111111) } ) ) ); auto alice_info = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("20.0005")) == alice_info["total_votes"].as_double() ); auto bob_info = get_producer_info( "bob111111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("20.0005")) == bob_info["total_votes"].as_double() ); //carol1111111 votes for alice1111111 (but revokes vote for bob111111111) BOOST_REQUIRE_EQUAL( success(), push_action(N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111) } ) ) ); alice_info = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("20.0005")) == alice_info["total_votes"].as_double() ); bob_info = get_producer_info( "bob111111111" ); BOOST_TEST_REQUIRE( 0 == bob_info["total_votes"].as_double() ); //alice1111111 votes for herself and bob111111111 issue( "alice1111111", core_from_string("2.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("1.0000"), core_from_string("1.0000") ) ); BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(alice1111111), N(bob111111111) } ) ) ); alice_info = get_producer_info( "alice1111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("22.0005")) == alice_info["total_votes"].as_double() ); bob_info = get_producer_info( "bob111111111" ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("2.0000")) == bob_info["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( proxy_register_unregister_keeps_stake, eosio_system_tester ) try { //register proxy by first action for this user ever BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true ) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" ), get_voter_info( "alice1111111" ) ); //unregister proxy BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", false) ) ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111" ), get_voter_info( "alice1111111" ) ); //stake and then register as a proxy issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("200.0002"), core_from_string("100.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(regproxy), mvo() ("proxy", "bob111111111") ("isproxy", true) ) ); REQUIRE_MATCHING_OBJECT( proxy( "bob111111111" )( "staked", 3000003 ), get_voter_info( "bob111111111" ) ); //unrgister and check that stake is still in place BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(regproxy), mvo() ("proxy", "bob111111111") ("isproxy", false) ) ); REQUIRE_MATCHING_OBJECT( voter( "bob111111111", core_from_string("300.0003") ), get_voter_info( "bob111111111" ) ); //register as a proxy and then stake BOOST_REQUIRE_EQUAL( success(), push_action( N(carol1111111), N(regproxy), mvo() ("proxy", "carol1111111") ("isproxy", true) ) ); issue( "carol1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("246.0002"), core_from_string("531.0001") ) ); //check that both proxy flag and stake a correct REQUIRE_MATCHING_OBJECT( proxy( "carol1111111" )( "staked", 7770003 ), get_voter_info( "carol1111111" ) ); //unregister BOOST_REQUIRE_EQUAL( success(), push_action( N(carol1111111), N(regproxy), mvo() ("proxy", "carol1111111") ("isproxy", false) ) ); REQUIRE_MATCHING_OBJECT( voter( "carol1111111", core_from_string("777.0003") ), get_voter_info( "carol1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( proxy_stake_unstake_keeps_proxy_flag, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true) ) ); issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" ), get_voter_info( "alice1111111" ) ); //stake BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("100.0000"), core_from_string("50.0000") ) ); //check that account is still a proxy REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "staked", 1500000 ), get_voter_info( "alice1111111" ) ); //stake more BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("30.0000"), core_from_string("20.0000") ) ); //check that account is still a proxy REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )("staked", 2000000 ), get_voter_info( "alice1111111" ) ); //unstake more BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("65.0000"), core_from_string("35.0000") ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )("staked", 1000000 ), get_voter_info( "alice1111111" ) ); //unstake the rest BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("65.0000"), core_from_string("35.0000") ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "staked", 0 ), get_voter_info( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( proxy_actions_affect_producers, eosio_system_tester, * boost::unit_test::tolerance(1e+5) ) try { create_accounts_with_resources( { N(defproducer1), N(defproducer2), N(defproducer3) } ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer1", 1) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer2", 2) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer3", 3) ); //register as a proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true) ) ); //accumulate proxied votes issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "proxied_vote_weight", stake2votes(core_from_string("150.0003")) ), get_voter_info( "alice1111111" ) ); //vote for producers BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer1), N(defproducer2) } ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( 0 == get_producer_info( "defproducer3" )["total_votes"].as_double() ); //vote for another producers BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer1), N(defproducer3) } ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer3" )["total_votes"].as_double() ); //unregister proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", false) ) ); //REQUIRE_MATCHING_OBJECT( voter( "alice1111111" )( "proxied_vote_weight", stake2votes(core_from_string("150.0003")) ), get_voter_info( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //register proxy again BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_producer_info( "defproducer3" )["total_votes"].as_double() ); //stake increase by proxy itself affects producers issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("30.0001"), core_from_string("20.0001") ) ); BOOST_REQUIRE_EQUAL( stake2votes(core_from_string("200.0005")), get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( stake2votes(core_from_string("200.0005")), get_producer_info( "defproducer3" )["total_votes"].as_double() ); //stake decrease by proxy itself affects producers BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", core_from_string("10.0001"), core_from_string("10.0001") ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("180.0003")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("180.0003")) == get_producer_info( "defproducer3" )["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try { const double continuous_rate = 4.879 / 100.; const double usecs_per_year = 52 * 7 * 24 * 3600 * 1000000ll; const double secs_per_year = 52 * 7 * 24 * 3600; const asset large_asset = core_from_string("80.0000"); create_account_with_resources( N(defproducera), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(defproducerb), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(defproducerc), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(producvotera), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(producvoterb), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); BOOST_REQUIRE_EQUAL(success(), regproducer(N(defproducera))); auto prod = get_producer_info( N(defproducera) ); BOOST_REQUIRE_EQUAL("defproducera", prod["owner"].as_string()); BOOST_REQUIRE_EQUAL(0, prod["total_votes"].as_double()); transfer( config::system_account_name, "producvotera", core_from_string("400000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvotera", core_from_string("100000000.0000"), core_from_string("100000000.0000"))); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() ("voter", "producvotera") ("proxy", name(0).to_string()) ("producers", vector{ N(defproducera) }) ) ); // defproducera is the only active producer // produce enough blocks so new schedule kicks in and defproducera produces some blocks { produce_blocks(50); const auto initial_global_state = get_global_state(); const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t initial_savings = initial_global_state["savings"].as(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); prod = get_producer_info("defproducera"); const uint32_t unpaid_blocks = prod["unpaid_blocks"].as(); BOOST_REQUIRE(1 < unpaid_blocks); BOOST_REQUIRE_EQUAL(0, prod["last_claim_time"].as()); BOOST_REQUIRE_EQUAL(initial_tot_unpaid_blocks, unpaid_blocks); const asset initial_supply = get_token_supply(); const asset initial_balance = get_balance(N(defproducera)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); const auto global_state = get_global_state(); const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); const int64_t savings = global_state["savings"].as(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); prod = get_producer_info("defproducera"); BOOST_REQUIRE_EQUAL(1, prod["unpaid_blocks"].as()); BOOST_REQUIRE_EQUAL(1, tot_unpaid_blocks); const asset supply = get_token_supply(); const asset balance = get_balance(N(defproducera)); BOOST_REQUIRE_EQUAL(claim_time, prod["last_claim_time"].as()); auto usecs_between_fills = claim_time - initial_claim_time; int32_t secs_between_fills = usecs_between_fills/1000000; BOOST_REQUIRE_EQUAL(0, initial_savings); BOOST_REQUIRE_EQUAL(0, initial_perblock_bucket); BOOST_REQUIRE_EQUAL(0, initial_pervote_bucket); BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * continuous_rate ) / secs_per_year ), supply.get_amount() - initial_supply.get_amount()); BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * (4. * continuous_rate/ 5.) / secs_per_year ) ), savings - initial_savings); BOOST_REQUIRE_EQUAL(int64_t( ( initial_supply.get_amount() * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ), balance.get_amount() - initial_balance.get_amount()); int64_t from_perblock_bucket = int64_t( initial_supply.get_amount() * double(secs_between_fills) * (0.25 * continuous_rate/ 5.) / secs_per_year ) ; int64_t from_pervote_bucket = int64_t( initial_supply.get_amount() * double(secs_between_fills) * (0.75 * continuous_rate/ 5.) / secs_per_year ) ; if (from_pervote_bucket >= 100 * 10000) { BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(0, pervote_bucket); } else { BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(from_pervote_bucket, pervote_bucket); } } { BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); } // defproducera waits for 23 hours and 55 minutes, can't claim rewards yet { produce_block(fc::seconds(23 * 3600 + 55 * 60)); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); } // wait 5 more minutes, defproducera can now claim rewards again { produce_block(fc::seconds(5 * 60)); const auto initial_global_state = get_global_state(); const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t initial_savings = initial_global_state["savings"].as(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const double initial_tot_vote_weight = initial_global_state["total_producer_vote_weight"].as(); prod = get_producer_info("defproducera"); const uint32_t unpaid_blocks = prod["unpaid_blocks"].as(); BOOST_REQUIRE(1 < unpaid_blocks); BOOST_REQUIRE_EQUAL(initial_tot_unpaid_blocks, unpaid_blocks); BOOST_REQUIRE(0 < prod["total_votes"].as()); BOOST_TEST(initial_tot_vote_weight, prod["total_votes"].as()); BOOST_REQUIRE(0 < prod["last_claim_time"].as()); BOOST_REQUIRE_EQUAL(initial_tot_unpaid_blocks, unpaid_blocks); const asset initial_supply = get_token_supply(); const asset initial_balance = get_balance(N(defproducera)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); const auto global_state = get_global_state(); const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); const int64_t savings = global_state["savings"].as(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); prod = get_producer_info("defproducera"); BOOST_REQUIRE_EQUAL(1, prod["unpaid_blocks"].as()); BOOST_REQUIRE_EQUAL(1, tot_unpaid_blocks); const asset supply = get_token_supply(); const asset balance = get_balance(N(defproducera)); BOOST_REQUIRE_EQUAL(claim_time, prod["last_claim_time"].as()); auto usecs_between_fills = claim_time - initial_claim_time; BOOST_REQUIRE_EQUAL(int64_t( ( double(initial_supply.get_amount()) * double(usecs_between_fills) * continuous_rate / usecs_per_year ) ), supply.get_amount() - initial_supply.get_amount()); BOOST_REQUIRE_EQUAL( (supply.get_amount() - initial_supply.get_amount()) - (supply.get_amount() - initial_supply.get_amount()) / 5, savings - initial_savings); int64_t to_producer = int64_t( (double(initial_supply.get_amount()) * double(usecs_between_fills) * continuous_rate) / usecs_per_year ) / 5; int64_t to_perblock_bucket = to_producer / 4; int64_t to_pervote_bucket = to_producer - to_perblock_bucket; if (to_pervote_bucket + initial_pervote_bucket >= 100 * 10000) { BOOST_REQUIRE_EQUAL(to_perblock_bucket + to_pervote_bucket + initial_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(0, pervote_bucket); } else { BOOST_REQUIRE_EQUAL(to_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(to_pervote_bucket + initial_pervote_bucket, pervote_bucket); } } // defproducerb tries to claim rewards but he's not on the list { BOOST_REQUIRE_EQUAL(wasm_assert_msg("unable to find key"), push_action(N(defproducerb), N(claimrewards), mvo()("owner", "defproducerb"))); } // test stability over a year { regproducer(N(defproducerb)); regproducer(N(defproducerc)); const asset initial_supply = get_token_supply(); const int64_t initial_savings = get_global_state()["savings"].as(); for (uint32_t i = 0; i < 7 * 52; ++i) { produce_block(fc::seconds(8 * 3600)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducerc), N(claimrewards), mvo()("owner", "defproducerc"))); produce_block(fc::seconds(8 * 3600)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducerb), N(claimrewards), mvo()("owner", "defproducerb"))); produce_block(fc::seconds(8 * 3600)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); } const asset supply = get_token_supply(); const int64_t savings = get_global_state()["savings"].as(); // Amount issued per year is very close to the 5% inflation target. Small difference (500 tokens out of 50'000'000 issued) // is due to compounding every 8 hours in this test as opposed to theoretical continuous compounding BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.get_amount()) * double(0.05)) - (supply.get_amount() - initial_supply.get_amount())); BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.get_amount()) * double(0.04)) - (savings - initial_savings)); } } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try { const int64_t secs_per_year = 52 * 7 * 24 * 3600; const double usecs_per_year = secs_per_year * 1000000; const double cont_rate = 4.879/100.; const asset net = core_from_string("80.0000"); const asset cpu = core_from_string("80.0000"); create_account_with_resources( N(producvotera), config::system_account_name, core_from_string("1.0000"), false, net, cpu ); create_account_with_resources( N(producvoterb), config::system_account_name, core_from_string("1.0000"), false, net, cpu ); create_account_with_resources( N(producvoterc), config::system_account_name, core_from_string("1.0000"), false, net, cpu ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers std::vector producer_names; { producer_names.reserve('z' - 'a' + 1); const std::string root("defproducer"); for ( char c = 'a'; c <= 'z'; ++c ) { producer_names.emplace_back(root + std::string(1, c)); } setup_producer_accounts(producer_names); for (const auto& p: producer_names) { BOOST_REQUIRE_EQUAL( success(), regproducer(p) ); produce_blocks(1); ilog( "------ get pro----------" ); wdump((p)); BOOST_TEST(0 == get_producer_info(p)["total_votes"].as()); } } { transfer( config::system_account_name, "producvotera", core_from_string("100000000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL(success(), stake("producvotera", core_from_string("30000000.0000"), core_from_string("30000000.0000")) ); transfer( config::system_account_name, "producvoterb", core_from_string("100000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvoterb", core_from_string("30000000.0000"), core_from_string("30000000.0000")) ); transfer( config::system_account_name, "producvoterc", core_from_string("100000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvoterc", core_from_string("30000000.0000"), core_from_string("30000000.0000")) ); } // producvotera votes for defproducera ... defproducerj // producvoterb votes for defproducera ... defproduceru // producvoterc votes for defproducera ... defproducerz { BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() ("voter", "producvotera") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+10)) ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterb), N(voteproducer), mvo() ("voter", "producvoterb") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+21)) ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterc), N(voteproducer), mvo() ("voter", "producvoterc") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.end())) ) ); } { auto proda = get_producer_info( N(defproducera) ); auto prodj = get_producer_info( N(defproducerj) ); auto prodk = get_producer_info( N(defproducerk) ); auto produ = get_producer_info( N(defproduceru) ); auto prodv = get_producer_info( N(defproducerv) ); auto prodz = get_producer_info( N(defproducerz) ); BOOST_REQUIRE (0 == proda["unpaid_blocks"].as() && 0 == prodz["unpaid_blocks"].as()); BOOST_REQUIRE (0 == proda["last_claim_time"].as() && 0 == prodz["last_claim_time"].as()); // check vote ratios BOOST_REQUIRE ( 0 < proda["total_votes"].as() && 0 < prodz["total_votes"].as() ); BOOST_TEST( proda["total_votes"].as() == prodj["total_votes"].as() ); BOOST_TEST( prodk["total_votes"].as() == produ["total_votes"].as() ); BOOST_TEST( prodv["total_votes"].as() == prodz["total_votes"].as() ); BOOST_TEST( 2 * proda["total_votes"].as() == 3 * produ["total_votes"].as() ); BOOST_TEST( proda["total_votes"].as() == 3 * prodz["total_votes"].as() ); } // give a chance for everyone to produce blocks { produce_blocks(23 * 12 + 20); bool all_21_produced = true; for (uint32_t i = 0; i < 21; ++i) { if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { all_21_produced = false; } } bool rest_didnt_produce = true; for (uint32_t i = 21; i < producer_names.size(); ++i) { if (0 < get_producer_info(producer_names[i])["unpaid_blocks"].as()) { rest_didnt_produce = false; } } BOOST_REQUIRE(all_21_produced && rest_didnt_produce); } std::vector vote_shares(producer_names.size()); { double total_votes = 0; for (uint32_t i = 0; i < producer_names.size(); ++i) { vote_shares[i] = get_producer_info(producer_names[i])["total_votes"].as(); total_votes += vote_shares[i]; } BOOST_TEST(total_votes == get_global_state()["total_producer_vote_weight"].as()); std::for_each(vote_shares.begin(), vote_shares.end(), [total_votes](double& x) { x /= total_votes; }); BOOST_TEST(double(1) == std::accumulate(vote_shares.begin(), vote_shares.end(), double(0))); BOOST_TEST(double(3./57.) == vote_shares.front()); BOOST_TEST(double(1./57.) == vote_shares.back()); } { const uint32_t prod_index = 2; const auto prod_name = producer_names[prod_index]; const auto initial_global_state = get_global_state(); const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t initial_savings = initial_global_state["savings"].as(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const asset initial_supply = get_token_supply(); const asset initial_balance = get_balance(prod_name); const uint32_t initial_unpaid_blocks = get_producer_info(prod_name)["unpaid_blocks"].as(); BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); const auto global_state = get_global_state(); const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t savings = global_state["savings"].as(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); const asset supply = get_token_supply(); const asset balance = get_balance(prod_name); const uint32_t unpaid_blocks = get_producer_info(prod_name)["unpaid_blocks"].as(); const uint64_t usecs_between_fills = claim_time - initial_claim_time; const int32_t secs_between_fills = static_cast(usecs_between_fills / 1000000); const double expected_supply_growth = initial_supply.get_amount() * double(usecs_between_fills) * cont_rate / usecs_per_year; BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); const int64_t expected_perblock_bucket = int64_t( initial_supply.get_amount() * secs_between_fills * (0.25 * cont_rate/ 5.) / secs_per_year ) ; const int64_t expected_pervote_bucket = int64_t( initial_supply.get_amount() * secs_between_fills * (0.75 * cont_rate/ 5.) / secs_per_year ) ; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); if (from_pervote_bucket >= 100 * 10000) { BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket - from_pervote_bucket, pervote_bucket); } else { BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket, pervote_bucket); } produce_blocks(5); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } { const uint32_t prod_index = 23; const auto prod_name = producer_names[prod_index]; BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); BOOST_REQUIRE_EQUAL(0, get_balance(prod_name).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } // wait for 23 hours which is not enough for producers to get deactivated // payment calculations don't change. By now, pervote_bucket has grown enough // that a producer's share is more than 100 tokens produce_block(fc::seconds(23 * 3600)); { const uint32_t prod_index = 15; const auto prod_name = producer_names[prod_index]; const auto initial_global_state = get_global_state(); const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t initial_savings = initial_global_state["savings"].as(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const asset initial_supply = get_token_supply(); const asset initial_balance = get_balance(prod_name); const uint32_t initial_unpaid_blocks = get_producer_info(prod_name)["unpaid_blocks"].as(); BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); const auto global_state = get_global_state(); const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = initial_global_state["perblock_bucket"].as(); const int64_t savings = global_state["savings"].as(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); const asset supply = get_token_supply(); const asset balance = get_balance(prod_name); const uint32_t unpaid_blocks = get_producer_info(prod_name)["unpaid_blocks"].as(); const uint64_t usecs_between_fills = claim_time - initial_claim_time; const double expected_supply_growth = initial_supply.get_amount() * double(usecs_between_fills) * cont_rate / usecs_per_year; BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); const int64_t expected_perblock_bucket = int64_t( initial_supply.get_amount() * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) + initial_perblock_bucket; const int64_t expected_pervote_bucket = int64_t( initial_supply.get_amount() * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ) + initial_pervote_bucket; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); if (from_pervote_bucket >= 100 * 10000) { BOOST_REQUIRE_EQUAL(from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket - from_pervote_bucket, pervote_bucket); } else { BOOST_REQUIRE_EQUAL(from_perblock_bucket, balance.get_amount() - initial_balance.get_amount()); BOOST_REQUIRE_EQUAL(expected_pervote_bucket, pervote_bucket); } produce_blocks(5); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } { const uint32_t prod_index = 24; const auto prod_name = producer_names[prod_index]; BOOST_REQUIRE_EQUAL(success(), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); BOOST_REQUIRE(100 * 10000 <= get_balance(prod_name).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } // wait two more hours, now most producers haven't produced in a day and will // be deactivated BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() ("voter", "producvotera") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+21)) ) ); produce_block(fc::hours(9)); produce_blocks(8 * 21 * 12); { bool all_newly_elected_produced = true; for (uint32_t i = 21; i < producer_names.size(); ++i) { if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { all_newly_elected_produced = false; } } BOOST_REQUIRE(all_newly_elected_produced); } { uint32_t survived_active_producers = 0; uint32_t one_inactive_index = 0; for (uint32_t i = 0; i < 21; ++i) { if (fc::crypto::public_key() != fc::crypto::public_key(get_producer_info(producer_names[i])["producer_key"].as_string())) { ++survived_active_producers; } else { one_inactive_index = i; } } BOOST_REQUIRE(3 >= survived_active_producers); auto inactive_prod_info = get_producer_info(producer_names[one_inactive_index]); BOOST_REQUIRE_EQUAL(0, inactive_prod_info["time_became_active"].as()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("producer does not have an active key"), push_action(producer_names[one_inactive_index], N(claimrewards), mvo()("owner", producer_names[one_inactive_index]))); // re-register deactivated producer and let him produce blocks again const uint32_t initial_unpaid_blocks = inactive_prod_info["unpaid_blocks"].as(); regproducer(producer_names[one_inactive_index]); produce_blocks(21 * 12 * 100); auto reactivated_prod_info = get_producer_info(producer_names[one_inactive_index]); const uint32_t unpaid_blocks = reactivated_prod_info["unpaid_blocks"].as(); BOOST_REQUIRE(initial_unpaid_blocks + 12 <= unpaid_blocks); BOOST_REQUIRE_EQUAL(success(), push_action(producer_names[one_inactive_index], N(claimrewards), mvo()("owner", producer_names[one_inactive_index]))); } } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, 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 ); 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 } ); } //prepare system contract with different hash (contract differs in one byte) string eosio_system_wast2 = eosio_system_wast; string msg = "producer votes must be unique and sorted"; auto pos = eosio_system_wast2.find(msg); BOOST_REQUIRE( pos != std::string::npos ); msg[0] = 'P'; eosio_system_wast2.replace( pos, msg.size(), msg ); transaction trx; { auto code = wast_to_wasm( eosio_system_wast2 ); variant pretty_trx = fc::mutable_variant_object() ("expiration", "2020-01-01T00:30") ("ref_block_num", 2) ("ref_block_prefix", 3) ("max_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", "setcode") ("authorization", vector{ { config::system_account_name, config::active_name } }) ("data", fc::mutable_variant_object() ("account", name(config::system_account_name)) ("vmtype", 0) ("vmversion", "0") ("code", bytes( code.begin(), code.end() )) ) }) ); abi_serializer::from_variant(pretty_trx, trx, get_resolver()); } BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() ("proposer", "alice1111111") ("proposal_name", "upgrade1") ("trx", trx) ("requested", prod_perms) ) ); // get 15 approvals for ( size_t i = 0; i < 14; ++i ) { BOOST_REQUIRE_EQUAL(success(), push_action_msig( name(producer_names[i]), N(approve), mvo() ("proposer", "alice1111111") ("proposal_name", "upgrade1") ("level", permission_level{ name(producer_names[i]), config::active_name }) ) ); } //should fail BOOST_REQUIRE_EQUAL(wasm_assert_msg("transaction authorization failed"), push_action_msig( N(alice1111111), N(exec), mvo() ("proposer", "alice1111111") ("proposal_name", "upgrade1") ("executer", "alice1111111") ) ); // one more approval BOOST_REQUIRE_EQUAL(success(), push_action_msig( name(producer_names[14]), N(approve), mvo() ("proposer", "alice1111111") ("proposal_name", "upgrade1") ("level", permission_level{ name(producer_names[14]), 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", "upgrade1") ("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 ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(producer_onblock_check, eosio_system_tester) try { const asset large_asset = core_from_string("80.0000"); create_account_with_resources( N(producvotera), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(producvoterb), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); create_account_with_resources( N(producvoterc), config::system_account_name, core_from_string("1.0000"), false, large_asset, large_asset ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers std::vector producer_names; producer_names.reserve('z' - 'a' + 1); const std::string root("defproducer"); for ( char c = 'a'; c <= 'z'; ++c ) { producer_names.emplace_back(root + std::string(1, c)); } setup_producer_accounts(producer_names); for (auto a:producer_names) regproducer(a); BOOST_REQUIRE_EQUAL(0, get_producer_info( producer_names.front() )["total_votes"].as()); BOOST_REQUIRE_EQUAL(0, get_producer_info( producer_names.back() )["total_votes"].as()); transfer(config::system_account_name, "producvotera", core_from_string("200000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvotera", core_from_string("70000000.0000"), core_from_string("70000000.0000") )); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() ("voter", "producvotera") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+10)) )); // give a chance for everyone to produce blocks { produce_blocks(21 * 12); bool all_21_produced = true; for (uint32_t i = 0; i < 21; ++i) { if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { all_21_produced= false; } } bool rest_didnt_produce = true; for (uint32_t i = 21; i < producer_names.size(); ++i) { if (0 < get_producer_info(producer_names[i])["unpaid_blocks"].as()) { rest_didnt_produce = false; } } BOOST_REQUIRE_EQUAL(false, all_21_produced); BOOST_REQUIRE_EQUAL(true, rest_didnt_produce); } { BOOST_CHECK_EQUAL(0, get_global_state()["total_unpaid_blocks"].as()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("not enough has been staked for producers to claim rewards"), push_action(producer_names.front(), N(claimrewards), mvo()("owner", producer_names.front()))); BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.front()).get_amount()); BOOST_REQUIRE_EQUAL(wasm_assert_msg("not enough has been staked for producers to claim rewards"), push_action(producer_names.back(), N(claimrewards), mvo()("owner", producer_names.back()))); BOOST_REQUIRE_EQUAL(0, get_balance(producer_names.back()).get_amount()); } // stake across 15% boundary transfer(config::system_account_name, "producvoterb", core_from_string("100000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvoterb", core_from_string("4000000.0000"), core_from_string("4000000.0000"))); transfer(config::system_account_name, "producvoterc", core_from_string("100000000.0000"), config::system_account_name); BOOST_REQUIRE_EQUAL(success(), stake("producvoterc", core_from_string("2000000.0000"), core_from_string("2000000.0000"))); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterb), N(voteproducer), mvo() ("voter", "producvoterb") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+21)) ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterc), N(voteproducer), mvo() ("voter", "producvoterc") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.end())) ) ); // give a chance for everyone to produce blocks { produce_blocks(21 * 12); bool all_21_produced = true; for (uint32_t i = 0; i < 21; ++i) { if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { all_21_produced= false; } } bool rest_didnt_produce = true; for (uint32_t i = 21; i < producer_names.size(); ++i) { if (0 < get_producer_info(producer_names[i])["unpaid_blocks"].as()) { rest_didnt_produce = false; } } BOOST_REQUIRE_EQUAL(true, all_21_produced); BOOST_REQUIRE_EQUAL(true, rest_didnt_produce); BOOST_REQUIRE_EQUAL(success(), push_action(producer_names.front(), N(claimrewards), mvo()("owner", producer_names.front()))); BOOST_REQUIRE(0 < get_balance(producer_names.front()).get_amount()); } } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( voters_actions_affect_proxy_and_producers, eosio_system_tester, * boost::unit_test::tolerance(1e+6) ) try { create_accounts_with_resources( { N(donald111111), N(defproducer1), N(defproducer2), N(defproducer3) } ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer1", 1) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer2", 2) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer3", 3) ); //alice1111111 becomes a producer BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" ), get_voter_info( "alice1111111" ) ); //alice1111111 makes stake and votes issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("30.0001"), core_from_string("20.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer1), N(defproducer2) } ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("50.0002")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("50.0002")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), push_action( N(donald111111), N(regproxy), mvo() ("proxy", "donald111111") ("isproxy", true) ) ); REQUIRE_MATCHING_OBJECT( proxy( "donald111111" ), get_voter_info( "donald111111" ) ); //bob111111111 chooses alice1111111 as a proxy issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("150.0003")) == get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("200.0005")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("200.0005")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //carol1111111 chooses alice1111111 as a proxy issue( "carol1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("30.0001"), core_from_string("20.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("200.0005")) == get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("250.0007")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("250.0007")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //proxied voter carol1111111 increases stake BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("50.0000"), core_from_string("70.0000") ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("320.0005")) == get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("370.0007")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("370.0007")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //proxied voter bob111111111 decreases stake BOOST_REQUIRE_EQUAL( success(), unstake( "bob111111111", core_from_string("50.0001"), core_from_string("50.0001") ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("220.0003")) == get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("270.0005")) == get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("270.0005")) == get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //proxied voter carol1111111 chooses another proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", "donald111111" ) ("producers", vector() ) ) ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("50.0001")), get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("170.0002")), get_voter_info( "donald111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("100.0003")), get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("100.0003")), get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( 0, get_producer_info( "defproducer3" )["total_votes"].as_double() ); //bob111111111 switches to direct voting and votes for one of the same producers, but not for another one BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "") ("producers", vector{ N(defproducer2) } ) ) ); BOOST_TEST_REQUIRE( 0.0 == get_voter_info( "alice1111111" )["proxied_vote_weight"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("50.0002")), get_producer_info( "defproducer1" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( stake2votes(core_from_string("100.0003")), get_producer_info( "defproducer2" )["total_votes"].as_double() ); BOOST_TEST_REQUIRE( 0.0 == get_producer_info( "defproducer3" )["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_both_proxy_and_producers, eosio_system_tester ) try { //alice1111111 becomes a proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", true) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" ), get_voter_info( "alice1111111" ) ); //carol1111111 becomes a producer BOOST_REQUIRE_EQUAL( success(), regproducer( "carol1111111", 1) ); //bob111111111 chooses alice1111111 as a proxy issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("cannot vote for producers and proxy at same time"), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector{ N(carol1111111) } ) ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( select_invalid_proxy, eosio_system_tester ) try { //accumulate proxied votes issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); //selecting account not registered as a proxy BOOST_REQUIRE_EQUAL( wasm_assert_msg( "invalid proxy specified" ), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); //selecting not existing account as a proxy BOOST_REQUIRE_EQUAL( wasm_assert_msg( "invalid proxy specified" ), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "notexist" ) ("producers", vector() ) ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( double_register_unregister_proxy_keeps_votes, eosio_system_tester ) try { //alice1111111 becomes a proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", 1) ) ); issue( "alice1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", core_from_string("5.0000"), core_from_string("5.0000") ) ); edump((get_voter_info("alice1111111"))); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "staked", 100000 ), get_voter_info( "alice1111111" ) ); //bob111111111 stakes and selects alice1111111 as a proxy issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "proxied_vote_weight", stake2votes( core_from_string("150.0003") ))( "staked", 100000 ), get_voter_info( "alice1111111" ) ); //double regestering should fail without affecting total votes and stake BOOST_REQUIRE_EQUAL( wasm_assert_msg( "action has no effect" ), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", 1) ) ); REQUIRE_MATCHING_OBJECT( proxy( "alice1111111" )( "proxied_vote_weight", stake2votes(core_from_string("150.0003")) )( "staked", 100000 ), get_voter_info( "alice1111111" ) ); //uregister BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", 0) ) ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111" )( "proxied_vote_weight", stake2votes(core_from_string("150.0003")) )( "staked", 100000 ), get_voter_info( "alice1111111" ) ); //double unregistering should not affect proxied_votes and stake BOOST_REQUIRE_EQUAL( wasm_assert_msg( "action has no effect" ), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", 0) ) ); REQUIRE_MATCHING_OBJECT( voter( "alice1111111" )( "proxied_vote_weight", stake2votes(core_from_string("150.0003")))( "staked", 100000 ), get_voter_info( "alice1111111" ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( proxy_cannot_use_another_proxy, eosio_system_tester ) try { //alice1111111 becomes a proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(alice1111111), N(regproxy), mvo() ("proxy", "alice1111111") ("isproxy", 1) ) ); //bob111111111 becomes a proxy BOOST_REQUIRE_EQUAL( success(), push_action( N(bob111111111), N(regproxy), mvo() ("proxy", "bob111111111") ("isproxy", 1) ) ); //proxy should not be able to use a proxy issue( "bob111111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg( "account registered as a proxy is not allowed to use a proxy" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); //voter that uses a proxy should not be allowed to become a proxy issue( "carol1111111", core_from_string("1000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), stake( "carol1111111", core_from_string("100.0002"), core_from_string("50.0001") ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(carol1111111), N(voteproducer), mvo() ("voter", "carol1111111") ("proxy", "alice1111111" ) ("producers", vector() ) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg( "account that uses a proxy is not allowed to become a proxy" ), push_action( N(carol1111111), N(regproxy), mvo() ("proxy", "carol1111111") ("isproxy", 1) ) ); //proxy should not be able to use itself as a proxy BOOST_REQUIRE_EQUAL( wasm_assert_msg( "cannot proxy to self" ), push_action( N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", "bob111111111" ) ("producers", vector() ) ) ); } FC_LOG_AND_RETHROW() fc::mutable_variant_object config_to_variant( const eosio::chain::chain_config& config ) { return mutable_variant_object() ( "max_block_net_usage", config.max_block_net_usage ) ( "target_block_net_usage_pct", config.target_block_net_usage_pct ) ( "max_transaction_net_usage", config.max_transaction_net_usage ) ( "base_per_transaction_net_usage", config.base_per_transaction_net_usage ) ( "context_free_discount_net_usage_num", config.context_free_discount_net_usage_num ) ( "context_free_discount_net_usage_den", config.context_free_discount_net_usage_den ) ( "max_block_cpu_usage", config.max_block_cpu_usage ) ( "target_block_cpu_usage_pct", config.target_block_cpu_usage_pct ) ( "max_transaction_cpu_usage", config.max_transaction_cpu_usage ) ( "min_transaction_cpu_usage", config.min_transaction_cpu_usage ) ( "max_transaction_lifetime", config.max_transaction_lifetime ) ( "deferred_trx_expiration_window", config.deferred_trx_expiration_window ) ( "max_transaction_delay", config.max_transaction_delay ) ( "max_inline_action_size", config.max_inline_action_size ) ( "max_inline_action_depth", config.max_inline_action_depth ) ( "max_authority_depth", config.max_authority_depth ); } BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_tester ) try { create_accounts_with_resources( { N(defproducer1), N(defproducer2), N(defproducer3) } ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer1", 1) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer2", 2) ); BOOST_REQUIRE_EQUAL( success(), regproducer( "defproducer3", 3) ); //stake more than 15% of total EOS supply to activate chain transfer( "eosio", "alice1111111", core_from_string("600000000.0000"), "eosio" ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("300000000.0000"), core_from_string("300000000.0000") ) ); // 1000000000.0000 //vote for producers BOOST_REQUIRE_EQUAL( success(), push_action(N(alice1111111), N(voteproducer), mvo() ("voter", "alice1111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer1) } ) ) ); produce_blocks(250); auto producer_keys = control->head_block_state()->active_schedule.producers; BOOST_REQUIRE_EQUAL( 1, producer_keys.size() ); BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); //auto config = config_to_variant( control->get_global_properties().configuration ); //auto prod1_config = testing::filter_fields( config, producer_parameters_example( 1 ) ); //REQUIRE_EQUAL_OBJECTS(prod1_config, config); // elect 2 producers issue( "bob111111111", core_from_string("80000.0000"), config::system_account_name ); ilog("stake"); BOOST_REQUIRE_EQUAL( success(), stake( "bob111111111", core_from_string("40000.0000"), core_from_string("40000.0000") ) ); ilog("start vote"); BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer2) } ) ) ); ilog("."); produce_blocks(250); producer_keys = control->head_block_state()->active_schedule.producers; BOOST_REQUIRE_EQUAL( 2, producer_keys.size() ); BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys[1].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //auto prod2_config = testing::filter_fields( config, producer_parameters_example( 2 ) ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); // elect 3 producers BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer2), N(defproducer3) } ) ) ); produce_blocks(250); producer_keys = control->head_block_state()->active_schedule.producers; BOOST_REQUIRE_EQUAL( 3, producer_keys.size() ); BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); BOOST_REQUIRE_EQUAL( name("defproducer2"), producer_keys[1].producer_name ); BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys[2].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //REQUIRE_EQUAL_OBJECTS(prod2_config, config); //back to 2 producers BOOST_REQUIRE_EQUAL( success(), push_action(N(bob111111111), N(voteproducer), mvo() ("voter", "bob111111111") ("proxy", name(0).to_string() ) ("producers", vector{ N(defproducer3) } ) ) ); produce_blocks(250); producer_keys = control->head_block_state()->active_schedule.producers; BOOST_REQUIRE_EQUAL( 2, producer_keys.size() ); BOOST_REQUIRE_EQUAL( name("defproducer1"), producer_keys[0].producer_name ); BOOST_REQUIRE_EQUAL( name("defproducer3"), producer_keys[1].producer_name ); //config = config_to_variant( control->get_global_properties().configuration ); //auto prod3_config = testing::filter_fields( config, producer_parameters_example( 3 ) ); //REQUIRE_EQUAL_OBJECTS(prod3_config, config); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( buyname, eosio_system_tester ) try { create_accounts_with_resources( { N(dan), N(sam) } ); transfer( config::system_account_name, "dan", core_from_string( "10000.0000" ) ); transfer( config::system_account_name, "sam", core_from_string( "10000.0000" ) ); stake_with_transfer( config::system_account_name, "sam", core_from_string( "80000000.0000" ), core_from_string( "80000000.0000" ) ); regproducer( config::system_account_name ); push_action( N(sam), N(voteproducer), mvo() ("voter", "sam") ("proxy", name(0).to_string() ) ("producers", vector{ config::system_account_name } ) ); // wait 14 days after min required amount has been staked produce_block( fc::days(14) ); produce_block(); BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(fail) }, N(dan) ), fc::exception ); // dan shouldn't be able to create fail bidname( "dan", "nofail", core_from_string( "1.0000" ) ); BOOST_REQUIRE_EQUAL( "assertion failure with message: must increase bid by 10%", bidname( "sam", "nofail", core_from_string( "1.0000" ) )); // didn't increase bid by 10% BOOST_REQUIRE_EQUAL( success(), bidname( "sam", "nofail", core_from_string( "2.0000" ) )); // didn't increase bid by 10% produce_block( fc::days(1) ); produce_block(); BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(nofail) }, N(dan) ), fc::exception); // dan shoudn't be able to do this, sam won //wlog( "verify sam can create nofail" ); create_accounts_with_resources( { N(nofail) }, N(sam) ); // sam should be able to do this, he won the bid //wlog( "verify nofail can create test.nofail" ); transfer( "eosio", "nofail", core_from_string( "1000.0000" ) ); create_accounts_with_resources( { N(test.nofail) }, N(nofail) ); // only nofail can create test.nofail //wlog( "verify dan cannot create test.fail" ); BOOST_REQUIRE_THROW( create_accounts_with_resources( { N(test.fail) }, N(dan) ), fc::exception ); // dan shouldn't be able to do this create_accounts_with_resources( { N(goodgoodgood) }, N(dan) ); /// 12 char names should succeed } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { const std::string not_closed_message("auction for name is not closed yet"); std::vector accounts = { N(alice), N(bob), N(carl), N(david), N(eve) }; create_accounts_with_resources( accounts ); for ( const auto& a: accounts ) { transfer( config::system_account_name, a, core_from_string( "10000.0000" ) ); BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance(a) ); } create_accounts_with_resources( { N(producer) } ); BOOST_REQUIRE_EQUAL( success(), regproducer( N(producer) ) ); produce_block(); // stake but but not enough to go live stake_with_transfer( config::system_account_name, "bob", core_from_string( "35000000.0000" ), core_from_string( "35000000.0000" ) ); stake_with_transfer( config::system_account_name, "carl", core_from_string( "35000000.0000" ), core_from_string( "35000000.0000" ) ); BOOST_REQUIRE_EQUAL( success(),push_action( N(bob), N(voteproducer), mvo() ("voter", "bob") ("proxy", name(0).to_string() ) ("producers", vector{ N(producer) } ) ) ); BOOST_REQUIRE_EQUAL( success(), push_action( N(carl), N(voteproducer), mvo() ("voter", "carl") ("proxy", name(0).to_string() ) ("producers", vector{ N(producer) } ) ) ); // start bids bidname( "bob", "prefa", core_from_string("1.0000") ); BOOST_REQUIRE_EQUAL( core_from_string( "9999.0000" ), get_balance("bob") ); bidname( "bob", "prefb", core_from_string("1.0000") ); bidname( "bob", "prefc", core_from_string("1.0000") ); BOOST_REQUIRE_EQUAL( core_from_string( "9997.0000" ), get_balance("bob") ); bidname( "carl", "prefd", core_from_string("1.0000") ); bidname( "carl", "prefe", core_from_string("1.0000") ); BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("carl") ); BOOST_REQUIRE_EQUAL( error("assertion failure with message: account is already high bidder"), bidname( "bob", "prefb", core_from_string("1.1001") ) ); BOOST_REQUIRE_EQUAL( error("assertion failure with message: must increase bid by 10%"), bidname( "alice", "prefb", core_from_string("1.0999") ) ); BOOST_REQUIRE_EQUAL( core_from_string( "9997.0000" ), get_balance("bob") ); BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance("alice") ); // alice outbids bob on prefb { BOOST_REQUIRE_EQUAL( success(), bidname( "alice", "prefb", core_from_string("1.1001") ) ); BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("bob") ); BOOST_REQUIRE_EQUAL( core_from_string( "9998.8999" ), get_balance("alice") ); } // david outbids carl on prefd { BOOST_REQUIRE_EQUAL( core_from_string( "9998.0000" ), get_balance("carl") ); BOOST_REQUIRE_EQUAL( core_from_string( "10000.0000" ), get_balance("david") ); BOOST_REQUIRE_EQUAL( success(), bidname( "david", "prefd", core_from_string("1.9900") ) ); BOOST_REQUIRE_EQUAL( core_from_string( "9999.0000" ), get_balance("carl") ); BOOST_REQUIRE_EQUAL( core_from_string( "9998.0100" ), get_balance("david") ); } // eve outbids carl on prefe { BOOST_REQUIRE_EQUAL( success(), bidname( "eve", "prefe", core_from_string("1.7200") ) ); } produce_block( fc::days(14) ); produce_block(); // highest bid is from david for prefd but no bids can be closed yet BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefd), N(david) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); // stake enough to go above the 15% threshold stake_with_transfer( config::system_account_name, "alice", core_from_string( "10000000.0000" ), core_from_string( "10000000.0000" ) ); BOOST_REQUIRE_EQUAL(0, get_producer_info("producer")["unpaid_blocks"].as()); BOOST_REQUIRE_EQUAL( success(), push_action( N(alice), N(voteproducer), mvo() ("voter", "alice") ("proxy", name(0).to_string() ) ("producers", vector{ N(producer) } ) ) ); // need to wait for 14 days after going live produce_blocks(10); produce_block( fc::days(2) ); produce_blocks( 10 ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefd), N(david) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); // it's been 14 days, auction for prefd has been closed produce_block( fc::days(12) ); create_account_with_resources( N(prefd), N(david) ); produce_blocks(2); produce_block( fc::hours(23) ); // auctions for prefa, prefb, prefc, prefe haven't been closed BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(alice) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefc), N(bob) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefe), N(eve) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); // attemp to create account with no bid BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefg), N(alice) ), fc::exception, fc_assert_exception_message_is( "no active bid for name" ) ); // changing highest bid pushes auction closing time by 24 hours BOOST_REQUIRE_EQUAL( success(), bidname( "eve", "prefb", core_from_string("2.1880") ) ); produce_block( fc::hours(22) ); produce_blocks(2); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(eve) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); // but changing a bid that is not the highest does not push closing time BOOST_REQUIRE_EQUAL( success(), bidname( "carl", "prefe", core_from_string("2.0980") ) ); produce_block( fc::hours(2) ); produce_blocks(2); // bid for prefb has closed, only highest bidder can claim BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(alice) ), fc::exception, fc_assert_exception_message_is("only high bidder can claim") ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefb), N(carl) ), fc::exception, fc_assert_exception_message_is("only high bidder can claim") ); create_account_with_resources( N(prefb), N(eve) ); BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefe), N(carl) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); produce_block(); produce_block( fc::hours(24) ); // by now bid for prefe has closed create_account_with_resources( N(prefe), N(carl) ); // prefe can now create *.prefe BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(xyz.prefe), N(carl) ), fc::exception, fc_assert_exception_message_is("only suffix may create this account") ); transfer( config::system_account_name, N(prefe), core_from_string("10000.0000") ); create_account_with_resources( N(xyz.prefe), N(prefe) ); // other auctions haven't closed BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(prefa), N(bob) ), fc::exception, fc_assert_exception_message_is( not_closed_message ) ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( vote_producers_in_and_out, eosio_system_tester ) try { const asset net = core_from_string("80.0000"); const asset cpu = core_from_string("80.0000"); std::vector voters = { N(producvotera), N(producvoterb), N(producvoterc), N(producvoterd) }; for (const auto& v: voters) { create_account_with_resources(v, config::system_account_name, core_from_string("1.0000"), false, net, cpu); } // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers std::vector producer_names; { producer_names.reserve('z' - 'a' + 1); const std::string root("defproducer"); for ( char c = 'a'; c <= 'z'; ++c ) { producer_names.emplace_back(root + std::string(1, c)); } setup_producer_accounts(producer_names); for (const auto& p: producer_names) { BOOST_REQUIRE_EQUAL( success(), regproducer(p) ); produce_blocks(1); ilog( "------ get pro----------" ); wdump((p)); BOOST_TEST(0 == get_producer_info(p)["total_votes"].as()); } } for (const auto& v: voters) { transfer( config::system_account_name, v, core_from_string("200000000.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL(success(), stake(v, core_from_string("30000000.0000"), core_from_string("30000000.0000")) ); } { BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() ("voter", "producvotera") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+20)) ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterb), N(voteproducer), mvo() ("voter", "producvoterb") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.begin()+21)) ) ); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterc), N(voteproducer), mvo() ("voter", "producvoterc") ("proxy", name(0).to_string()) ("producers", vector(producer_names.begin(), producer_names.end())) ) ); } // give a chance for everyone to produce blocks { produce_blocks(23 * 12 + 20); bool all_21_produced = true; for (uint32_t i = 0; i < 21; ++i) { if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { all_21_produced = false; } } bool rest_didnt_produce = true; for (uint32_t i = 21; i < producer_names.size(); ++i) { if (0 < get_producer_info(producer_names[i])["unpaid_blocks"].as()) { rest_didnt_produce = false; } } BOOST_REQUIRE(all_21_produced && rest_didnt_produce); } { produce_block(fc::hours(7)); const uint32_t voted_out_index = 20; const uint32_t new_prod_index = 23; BOOST_REQUIRE_EQUAL(success(), stake("producvoterd", core_from_string("40000000.0000"), core_from_string("40000000.0000"))); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterd), N(voteproducer), mvo() ("voter", "producvoterd") ("proxy", name(0).to_string()) ("producers", vector{ producer_names[new_prod_index] }) ) ); BOOST_REQUIRE_EQUAL(0, get_producer_info(producer_names[new_prod_index])["unpaid_blocks"].as()); produce_blocks(4 * 12 * 21); BOOST_REQUIRE(0 < get_producer_info(producer_names[new_prod_index])["unpaid_blocks"]); const uint32_t initial_unpaid_blocks = get_producer_info(producer_names[voted_out_index])["unpaid_blocks"].as(); produce_blocks(2 * 12 * 21); BOOST_REQUIRE_EQUAL(initial_unpaid_blocks, get_producer_info(producer_names[voted_out_index])["unpaid_blocks"].as()); produce_block(fc::hours(24)); BOOST_REQUIRE_EQUAL(success(), push_action(N(producvoterd), N(voteproducer), mvo() ("voter", "producvoterd") ("proxy", name(0).to_string()) ("producers", vector{ producer_names[voted_out_index] }) ) ); produce_blocks(2 * 12 * 21); BOOST_REQUIRE(fc::crypto::public_key() != fc::crypto::public_key(get_producer_info(producer_names[voted_out_index])["producer_key"].as_string())); BOOST_REQUIRE_EQUAL(success(), push_action(producer_names[voted_out_index], N(claimrewards), mvo()("owner", producer_names[voted_out_index]))); } } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( setparams, 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 ); 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 } ); } eosio_parameters params; (eosio::chain::chain_config&)params = control->get_global_properties().configuration; params.max_ram_size = 65ll*1024 * 1024 * 1024; //change some values params.max_block_net_usage += 10; params.max_transaction_lifetime += 1; transaction trx; { variant pretty_trx = fc::mutable_variant_object() ("expiration", "2020-01-01T00:30") ("ref_block_num", 2) ("ref_block_prefix", 3) ("max_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", "setparams") ("authorization", vector{ { config::system_account_name, config::active_name } }) ("data", fc::mutable_variant_object() ("params", params) ) }) ); abi_serializer::from_variant(pretty_trx, trx, get_resolver()); } BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() ("proposer", "alice1111111") ("proposal_name", "setparams1") ("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", "setparams1") ("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", "setparams1") ("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 auto active_params = control->get_global_properties().configuration; BOOST_REQUIRE_EQUAL( params.max_block_net_usage, active_params.max_block_net_usage ); BOOST_REQUIRE_EQUAL( params.max_transaction_lifetime, active_params.max_transaction_lifetime ); } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END()