void token::issue( account_name to, asset quantity, string memo ) { auto sym = quantity.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); auto sym_name = sym.name(); stats statstable( _self, sym_name ); auto existing = statstable.find( sym_name ); eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); const auto& st = *existing; require_auth( st.issuer ); eosio_assert( quantity.is_valid(), "invalid quantity" ); eosio_assert( quantity.amount > 0, "must issue positive quantity" ); eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply"); statstable.modify( st, 0, [&]( auto& s ) { s.supply += quantity; }); add_balance( st.issuer, quantity, st.issuer ); if( to != st.issuer ) { SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} ); } }
/// @brief /// Change knight battle stage /// @param from /// Player who requested change stage /// @param knt /// Knight type /// @param stage /// Stage code void setkntstage(name from, uint8_t stage) { require_auth(from); auto stagerule = stage_rule_controller.get_table().find(stage); assert_true(stagerule != stage_rule_controller.get_table().cend(), "no stage rule"); int minlv = stagerule->lvfrom; bool pass = false; auto iter = knights.find(from); assert_true(iter != knights.cend(), "could not found knight"); auto &rows = iter->rows; for (auto iter = rows.cbegin(); iter != rows.cend(); iter++) { auto &knight = *iter; if (knight.level >= minlv) { pass = true; break; } } assert_true(pass, "no one exceed stage minmium level"); auto &players = player_controller.get_players(); auto player = players.find(from); players.modify(player, self, [&](auto& target) { target.current_stage = stage; }); }
/// @brief /// Equip item /// @param to /// Knight who you want to equip the item /// @param id /// Target item id void equip(name from, uint8_t to, uint32_t id) { require_auth(from); assert_true(to > 0 && to < kt_count, "invalid knight type"); auto item_iter = item_controller.find(from); auto &rows = item_controller.get_items(item_iter); auto &item = item_controller.get_item(rows, id); assert_true(item.saleid == 0, "item is on sale"); auto &rule_table = item_controller.get_ritem_rule().get_table(); auto rule = rule_table.find(item.code); assert_true(rule != rule_table.cend(), "could not find rule"); assert_true(is_valid_for((knight_type)to, (item_sub_type)rule->sub_type), "it's invalid knight to attach"); auto knt_iter = knights.find(from); assert_true(knt_iter != knights.cend(), "could not found knight"); auto &knight = get_knight(knt_iter, to); assert_true(rule->min_level <= knight.level, "not enough knight level to equip item"); for (int index = 0; index < rows.size(); index++) { if (rows[index].knight != to) { continue; } auto itr_rule = rule_table.find(rows[index].code); assert_true(itr_rule != rule_table.cend(), "could not find target item rule"); if (itr_rule->type == rule->type) { item_controller.set_item_knight(item_iter, rows[index].id, 0); break; } } item_controller.set_item_knight(item_iter, id, to); refresh_stat(from, to); }
void system_contract::regproxy( const account_name proxy ) { require_auth( proxy ); voters_table voters_tbl( _self, _self ); auto proxy_it = voters_tbl.find( proxy ); if ( proxy_it != voters_tbl.end() ) { eosio_assert( proxy_it->is_proxy == 0, "account is already a proxy" ); eosio_assert( proxy_it->proxy == 0, "account that uses a proxy is not allowed to become a proxy" ); voters_tbl.modify( proxy_it, 0, [&](voter_info& a) { a.is_proxy = 1; a.last_update = now(); //a.proxied_votes may be > 0, if the proxy has been unregistered, so we had to keep the value }); if ( 0 < proxy_it->proxied_votes ) { producers_table producers_tbl( _self, _self ); for ( auto p : proxy_it->producers ) { auto prod = producers_tbl.find( p ); eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes += proxy_it->proxied_votes; }); } } } else { voters_tbl.emplace( proxy, [&]( voter_info& a ) { a.owner = proxy; a.last_update = now(); a.proxy = 0; a.is_proxy = 1; a.proxied_votes = 0; a.staked.amount = 0; }); } }
static void on( const undelegatebw& del ) { eosio_assert( del.unstake_cpu_quantity.quantity >= 0, "must stake a positive amount" ); eosio_assert( del.unstake_net_quantity.quantity >= 0, "must stake a positive amount" ); auto total_stake = del.unstake_cpu_quantity + del.unstake_net_quantity; eosio_assert( total_stake.quantity >= 0, "must stake a positive amount" ); require_auth( del.from ); del_bandwidth_index_type del_index( SystemAccount, del.from ); total_resources_index_type total_index( SystemAccount, del.receiver ); //eosio_assert( is_account( del.receiver ), "can only delegate resources to an existing account" ); const auto& dbw = del_index.get(del.receiver); eosio_assert( dbw.net_weight >= del.unstake_net_quantity, "insufficient staked net bandwidth" ); eosio_assert( dbw.cpu_weight >= del.unstake_cpu_quantity, "insufficient staked cpu bandwidth" ); del_index.update( dbw, del.from, [&]( auto& dbo ){ dbo.net_weight -= del.unstake_net_quantity; dbo.cpu_weight -= del.unstake_cpu_quantity; }); const auto& totals = total_index.get( del.receiver ); total_index.update( totals, 0, [&]( auto& tot ) { tot.total_net_weight -= del.unstake_net_quantity; tot.total_cpu_weight -= del.unstake_cpu_quantity; }); set_resource_limits( totals.owner, totals.total_ram, totals.total_net_weight.quantity, totals.total_cpu_weight.quantity, 0 ); /// TODO: implement / enforce time delays on withdrawing currency::inline_transfer( SystemAccount, del.from, total_stake, "unstake bandwidth" ); } // undelegatebw
void system_contract::unregprod( const account_name producer ) { require_auth( producer ); producers_table producers_tbl( _self, _self ); auto prod = producers_tbl.find( producer ); eosio_assert( prod != producers_tbl.end(), "producer not found" ); producers_tbl.modify( prod, 0, [&]( producer_info& info ){ info.packed_key.clear(); }); }
/// @brief /// Detach item /// @param id /// Target item id void detach(name from, uint32_t id) { require_auth(from); auto iter = item_controller.find(from); auto &rows = item_controller.get_items(iter); auto &item = item_controller.get_item(rows, id); int8_t knight = item.knight; item_controller.set_item_knight(iter, id, 0); refresh_stat(from, knight); }
ACTION( SystemAccount, voteproducer ) { account_name voter; account_name proxy; std::vector<account_name> producers; EOSLIB_SERIALIZE( voteproducer, (voter)(proxy)(producers) ) }; /** * @pre vp.producers must be sorted from lowest to highest * @pre if proxy is set then no producers can be voted for * @pre every listed producer or proxy must have been previously registered * @pre vp.voter must authorize this action * @pre voter must have previously staked some EOS for voting */ static void on( const voteproducer& vp ) { eosio_assert( std::is_sorted( vp.producers.begin(), vp.producers.end() ), "producer votes must be sorted" ); eosio_assert( vp.producers.size() <= 30, "attempt to vote for too many producers" ); if( vp.proxy != 0 ) eosio_assert( vp.producers.size() == 0, "cannot vote for producers and proxy at same time" ); require_auth( vp.voter ); account_votes_index_type avotes( SystemAccount, SystemAccount ); const auto& existing = avotes.get( vp.voter ); std::map<account_name, pair<uint128_t, uint128_t> > producer_vote_changes; uint128_t old_weight = existing.staked.quantity; /// old time uint128_t new_weight = old_weight; /// TODO: update for current weight for( const auto& p : existing.producers ) producer_vote_changes[p].first = old_weight; for( const auto& p : vp.producers ) producer_vote_changes[p].second = new_weight; producer_votes_index_type votes( SystemAccount, SystemAccount ); for( const auto& delta : producer_vote_changes ) { if( delta.second.first != delta.second.second ) { const auto& provote = votes.get( delta.first ); votes.update( provote, 0, [&]( auto& pv ){ pv.total_votes -= delta.second.first; pv.total_votes += delta.second.second; }); } } avotes.update( existing, 0, [&]( auto& av ) { av.proxy = vp.proxy; av.last_update = now(); av.producers = vp.producers; }); }
void system_contract::decrease_voting_power( account_name acnt, const eosio::asset& amount ) { require_auth( acnt ); voters_table voters_tbl( _self, _self ); auto voter = voters_tbl.find( acnt ); eosio_assert( voter != voters_tbl.end(), "stake not found" ); if ( 0 < amount.amount ) { eosio_assert( amount <= voter->staked, "cannot unstake more than total stake amount" ); voters_tbl.modify( voter, 0, [&](voter_info& a) { a.staked -= amount; a.last_update = now(); }); const std::vector<account_name>* producers = nullptr; if ( voter->proxy ) { auto proxy = voters_tbl.find( voter->proxy ); voters_tbl.modify( proxy, 0, [&](voter_info& a) { a.proxied_votes -= uint64_t(amount.amount); } ); if ( proxy->is_proxy ) { //only if proxy is still active. if proxy has been unregistered, we update proxied_votes, but don't propagate to producers producers = &proxy->producers; } } else { producers = &voter->producers; } if ( producers ) { producers_table producers_tbl( _self, _self ); for( auto p : *producers ) { auto prod = producers_tbl.find( p ); eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption producers_tbl.modify( prod, 0, [&]( auto& v ) { v.total_votes -= uint64_t(amount.amount); }); } } } else { if (voter->deferred_trx_id) { //XXX cancel_deferred_transaction(voter->deferred_trx_id); } voters_tbl.modify( voter, 0, [&](voter_info& a) { a.staked += a.unstaking; a.unstaking.amount = 0; a.unstake_per_week.amount = 0; a.deferred_trx_id = 0; a.last_update = now(); }); } }
/** * This method will create a producr_config and producer_votes object for 'producer' * * @pre producer is not already registered * @pre producer to register is an account * @pre authority of producer to register * */ static void on( const regproducer& reg ) { auto producer = reg.producer; require_auth( producer ); producer_votes_index_type votes( SystemAccount, SystemAccount ); const auto* existing = votes.find( producer ); eosio_assert( !existing, "producer already registered" ); votes.emplace( producer, [&]( auto& pv ){ pv.owner = producer; pv.total_votes = 0; }); producer_config_index_type proconfig( SystemAccount, SystemAccount ); proconfig.emplace( producer, [&]( auto& pc ) { pc.owner = producer; pc.packed_key = reg.producer_key; }); }
ACTION( SystemAccount, stakevote ) { account_name voter; system_token_type amount; EOSLIB_SERIALIZE( stakevote, (voter)(amount) ) }; static void on( const stakevote& sv ) { print( "on stake vote\n" ); eosio_assert( sv.amount.quantity > 0, "must stake some tokens" ); require_auth( sv.voter ); account_votes_index_type avotes( SystemAccount, SystemAccount ); const auto* acv = avotes.find( sv.voter ); if( !acv ) { acv = &avotes.emplace( sv.voter, [&]( auto& av ) { av.owner = sv.voter; av.last_update = now(); av.proxy = 0; }); } uint128_t old_weight = acv->staked.quantity; uint128_t new_weight = old_weight + sv.amount.quantity; producer_votes_index_type votes( SystemAccount, SystemAccount ); for( auto p : acv->producers ) { votes.update( votes.get( p ), 0, [&]( auto& v ) { v.total_votes -= old_weight; v.total_votes += new_weight; }); } avotes.update( *acv, 0, [&]( auto av ) { av.last_update = now(); av.staked += sv.amount; }); currency::inline_transfer( sv.voter, SystemAccount, sv.amount, "stake for voting" ); }
void token::create( account_name issuer, asset maximum_supply ) { require_auth( _self ); auto sym = maximum_supply.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); eosio_assert( maximum_supply.is_valid(), "invalid supply"); eosio_assert( maximum_supply.amount > 0, "max-supply must be positive"); stats statstable( _self, sym.name() ); auto existing = statstable.find( sym.name() ); eosio_assert( existing == statstable.end(), "token with symbol already exists" ); statstable.emplace( _self, [&]( auto& s ) { s.supply.symbol = maximum_supply.symbol; s.max_supply = maximum_supply; s.issuer = issuer; }); }
/// @brief /// level up knight. it will decrease powder. /// @param from /// Player who requested level up action /// @param type /// knight who you want to level up void lvupknight(name from, uint8_t type) { require_auth(from); assert_true(type > 0 && type < kt_count, "invalid knight type"); auto iter = knights.find(from); assert_true(iter != knights.cend(), "could not found knight"); auto &knight = get_knight(iter, type); auto player = player_controller.get_player(from); assert_true(player_controller.is_empty_player(player) == false, "could not find player"); uint64_t level = knight.level + 1; assert_true(level <= kv_max_knight_level, "already max level"); auto &rule_table = knight_level_rule_controller.get_table(); auto rule = rule_table.find(level); assert_true(rule != rule_table.cend(), "there is no level rule"); int powder = rule->powder; assert_true(knight.kill_count >= rule->exp, "Insufficient exp"); assert_true(powder <= player->powder, "Insufficient powder"); if (powder > 0) { player_controller.decrease_powder(player, powder); } knights.modify(iter, self, [&](auto& target) { for (int index = 0; index < target.rows.size(); index++) { if (target.rows[index].type == type) { target.rows[index].level = level; auto stat = calculate_stat(from, knight); target.rows[index].attack = stat.attack; target.rows[index].defense = stat.defense; target.rows[index].hp = stat.hp; target.rows[index].luck = stat.luck; break; } } }); }
void system_contract::unregproxy( const account_name proxy ) { require_auth( proxy ); voters_table voters_tbl( _self, _self ); auto proxy_it = voters_tbl.find( proxy ); eosio_assert( proxy_it != voters_tbl.end(), "proxy not found" ); eosio_assert( proxy_it->is_proxy == 1, "account is not a proxy" ); voters_tbl.modify( proxy_it, 0, [&](voter_info& a) { a.is_proxy = 0; a.last_update = now(); //a.proxied_votes should be kept in order to be able to reenable this proxy in the future }); if ( 0 < proxy_it->proxied_votes ) { producers_table producers_tbl( _self, _self ); for ( auto p : proxy_it->producers ) { auto prod_it = producers_tbl.find( p ); eosio_assert( prod_it != producers_tbl.end(), "never existed producer" ); //data corruption producers_tbl.modify( prod_it, 0, [&]( auto& pi ) { pi.total_votes -= proxy_it->proxied_votes; }); } } }
void apply_offer( const offer_bet& offer ) { eos_assert( offer.amount > 0, "insufficient bet" ); eos_assert( !hasOffer( offer.commitment ), "offer with this commitment already exist" ); require_auth( offer.player ); auto acnt = get_account( offer.player ); acnt.balance -= offer.amount; acnt.open_offers++; save( acnt ); /** * 1. Lookup lowerbound on offer's by offer_primary_key * if lowerbound.primary.bet == offer.bet * global_dice.nextgameid++ (load and save to DB) * create new game and set game.bet == offer.bet * set player1 == lowerbound player * set player2 == offer.player * update lowerbound.primary.bet = 0 and lwoerbound.gameid = global_dice.nextgameid * Create offer entry in offers table with bet = 0 and gameid == --^ * else * Create offer entry in offers table with bet = offer.bet and gameid = 0 */ }
void token::transfer( account_name from, account_name to, asset quantity, string memo ) { eosio_assert( from != to, "cannot transfer to self" ); require_auth( from ); eosio_assert( is_account( to ), "to account does not exist"); auto sym = quantity.symbol.name(); stats statstable( _self, sym ); const auto& st = statstable.get( sym ); require_recipient( from ); require_recipient( to ); eosio_assert( quantity.is_valid(), "invalid quantity" ); eosio_assert( quantity.amount > 0, "must transfer positive quantity" ); eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); sub_balance( from, quantity ); add_balance( to, quantity, from ); }
/// @brief /// Rebirth all knights. /// @param from /// Player who requested rebirth void rebirth(name from) { require_auth(from); auto iter = knights.find(from); assert_true(iter != knights.cend(), "can not found knight"); auto &rows = iter->rows; int old_total_kill; for (int index = 0; index < rows.size(); index++) { old_total_kill += rows[index].kill_count; } auto &players = player_controller.get_players(); auto player = players.find(from); assert_true(players.cend() != player, "could not find player"); int total_kill_count = 0; auto &mats = material_controller.get_materials(from); int exp_mat_count = mats.size() + rows.size(); int max_mat_count = material_controller.get_max_inventory_size(*player); assert_true(exp_mat_count <= max_mat_count, "insufficient inventory"); auto stagerule = stage_rule_controller.get_table().find(player->current_stage); assert_true(stagerule != stage_rule_controller.get_table().cend(), "no stage rule"); time current = time_util::getnow(); int elapsed_sec = (int)(current - player->last_rebirth); if (old_total_kill > 0) { assert_true(elapsed_sec >= kv_min_rebirth, "too short to get rebirth"); } int kill_counts[kt_count] = {0, }; int lucks[kt_count] = {0, }; for (auto iter = rows.cbegin(); iter != rows.cend(); iter++) { auto &knight = *iter; int max_sec = calculate_max_alive_time(knight); int play_sec = elapsed_sec; if (play_sec > max_sec) { play_sec = max_sec; } int current_kill_count = knight.attack * play_sec / 60 / kv_enemy_hp; if (current_kill_count == 0) { current_kill_count = 1; } kill_counts[knight.type] = current_kill_count; lucks[knight.type] = knight.luck; total_kill_count += current_kill_count; } knights.modify(iter, self, [&](auto& target) { for (int index = 0; index < target.rows.size(); index++) { int type = target.rows[index].type; target.rows[index].kill_count += kill_counts[type]; } }); int powder = total_kill_count / kv_kill_powder_rate; if (powder <= 0) { powder = 1; } int floor = (total_kill_count / 10) + 1; for (int index = 1; index < kt_count; index++) { if (kill_counts[index] > 0) { int mat_code = get_botties(*player, floor, lucks[index], kill_counts[index], *stagerule); material_controller.add_material(from, mat_code); } } players.modify(player, self, [&](auto& target) { target.last_rebirth = current; target.powder += powder; if (target.maxfloor < floor) { target.maxfloor = floor; } }); }
// actions //------------------------------------------------------------------------- /// @brief /// hire new knight. player could pay the hire cost. /// @param from /// Player who requested hire action /// @param type /// knight who you want to hire void hireknight(name from, uint8_t type, const asset& quantity) { require_auth(from); assert_true(type > 0 && type < kt_count, "invalid knight type"); auto rule = knight_rule_controller.get_table().find(type); assert_true(rule != knight_rule_controller.get_table().cend(), "no knight rule"); knightrow knight; knight.type = type; knight.level = 1; knight.attack = rule->attack; knight.defense = rule->defense; knight.hp = rule->hp; knight.luck = rule->luck; int count = 1; auto iter = knights.find(from); if (iter == knights.cend()) { knights.emplace(self, [&](auto &target) { target.owner = from; target.rows.push_back(knight); }); } else { bool found = false; knights.modify(iter, self, [&](auto &target) { for (int index = 0; index < target.rows.size(); index++) { if (target.rows[index].type == type) { found = true; break; } } target.rows.push_back(knight); count = target.rows.size(); }); assert_true(found == false, "you have already same knight"); } auto price_itr = knight_price_rule_controller.get_table().find(count); assert_true(price_itr != knight_price_rule_controller.get_table().cend(), "could not find price rule"); // pay the cost asset price = price_itr->price; assert_true(quantity.amount == price.amount, "knight price does not match"); /* if (price.amount > 0) { player_controller.transfer(from, to_name(self), price); } */ name seller; seller.value = self; buylog blog; blog.seller = seller; blog.dt = time_util::getnow(); blog.type = ct_knight; blog.pid = 0; blog.code = type; blog.dna = 0; blog.level = 0; blog.exp = 0; blog.price = price; saleslog_controller.add_buylog(blog, from); auto &players = player_controller.get_players(); auto player = players.find(from); assert_true(player != players.cend(), "could not find player"); time current = time_util::getnow(); players.modify(player, self, [&](auto& target) { target.last_rebirth = current; }); }
void apply( uint64_t receiver, uint64_t code, uint64_t action ) { if( code == N(eosio) && action == N(onerror) ) { auto error_dtrx = eosio::deferred_transaction::from_current_action(); eosio::print("onerror called\n"); auto error_action = error_dtrx.actions.at(0).name; // Error handlers for deferred transactions in these tests currently only support the first action WASM_TEST_ERROR_HANDLER("test_action", "assert_false", test_transaction, assert_false_error_handler ); return; } if ( action == N(cf_action) ) { test_action::test_cf_action(); return; } WASM_TEST_HANDLER(test_action, assert_true_cf); require_auth(code); //test_types WASM_TEST_HANDLER(test_types, types_size); WASM_TEST_HANDLER(test_types, char_to_symbol); WASM_TEST_HANDLER(test_types, string_to_name); WASM_TEST_HANDLER(test_types, name_class); //test_compiler_builtins WASM_TEST_HANDLER(test_compiler_builtins, test_multi3); WASM_TEST_HANDLER(test_compiler_builtins, test_divti3); WASM_TEST_HANDLER(test_compiler_builtins, test_divti3_by_0); WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3); WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3_by_0); WASM_TEST_HANDLER(test_compiler_builtins, test_modti3); WASM_TEST_HANDLER(test_compiler_builtins, test_modti3_by_0); WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3); WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3_by_0); WASM_TEST_HANDLER(test_compiler_builtins, test_lshlti3); WASM_TEST_HANDLER(test_compiler_builtins, test_lshrti3); WASM_TEST_HANDLER(test_compiler_builtins, test_ashlti3); WASM_TEST_HANDLER(test_compiler_builtins, test_ashrti3); //test_action WASM_TEST_HANDLER(test_action, read_action_normal); WASM_TEST_HANDLER(test_action, read_action_to_0); WASM_TEST_HANDLER(test_action, read_action_to_64k); WASM_TEST_HANDLER_EX(test_action, require_notice); WASM_TEST_HANDLER(test_action, require_auth); WASM_TEST_HANDLER(test_action, assert_false); WASM_TEST_HANDLER(test_action, assert_true); WASM_TEST_HANDLER(test_action, now); WASM_TEST_HANDLER(test_action, test_abort); WASM_TEST_HANDLER_EX(test_action, test_current_receiver); WASM_TEST_HANDLER(test_action, test_current_sender); WASM_TEST_HANDLER(test_action, test_publication_time); // test named actions // We enforce action name matches action data type name, so name mangling will not work for these tests. if ( action == N(dummy_action) ) { test_action::test_dummy_action(); return; } //test_print WASM_TEST_HANDLER(test_print, test_prints); WASM_TEST_HANDLER(test_print, test_prints_l); WASM_TEST_HANDLER(test_print, test_printi); WASM_TEST_HANDLER(test_print, test_printui); WASM_TEST_HANDLER(test_print, test_printi128); WASM_TEST_HANDLER(test_print, test_printui128); WASM_TEST_HANDLER(test_print, test_printn); WASM_TEST_HANDLER(test_print, test_printsf); WASM_TEST_HANDLER(test_print, test_printdf); WASM_TEST_HANDLER(test_print, test_printqf); //test_math WASM_TEST_HANDLER(test_math, test_multeq); WASM_TEST_HANDLER(test_math, test_diveq); WASM_TEST_HANDLER(test_math, test_i64_to_double); WASM_TEST_HANDLER(test_math, test_double_to_i64); WASM_TEST_HANDLER(test_math, test_diveq_by_0); WASM_TEST_HANDLER(test_math, test_double_api); WASM_TEST_HANDLER(test_math, test_double_api_div_0); //test crypto WASM_TEST_HANDLER(test_crypto, test_recover_key); WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_true); WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_false); WASM_TEST_HANDLER(test_crypto, test_sha1); WASM_TEST_HANDLER(test_crypto, test_sha256); WASM_TEST_HANDLER(test_crypto, test_sha512); WASM_TEST_HANDLER(test_crypto, test_ripemd160); WASM_TEST_HANDLER(test_crypto, sha1_no_data); WASM_TEST_HANDLER(test_crypto, sha256_no_data); WASM_TEST_HANDLER(test_crypto, sha512_no_data); WASM_TEST_HANDLER(test_crypto, ripemd160_no_data); WASM_TEST_HANDLER(test_crypto, sha256_null); WASM_TEST_HANDLER(test_crypto, assert_sha256_false); WASM_TEST_HANDLER(test_crypto, assert_sha256_true); WASM_TEST_HANDLER(test_crypto, assert_sha1_false); WASM_TEST_HANDLER(test_crypto, assert_sha1_true); WASM_TEST_HANDLER(test_crypto, assert_sha512_false); WASM_TEST_HANDLER(test_crypto, assert_sha512_true); WASM_TEST_HANDLER(test_crypto, assert_ripemd160_false); WASM_TEST_HANDLER(test_crypto, assert_ripemd160_true); //test transaction WASM_TEST_HANDLER(test_transaction, test_tapos_block_num); WASM_TEST_HANDLER(test_transaction, test_tapos_block_prefix); WASM_TEST_HANDLER(test_transaction, send_action); WASM_TEST_HANDLER(test_transaction, send_action_inline_fail); WASM_TEST_HANDLER(test_transaction, send_action_empty); WASM_TEST_HANDLER(test_transaction, send_action_large); WASM_TEST_HANDLER(test_transaction, send_action_recurse); WASM_TEST_HANDLER(test_transaction, test_read_transaction); WASM_TEST_HANDLER(test_transaction, test_transaction_size); WASM_TEST_HANDLER_EX(test_transaction, send_transaction); WASM_TEST_HANDLER_EX(test_transaction, send_transaction_empty); WASM_TEST_HANDLER_EX(test_transaction, send_transaction_trigger_error_handler); WASM_TEST_HANDLER_EX(test_transaction, send_transaction_large); WASM_TEST_HANDLER_EX(test_transaction, send_action_sender); WASM_TEST_HANDLER_EX(test_transaction, send_transaction_expiring_late); WASM_TEST_HANDLER(test_transaction, deferred_print); WASM_TEST_HANDLER_EX(test_transaction, send_deferred_transaction); WASM_TEST_HANDLER(test_transaction, cancel_deferred_transaction); WASM_TEST_HANDLER(test_transaction, send_cf_action); WASM_TEST_HANDLER(test_transaction, send_cf_action_fail); WASM_TEST_HANDLER(test_transaction, read_inline_action); WASM_TEST_HANDLER(test_transaction, read_inline_cf_action); //test chain WASM_TEST_HANDLER(test_chain, test_activeprods); // test fixed_point WASM_TEST_HANDLER(test_fixedpoint, create_instances); WASM_TEST_HANDLER(test_fixedpoint, test_addition); WASM_TEST_HANDLER(test_fixedpoint, test_subtraction); WASM_TEST_HANDLER(test_fixedpoint, test_multiplication); WASM_TEST_HANDLER(test_fixedpoint, test_division); WASM_TEST_HANDLER(test_fixedpoint, test_division_by_0); // test double WASM_TEST_HANDLER(test_real, create_instances); WASM_TEST_HANDLER(test_real, test_addition); WASM_TEST_HANDLER(test_real, test_multiplication); WASM_TEST_HANDLER(test_real, test_division); WASM_TEST_HANDLER(test_real, test_division_by_0); // test checktime WASM_TEST_HANDLER(test_checktime, checktime_pass); WASM_TEST_HANDLER(test_checktime, checktime_failure); // test datastream WASM_TEST_HANDLER(test_datastream, test_basic); // test permission WASM_TEST_HANDLER_EX(test_permission, check_authorization); //unhandled test call eosio_assert(false, "Unknown Test"); }
static void on( const regproxy& reg ) { require_auth( reg.proxy_to_register ); }
/** * @pre producers must be sorted from lowest to highest * @pre if proxy is set then no producers can be voted for * @pre every listed producer or proxy must have been previously registered * @pre voter must authorize this action * @pre voter must have previously staked some EOS for voting */ void system_contract::voteproducer( const account_name voter, const account_name proxy, const std::vector<account_name>& producers ) { require_auth( voter ); //validate input if ( proxy ) { eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" ); require_recipient( proxy ); } else { eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" ); for( size_t i = 1; i < producers.size(); ++i ) { eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" ); } } voters_table voters_tbl( _self, _self ); auto voter_it = voters_tbl.find( voter ); eosio_assert( 0 <= voter_it->staked.amount, "negative stake" ); eosio_assert( voter_it != voters_tbl.end() && ( 0 < voter_it->staked.amount || ( voter_it->is_proxy && 0 < voter_it->proxied_votes ) ), "no stake to vote" ); if ( voter_it->is_proxy ) { eosio_assert( proxy == 0 , "account registered as a proxy is not allowed to use a proxy" ); } //find old producers, update old proxy if needed const std::vector<account_name>* old_producers = nullptr; if( voter_it->proxy ) { if ( voter_it->proxy == proxy ) { return; // nothing changed } auto old_proxy = voters_tbl.find( voter_it->proxy ); eosio_assert( old_proxy != voters_tbl.end(), "old proxy not found" ); //data corruption voters_tbl.modify( old_proxy, 0, [&](auto& a) { a.proxied_votes -= uint64_t(voter_it->staked.amount); } ); if ( old_proxy->is_proxy ) { //if proxy stopped being a proxy, the votes were already taken back from producers by on( const unregister_proxy& ) old_producers = &old_proxy->producers; } } else { old_producers = &voter_it->producers; } //find new producers, update new proxy if needed const std::vector<account_name>* new_producers = nullptr; if ( proxy ) { auto new_proxy = voters_tbl.find( proxy ); eosio_assert( new_proxy != voters_tbl.end() && new_proxy->is_proxy, "proxy not found" ); voters_tbl.modify( new_proxy, 0, [&](auto& a) { a.proxied_votes += uint64_t(voter_it->staked.amount); } ); new_producers = &new_proxy->producers; } else { new_producers = &producers; } producers_table producers_tbl( _self, _self ); uint128_t votes = uint64_t(voter_it->staked.amount); if ( voter_it->is_proxy ) { votes += voter_it->proxied_votes; } if ( old_producers ) { //old_producers == nullptr if proxy has stopped being a proxy and votes were taken back from the producers at that moment //revoke votes only from no longer elected std::vector<account_name> revoked( old_producers->size() ); auto end_it = std::set_difference( old_producers->begin(), old_producers->end(), new_producers->begin(), new_producers->end(), revoked.begin() ); for ( auto it = revoked.begin(); it != end_it; ++it ) { auto prod = producers_tbl.find( *it ); eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes -= votes; } ); } } //update newly elected std::vector<account_name> elected( new_producers->size() ); auto end_it = elected.begin(); if( old_producers ) { end_it = std::set_difference( new_producers->begin(), new_producers->end(), old_producers->begin(), old_producers->end(), elected.begin() ); } else { end_it = std::copy( new_producers->begin(), new_producers->end(), elected.begin() ); } for ( auto it = elected.begin(); it != end_it; ++it ) { auto prod = producers_tbl.find( *it ); eosio_assert( prod != producers_tbl.end(), "producer is not registered" ); if ( proxy == 0 ) { //direct voting, in case of proxy voting update total_votes even for inactive producers eosio_assert( prod->active(), "producer is not currently registered" ); } producers_tbl.modify( prod, 0, [&]( auto& pi ) { pi.total_votes += votes; } ); } // save new values to the account itself voters_tbl.modify( voter_it, 0, [&](voter_info& a) { a.proxy = proxy; a.last_update = now(); a.producers = producers; }); }
ACTION( SystemAccount, regproducer ) { account_name producer; bytes producer_key; EOSLIB_SERIALIZE( regproducer, (producer)(producer_key) ) }; ACTION( SystemAccount, regproxy ) { account_name proxy_to_register; EOSLIB_SERIALIZE( regproxy, (proxy_to_register) ) }; ACTION( SystemAccount, delegatebw ) { account_name from; account_name receiver; typename currency::token_type stake_net_quantity; typename currency::token_type stake_cpu_quantity; EOSLIB_SERIALIZE( delegatebw, (from)(receiver)(stake_net_quantity)(stake_cpu_quantity) ) }; ACTION( SystemAccount, undelegatebw ) { account_name from; account_name receiver; typename currency::token_type unstake_net_quantity; typename currency::token_type unstake_cpu_quantity; EOSLIB_SERIALIZE( undelegatebw, (from)(receiver)(unstake_net_quantity)(unstake_cpu_quantity) ) }; ACTION( SystemAccount, nonce ) { eosio::string value; EOSLIB_SERIALIZE( nonce, (value) ) }; /// new id options: // 1. hash + collision // 2. incrementing count (key=> tablename static void on( const delegatebw& del ) { eosio_assert( del.stake_cpu_quantity.quantity >= 0, "must stake a positive amount" ); eosio_assert( del.stake_net_quantity.quantity >= 0, "must stake a positive amount" ); auto total_stake = del.stake_cpu_quantity + del.stake_net_quantity; eosio_assert( total_stake.quantity >= 0, "must stake a positive amount" ); require_auth( del.from ); del_bandwidth_index_type del_index( SystemAccount, del.from ); total_resources_index_type total_index( SystemAccount, del.receiver ); //eosio_assert( is_account( del.receiver ), "can only delegate resources to an existing account" ); auto itr = del_index.find( del.receiver); if( itr != nullptr ) { del_index.emplace( del.from, [&]( auto& dbo ){ dbo.from = del.from; dbo.to = del.receiver; dbo.net_weight = del.stake_net_quantity; dbo.cpu_weight = del.stake_cpu_quantity; }); } else { del_index.update( *itr, del.from, [&]( auto& dbo ){ dbo.net_weight = del.stake_net_quantity; dbo.cpu_weight = del.stake_cpu_quantity; }); } auto tot_itr = total_index.find( del.receiver ); if( tot_itr == nullptr ) { tot_itr = &total_index.emplace( del.from, [&]( auto& tot ) { tot.owner = del.receiver; tot.total_net_weight += del.stake_net_quantity; tot.total_cpu_weight += del.stake_cpu_quantity; }); } else { total_index.update( *tot_itr, 0, [&]( auto& tot ) { tot.total_net_weight += del.stake_net_quantity; tot.total_cpu_weight += del.stake_cpu_quantity; }); } set_resource_limits( tot_itr->owner, tot_itr->total_ram, tot_itr->total_net_weight.quantity, tot_itr->total_cpu_weight.quantity, 0 ); currency::inline_transfer( del.from, SystemAccount, total_stake, "stake bandwidth" ); } // delegatebw