diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index d8793423..35cf3880 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -348,6 +348,8 @@ namespace graphene { namespace app { break; case impl_buyback_object_type: break; + case impl_fba_accumulator_object_type: + break; } } return result; diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index b85d4573..85787423 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -198,6 +198,11 @@ struct get_impacted_account_visitor _impacted.insert( op.account ); } + void operator()( const fba_distribute_operation& op ) + { + _impacted.insert( op.account_id ); + } + }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index d0cbc20b..c38bd80b 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -81,6 +81,7 @@ add_library( graphene_chain account_object.cpp asset_object.cpp + fba_object.cpp proposal_object.cpp vesting_balance_object.cpp diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 03fe26c7..1f29bb0a 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -260,14 +260,28 @@ void_result account_update_evaluator::do_apply( const account_update_operation& database& d = db(); bool sa_before, sa_after; d.modify( *acnt, [&](account_object& a){ - if( o.owner ) a.owner = *o.owner; - if( o.active ) a.active = *o.active; + if( o.owner ) + { + a.owner = *o.owner; + a.top_n_control_flags = 0; + } + if( o.active ) + { + a.active = *o.active; + a.top_n_control_flags = 0; + } if( o.new_options ) a.options = *o.new_options; sa_before = a.has_special_authority(); if( o.extensions.value.owner_special_authority.valid() ) + { a.owner_special_authority = *(o.extensions.value.owner_special_authority); + a.top_n_control_flags = 0; + } if( o.extensions.value.active_special_authority.valid() ) + { a.active_special_authority = *(o.extensions.value.active_special_authority); + a.top_n_control_flags = 0; + } sa_after = a.has_special_authority(); }); diff --git a/libraries/chain/confidential_evaluator.cpp b/libraries/chain/confidential_evaluator.cpp index bcfef1e9..9946b492 100644 --- a/libraries/chain/confidential_evaluator.cpp +++ b/libraries/chain/confidential_evaluator.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include namespace graphene { namespace chain { @@ -67,6 +69,13 @@ void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_opera return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } +void transfer_to_blind_evaluator::pay_fee() +{ + if( db().head_block_time() >= HARDFORK_563_TIME ) + pay_fba_fee( fba_accumulator_id_transfer_to_blind ); + else + generic_evaluator::pay_fee(); +} void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o ) { try { @@ -104,9 +113,13 @@ void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_o return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } - - - +void transfer_from_blind_evaluator::pay_fee() +{ + if( db().head_block_time() >= HARDFORK_563_TIME ) + pay_fba_fee( fba_accumulator_id_transfer_from_blind ); + else + generic_evaluator::pay_fee(); +} void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o ) { try { @@ -157,5 +170,12 @@ void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation& return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } +void blind_transfer_evaluator::pay_fee() +{ + if( db().head_block_time() >= HARDFORK_563_TIME ) + pay_fba_fee( fba_accumulator_id_blind_transfer ); + else + generic_evaluator::pay_fee(); +} } } // graphene::chain diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 1b9a37c0..302abef4 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -23,6 +23,7 @@ */ #include +#include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -212,6 +214,8 @@ void database::initialize_indexes() add_index< primary_index > >(); add_index< primary_index< special_authority_index > >(); add_index< primary_index< buyback_index > >(); + + add_index< primary_index< simple_index< fba_accumulator_object > > >(); } void database::init_genesis(const genesis_state_type& genesis_state) @@ -664,6 +668,36 @@ void database::init_genesis(const genesis_state_type& genesis_state) wso.current_shuffled_witnesses.push_back( wid ); }); + // Create FBA counters + create([&]( fba_accumulator_object& acc ) + { + FC_ASSERT( acc.id == fba_accumulator_id_type( fba_accumulator_id_transfer_to_blind ) ); + acc.accumulated_fba_fees = 0; +#ifdef GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET + acc.designated_asset = GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET; +#endif + }); + + create([&]( fba_accumulator_object& acc ) + { + FC_ASSERT( acc.id == fba_accumulator_id_type( fba_accumulator_id_blind_transfer ) ); + acc.accumulated_fba_fees = 0; +#ifdef GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET + acc.designated_asset = GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET; +#endif + }); + + create([&]( fba_accumulator_object& acc ) + { + FC_ASSERT( acc.id == fba_accumulator_id_type( fba_accumulator_id_transfer_from_blind ) ); + acc.accumulated_fba_fees = 0; +#ifdef GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET + acc.designated_asset = GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET; +#endif + }); + + FC_ASSERT( get_index().get_next_id() == fba_accumulator_id_type( fba_accumulator_id_count ) ); + debug_dump(); _undo_db.enable(); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 9721ae45..9eabb1d9 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -519,11 +521,100 @@ void update_top_n_authorities( database& db ) db.modify( acct, [&]( account_object& a ) { vc.finish( is_owner ? a.owner : a.active ); + if( !vc.is_empty() ) + a.top_n_control_flags |= (is_owner ? account_object::top_n_control_owner : account_object::top_n_control_active); } ); } } ); } +void split_fba_balance( + database& db, + uint64_t fba_id, + uint16_t network_pct, + uint16_t designated_asset_buyback_pct, + uint16_t designated_asset_issuer_pct +) +{ + FC_ASSERT( uint32_t(network_pct) + uint32_t(designated_asset_buyback_pct) + uint32_t(designated_asset_issuer_pct) == GRAPHENE_100_PERCENT ); + const fba_accumulator_object& fba = fba_accumulator_id_type( fba_id )(db); + if( fba.accumulated_fba_fees == 0 ) + return; + + const asset_object& core = asset_id_type(0)(db); + const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(db); + + if( !fba.is_configured(db) ) + { + ilog( "${n} core given to network at block ${b} due to non-configured FBA", ("n", fba.accumulated_fba_fees)("b", db.head_block_time()) ); + db.modify( core_dd, [&]( asset_dynamic_data_object& _core_dd ) + { + _core_dd.current_supply -= fba.accumulated_fba_fees; + } ); + db.modify( fba, [&]( fba_accumulator_object& _fba ) + { + _fba.accumulated_fba_fees = 0; + } ); + return; + } + + fc::uint128_t buyback_amount_128 = fba.accumulated_fba_fees.value; + buyback_amount_128 *= designated_asset_buyback_pct; + buyback_amount_128 /= GRAPHENE_100_PERCENT; + share_type buyback_amount = buyback_amount_128.to_uint64(); + + fc::uint128_t issuer_amount_128 = fba.accumulated_fba_fees.value; + issuer_amount_128 *= designated_asset_issuer_pct; + issuer_amount_128 /= GRAPHENE_100_PERCENT; + share_type issuer_amount = issuer_amount_128.to_uint64(); + + // this assert should never fail + FC_ASSERT( buyback_amount + issuer_amount <= fba.accumulated_fba_fees ); + + share_type network_amount = fba.accumulated_fba_fees - (buyback_amount + issuer_amount); + + const asset_object& designated_asset = (*fba.designated_asset)(db); + + if( network_amount != 0 ) + { + db.modify( core_dd, [&]( asset_dynamic_data_object& _core_dd ) + { + _core_dd.current_supply -= network_amount; + } ); + } + + fba_distribute_operation vop; + vop.account_id = *designated_asset.buyback_account; + vop.fba_id = fba.id; + vop.amount = buyback_amount; + if( vop.amount != 0 ) + { + db.adjust_balance( *designated_asset.buyback_account, asset(buyback_amount) ); + db.push_applied_operation(vop); + } + + vop.account_id = designated_asset.issuer; + vop.fba_id = fba.id; + vop.amount = issuer_amount; + if( vop.amount != 0 ) + { + db.adjust_balance( designated_asset.issuer, asset(issuer_amount) ); + db.push_applied_operation(vop); + } + + db.modify( fba, [&]( fba_accumulator_object& _fba ) + { + _fba.accumulated_fba_fees = 0; + } ); +} + +void distribute_fba_balances( database& db ) +{ + split_fba_balance( db, fba_accumulator_id_transfer_to_blind , 20*GRAPHENE_1_PERCENT, 60*GRAPHENE_1_PERCENT, 20*GRAPHENE_1_PERCENT ); + split_fba_balance( db, fba_accumulator_id_blind_transfer , 20*GRAPHENE_1_PERCENT, 60*GRAPHENE_1_PERCENT, 20*GRAPHENE_1_PERCENT ); + split_fba_balance( db, fba_accumulator_id_transfer_from_blind, 20*GRAPHENE_1_PERCENT, 60*GRAPHENE_1_PERCENT, 20*GRAPHENE_1_PERCENT ); +} + void create_buyback_orders( database& db ) { const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get(); @@ -604,6 +695,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g { const auto& gpo = get_global_properties(); + distribute_fba_balances(*this); create_buyback_orders(*this); struct vote_tally_helper { diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index 06e31c21..b27d3960 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -103,4 +104,18 @@ database& generic_evaluator::db()const { return trx_state->db(); } } } FC_CAPTURE_AND_RETHROW() } + void generic_evaluator::pay_fba_fee( uint64_t fba_id ) + { + database& d = db(); + const fba_accumulator_object& fba = d.get< fba_accumulator_object >( fba_accumulator_id_type( fba_id ) ); + if( !fba.is_configured(d) ) + { + generic_evaluator::pay_fee(); + return; + } + d.modify( fba, [&]( fba_accumulator_object& _fba ) + { + _fba.accumulated_fba_fees += core_fee_paid; + } ); + } } } diff --git a/libraries/chain/fba_object.cpp b/libraries/chain/fba_object.cpp new file mode 100644 index 00000000..2febca45 --- /dev/null +++ b/libraries/chain/fba_object.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +namespace graphene { namespace chain { + +bool fba_accumulator_object::is_configured( const database& db )const +{ + if( !designated_asset.valid() ) + { + ilog( "FBA fee in block ${b} not paid because designated asset was not configured", ("b", db.head_block_num()) ); + return false; + } + const asset_object* dasset = db.find(*designated_asset); + if( dasset == nullptr ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset does not exist", ("b", db.head_block_num()) ); + return false; + } + if( dasset->is_market_issued() ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: FBA is a BitAsset", ("b", db.head_block_num()) ); + return false; + } + + const uint16_t allowed_flags = charge_market_fee; + + // check enabled issuer_permissions bits is subset of allowed_flags bits + if( (dasset->options.issuer_permissions & allowed_flags) != dasset->options.issuer_permissions ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: Disallowed permissions enabled", ("b", db.head_block_num()) ); + return false; + } + + // check enabled issuer_permissions bits is subset of allowed_flags bits + if( (dasset->options.flags & allowed_flags) != dasset->options.flags ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: Disallowed flags enabled", ("b", db.head_block_num()) ); + return false; + } + + if( !dasset->buyback_account.valid() ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset does not have a buyback account", ("b", db.head_block_num()) ); + return false; + } + const account_object& issuer_acct = dasset->issuer(db); + + if( issuer_acct.owner_special_authority.which() != special_authority::tag< top_holders_special_authority >::value ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset issuer has not set owner top_n control", ("b", db.head_block_num()) ); + return false; + } + if( issuer_acct.active_special_authority.which() != special_authority::tag< top_holders_special_authority >::value ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset issuer has not set active top_n control", ("b", db.head_block_num()) ); + return false; + } + if( issuer_acct.owner_special_authority.get< top_holders_special_authority >().asset != *designated_asset ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset issuer's top_n_control is not set to designated asset", ("b", db.head_block_num()) ); + return false; + } + if( issuer_acct.active_special_authority.get< top_holders_special_authority >().asset != *designated_asset ) + { + ilog( "FBA fee in block ${b} not paid because of FBA misconfiguration: designated asset issuer's top_n_control is not set to designated asset", ("b", db.head_block_num()) ); + return false; + } + + if( issuer_acct.top_n_control_flags != (account_object::top_n_control_owner | account_object::top_n_control_active) ) + { + ilog( "FBA fee in block ${b} not paid because designated asset's top_n control has not yet activated (wait until next maintenance interval)", ("b", db.head_block_num()) ); + return false; + } + + return true; +} + +} } diff --git a/libraries/chain/hardfork.d/563.hf b/libraries/chain/hardfork.d/563.hf new file mode 100644 index 00000000..892214ed --- /dev/null +++ b/libraries/chain/hardfork.d/563.hf @@ -0,0 +1,4 @@ +// #563 Stealth fee routing +#ifndef HARDFORK_563_TIME +#define HARDFORK_563_TIME (fc::time_point_sec( 1455127200 )) +#endif diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 0af36acc..11f0f586 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -208,6 +208,14 @@ namespace graphene { namespace chain { special_authority owner_special_authority = no_special_authority(); special_authority active_special_authority = no_special_authority(); + /** + * This flag is set when the top_n logic sets both authorities, + * and gets reset when authority or special_authority is set. + */ + uint8_t top_n_control_flags = 0; + static const uint8_t top_n_control_owner = 1; + static const uint8_t top_n_control_active = 2; + /** * This is a set of assets which the account is allowed to have. * This is utilized to restrict buyback accounts to the assets that trade in their markets. @@ -365,6 +373,7 @@ FC_REFLECT_DERIVED( graphene::chain::account_object, (whitelisting_accounts)(blacklisted_accounts) (cashback_vb) (owner_special_authority)(active_special_authority) + (top_n_control_flags) (allowed_assets) ) diff --git a/libraries/chain/include/graphene/chain/confidential_evaluator.hpp b/libraries/chain/include/graphene/chain/confidential_evaluator.hpp index 1f047c09..93e0e78e 100644 --- a/libraries/chain/include/graphene/chain/confidential_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/confidential_evaluator.hpp @@ -37,6 +37,8 @@ class transfer_to_blind_evaluator : public evaluator @@ -46,6 +48,8 @@ class transfer_from_blind_evaluator : public evaluator @@ -55,6 +59,8 @@ class blind_transfer_evaluator : public evaluator void_result do_evaluate( const blind_transfer_operation& o ); void_result do_apply( const blind_transfer_operation& o ) ; + + virtual void pay_fee() override; }; } } // namespace graphene::chain diff --git a/libraries/chain/include/graphene/chain/evaluator.hpp b/libraries/chain/include/graphene/chain/evaluator.hpp index 4271be58..8019e8f6 100644 --- a/libraries/chain/include/graphene/chain/evaluator.hpp +++ b/libraries/chain/include/graphene/chain/evaluator.hpp @@ -138,6 +138,11 @@ namespace graphene { namespace chain { object_id_type get_relative_id( object_id_type rel_id )const; + /** + * pay_fee() for FBA subclass should simply call this method + */ + void pay_fba_fee( uint64_t fba_id ); + asset fee_from_account; share_type core_fee_paid; const account_object* fee_paying_account = nullptr; diff --git a/libraries/chain/include/graphene/chain/fba_accumulator_id.hpp b/libraries/chain/include/graphene/chain/fba_accumulator_id.hpp new file mode 100644 index 00000000..9bc0cf23 --- /dev/null +++ b/libraries/chain/include/graphene/chain/fba_accumulator_id.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include + +namespace graphene { namespace chain { + +/** + * An object will be created at genesis for each of these FBA accumulators. + */ +enum graphene_fba_accumulator_id_enum +{ + fba_accumulator_id_transfer_to_blind = 0, + fba_accumulator_id_blind_transfer, + fba_accumulator_id_transfer_from_blind, + fba_accumulator_id_count +}; + +} } diff --git a/libraries/chain/include/graphene/chain/fba_object.hpp b/libraries/chain/include/graphene/chain/fba_object.hpp new file mode 100644 index 00000000..aec9e9cd --- /dev/null +++ b/libraries/chain/include/graphene/chain/fba_object.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include +#include +#include + +namespace graphene { namespace chain { + +class database; + +/** + * fba_accumulator_object accumulates fees to be paid out via buyback or other FBA mechanism. + */ + +class fba_accumulator_object : public graphene::db::abstract_object< fba_accumulator_object > +{ + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_fba_accumulator_object_type; + + share_type accumulated_fba_fees; + optional< asset_id_type > designated_asset; + + bool is_configured( const database& db )const; +}; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::fba_accumulator_object, (graphene::db::object), (accumulated_fba_fees)(designated_asset) ) diff --git a/libraries/chain/include/graphene/chain/protocol/fba.hpp b/libraries/chain/include/graphene/chain/protocol/fba.hpp new file mode 100644 index 00000000..7460ca8d --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/fba.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include + +namespace graphene { namespace chain { + +struct fba_distribute_operation : public base_operation +{ + struct fee_parameters_type {}; + + asset fee; // always zero + account_id_type account_id; + fba_accumulator_id_type fba_id; + share_type amount; + + account_id_type fee_payer()const { return account_id; } + void validate()const { FC_ASSERT( false ); } + share_type calculate_fee(const fee_parameters_type& k)const { return 0; } +}; + +} } + +FC_REFLECT( graphene::chain::fba_distribute_operation::fee_parameters_type, ) + +FC_REFLECT( graphene::chain::fba_distribute_operation, (fee)(account_id)(fba_id)(amount) ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 66a2ced3..7f2639f1 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include namespace graphene { namespace chain { @@ -89,7 +90,8 @@ namespace graphene { namespace chain { blind_transfer_operation, transfer_from_blind_operation, asset_settle_cancel_operation, // VIRTUAL - asset_claim_fees_operation + asset_claim_fees_operation, + fba_distribute_operation // VIRTUAL > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index fac66d7a..5237fcad 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -154,7 +154,8 @@ namespace graphene { namespace chain { impl_witness_schedule_object_type, impl_budget_record_object_type, impl_special_authority_object_type, - impl_buyback_object_type + impl_buyback_object_type, + impl_fba_accumulator_object_type }; //typedef fc::unsigned_int object_id_type; @@ -205,6 +206,7 @@ namespace graphene { namespace chain { class budget_record_object; class special_authority_object; class buyback_object; + class fba_accumulator_object; typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; @@ -224,6 +226,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_blinded_balance_object_type, blinded_balance_object > blinded_balance_id_type; typedef object_id< implementation_ids, impl_special_authority_object_type, special_authority_object > special_authority_id_type; typedef object_id< implementation_ids, impl_buyback_object_type, buyback_object > buyback_id_type; + typedef object_id< implementation_ids, impl_fba_accumulator_object_type, fba_accumulator_object > fba_accumulator_id_type; typedef fc::array symbol_type; typedef fc::ripemd160 block_id_type; @@ -355,6 +358,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_budget_record_object_type) (impl_special_authority_object_type) (impl_buyback_object_type) + (impl_fba_accumulator_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) @@ -384,6 +388,9 @@ FC_REFLECT_TYPENAME( graphene::chain::block_summary_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_transaction_history_id_type ) FC_REFLECT_TYPENAME( graphene::chain::budget_record_id_type ) FC_REFLECT_TYPENAME( graphene::chain::special_authority_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::buyback_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type ) + FC_REFLECT( graphene::chain::void_t, ) FC_REFLECT_ENUM( graphene::chain::asset_issuer_permission_flags, diff --git a/libraries/chain/include/graphene/chain/vote_count.hpp b/libraries/chain/include/graphene/chain/vote_count.hpp index bb23b840..f76a784d 100644 --- a/libraries/chain/include/graphene/chain/vote_count.hpp +++ b/libraries/chain/include/graphene/chain/vote_count.hpp @@ -63,6 +63,11 @@ struct vote_counter out_auth = auth; } + bool is_empty()const + { + return (total_votes == 0); + } + uint64_t last_votes = std::numeric_limits::max(); uint64_t total_votes = 0; int8_t bitshift = -1;