/* * Copyright (c) 2015 Cryptonomex, Inc., and contributors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Any modified source or binaries are used only with the BitShares network. * * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include namespace graphene { namespace chain { share_type cut_fee(share_type a, uint16_t p) { if( a == 0 || p == 0 ) return 0; if( p == GRAPHENE_100_PERCENT ) return a; fc::uint128 r(a.value); r *= p; r /= GRAPHENE_100_PERCENT; return r.to_uint64(); } bool account_object::is_authorized_asset(const asset_object& asset_obj) const { for( const auto id : blacklisting_accounts ) if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) return false; for( const auto id : whitelisting_accounts ) if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() ) return true; return false; } void account_balance_object::adjust_balance(const asset& delta) { assert(delta.asset_id == asset_type); balance += delta.amount; } void account_statistics_object::process_fees(const account_object& a, database& d) const { if( pending_fees > 0 || pending_vested_fees > 0 ) { auto pay_out_fees = [&](const account_object& account, share_type core_fee_total, bool require_vesting) { // Check the referrer -- if he's no longer a member, pay to the lifetime referrer instead. // No need to check the registrar; registrars are required to be lifetime members. if( account.referrer(d).is_basic_account(d.head_block_time()) ) d.modify(account, [](account_object& a) { a.referrer = a.lifetime_referrer; }); share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage); assert( network_cut <= core_fee_total ); #ifndef NDEBUG const auto& props = d.get_global_properties(); share_type reserveed = cut_fee(network_cut, props.parameters.reserve_percent_of_fee); share_type accumulated = network_cut - reserveed; assert( accumulated + reserveed == network_cut ); #endif share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage); share_type referral = core_fee_total - network_cut - lifetime_cut; d.modify(asset_dynamic_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) { d.accumulated_fees += network_cut; }); // Potential optimization: Skip some of this math and object lookups by special casing on the account type. // For example, if the account is a lifetime member, we can skip all this and just deposit the referral to // it directly. share_type referrer_cut = cut_fee(referral, account.referrer_rewards_percentage); share_type registrar_cut = referral - referrer_cut; d.deposit_cashback(d.get(account.lifetime_referrer), lifetime_cut, require_vesting); d.deposit_cashback(d.get(account.referrer), referrer_cut, require_vesting); d.deposit_cashback(d.get(account.registrar), registrar_cut, require_vesting); assert( referrer_cut + registrar_cut + accumulated + reserveed + lifetime_cut == core_fee_total ); }; pay_out_fees(a, pending_fees, true); pay_out_fees(a, pending_vested_fees, false); d.modify(*this, [&](account_statistics_object& s) { s.lifetime_fees_paid += pending_fees + pending_vested_fees; s.pending_fees = 0; s.pending_vested_fees = 0; }); } } void account_object::options_type::validate() const { auto needed_witnesses = num_witness; auto needed_committee = num_committee; for( vote_id_type id : votes ) if( id.type() == vote_id_type::witness && needed_witnesses ) --needed_witnesses; else if ( id.type() == vote_id_type::committee && needed_committee ) --needed_committee; FC_ASSERT( needed_witnesses == 0 && needed_committee == 0, "May not specify fewer witnesses or committee members than the number voted for."); } set account_member_index::get_account_members(const account_object& a)const { set result; for( auto auth : a.owner.account_auths ) result.insert(auth.first); return result; } set account_member_index::get_key_members(const account_object& a)const { set result; for( auto auth : a.owner.key_auths ) result.insert(auth.first); return result; } set
account_member_index::get_address_members(const account_object& a)const { set
result; for( auto auth : a.owner.address_auths ) result.insert(auth.first); return result; } void account_member_index::object_inserted(const object& obj) { assert( dynamic_cast(&obj) ); // for debug only const account_object& a = static_cast(obj); auto account_members = get_account_members(a); for( auto item : account_members ) account_to_account_memberships[item].insert(obj.id); auto key_members = get_key_members(a); for( auto item : key_members ) account_to_key_memberships[item].insert(obj.id); auto address_members = get_address_members(a); for( auto item : address_members ) account_to_address_memberships[item].insert(obj.id); } void account_member_index::object_removed(const object& obj) { assert( dynamic_cast(&obj) ); // for debug only const account_object& a = static_cast(obj); auto key_members = get_key_members(a); for( auto item : key_members ) account_to_key_memberships[item].erase( obj.id ); auto address_members = get_address_members(a); for( auto item : address_members ) account_to_address_memberships[item].erase( obj.id ); auto account_members = get_account_members(a); for( auto item : account_members ) account_to_account_memberships[item].erase( obj.id ); } void account_member_index::about_to_modify(const object& before) { before_key_members.clear(); before_account_members.clear(); assert( dynamic_cast(&before) ); // for debug only const account_object& a = static_cast(before); before_key_members = get_key_members(a); before_address_members = get_address_members(a); before_account_members = get_account_members(a); } void account_member_index::object_modified(const object& after) { assert( dynamic_cast(&after) ); // for debug only const account_object& a = static_cast(after); { set after_account_members = get_account_members(a); vector removed; removed.reserve(before_account_members.size()); std::set_difference(before_account_members.begin(), before_account_members.end(), after_account_members.begin(), after_account_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_account_memberships[*itr].erase(after.id); vector added; added.reserve(after_account_members.size()); std::set_difference(after_account_members.begin(), after_account_members.end(), before_account_members.begin(), before_account_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_account_memberships[*itr].insert(after.id); } { set after_key_members = get_key_members(a); vector removed; removed.reserve(before_key_members.size()); std::set_difference(before_key_members.begin(), before_key_members.end(), after_key_members.begin(), after_key_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_key_memberships[*itr].erase(after.id); vector added; added.reserve(after_key_members.size()); std::set_difference(after_key_members.begin(), after_key_members.end(), before_key_members.begin(), before_key_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_key_memberships[*itr].insert(after.id); } { set
after_address_members = get_address_members(a); vector
removed; removed.reserve(before_address_members.size()); std::set_difference(before_address_members.begin(), before_address_members.end(), after_address_members.begin(), after_address_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_address_memberships[*itr].erase(after.id); vector
added; added.reserve(after_address_members.size()); std::set_difference(after_address_members.begin(), after_address_members.end(), before_address_members.begin(), before_address_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_address_memberships[*itr].insert(after.id); } } void account_referrer_index::object_inserted( const object& obj ) { } void account_referrer_index::object_removed( const object& obj ) { } void account_referrer_index::about_to_modify( const object& before ) { } void account_referrer_index::object_modified( const object& after ) { } } } // graphene::chain