Merge branch '563-fork-stealth-fee-routing' into develop
Includes dependency '572-fork-reenable-asset-perms'
This commit is contained in:
commit
92685af364
25 changed files with 720 additions and 11 deletions
|
|
@ -348,6 +348,8 @@ namespace graphene { namespace app {
|
||||||
break;
|
break;
|
||||||
case impl_buyback_object_type:
|
case impl_buyback_object_type:
|
||||||
break;
|
break;
|
||||||
|
case impl_fba_accumulator_object_type:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,11 @@ struct get_impacted_account_visitor
|
||||||
_impacted.insert( op.account );
|
_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<account_id_type>& result )
|
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ add_library( graphene_chain
|
||||||
|
|
||||||
account_object.cpp
|
account_object.cpp
|
||||||
asset_object.cpp
|
asset_object.cpp
|
||||||
|
fba_object.cpp
|
||||||
proposal_object.cpp
|
proposal_object.cpp
|
||||||
vesting_balance_object.cpp
|
vesting_balance_object.cpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -260,14 +260,28 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
|
||||||
database& d = db();
|
database& d = db();
|
||||||
bool sa_before, sa_after;
|
bool sa_before, sa_after;
|
||||||
d.modify( *acnt, [&](account_object& a){
|
d.modify( *acnt, [&](account_object& a){
|
||||||
if( o.owner ) a.owner = *o.owner;
|
if( o.owner )
|
||||||
if( o.active ) a.active = *o.active;
|
{
|
||||||
|
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;
|
if( o.new_options ) a.options = *o.new_options;
|
||||||
sa_before = a.has_special_authority();
|
sa_before = a.has_special_authority();
|
||||||
if( o.extensions.value.owner_special_authority.valid() )
|
if( o.extensions.value.owner_special_authority.valid() )
|
||||||
|
{
|
||||||
a.owner_special_authority = *(o.extensions.value.owner_special_authority);
|
a.owner_special_authority = *(o.extensions.value.owner_special_authority);
|
||||||
|
a.top_n_control_flags = 0;
|
||||||
|
}
|
||||||
if( o.extensions.value.active_special_authority.valid() )
|
if( o.extensions.value.active_special_authority.valid() )
|
||||||
|
{
|
||||||
a.active_special_authority = *(o.extensions.value.active_special_authority);
|
a.active_special_authority = *(o.extensions.value.active_special_authority);
|
||||||
|
a.top_n_control_flags = 0;
|
||||||
|
}
|
||||||
sa_after = a.has_special_authority();
|
sa_after = a.has_special_authority();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,9 +252,12 @@ void_result asset_update_evaluator::do_evaluate(const asset_update_operation& o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( (d.head_block_time() < HARDFORK_572_TIME) || (a.dynamic_asset_data_id(d).current_supply != 0) )
|
||||||
|
{
|
||||||
// new issuer_permissions must be subset of old issuer permissions
|
// new issuer_permissions must be subset of old issuer permissions
|
||||||
FC_ASSERT(!(o.new_options.issuer_permissions & ~a.options.issuer_permissions),
|
FC_ASSERT(!(o.new_options.issuer_permissions & ~a.options.issuer_permissions),
|
||||||
"Cannot reinstate previously revoked issuer permissions on an asset.");
|
"Cannot reinstate previously revoked issuer permissions on an asset.");
|
||||||
|
}
|
||||||
|
|
||||||
// changed flags must be subset of old issuer permissions
|
// changed flags must be subset of old issuer permissions
|
||||||
FC_ASSERT(!((o.new_options.flags ^ a.options.flags) & ~a.options.issuer_permissions),
|
FC_ASSERT(!((o.new_options.flags ^ a.options.flags) & ~a.options.issuer_permissions),
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#include <graphene/chain/confidential_evaluator.hpp>
|
#include <graphene/chain/confidential_evaluator.hpp>
|
||||||
#include <graphene/chain/confidential_object.hpp>
|
#include <graphene/chain/confidential_object.hpp>
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
|
#include <graphene/chain/fba_accumulator_id.hpp>
|
||||||
|
#include <graphene/chain/hardfork.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
|
@ -67,6 +69,13 @@ void_result transfer_to_blind_evaluator::do_apply( const transfer_to_blind_opera
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} 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 )
|
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
|
|
@ -104,9 +113,13 @@ void_result transfer_from_blind_evaluator::do_apply( const transfer_from_blind_o
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} 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 )
|
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
|
||||||
{ try {
|
{ try {
|
||||||
|
|
@ -157,5 +170,12 @@ void_result blind_transfer_evaluator::do_apply( const blind_transfer_operation&
|
||||||
return void_result();
|
return void_result();
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
} 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
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
|
#include <graphene/chain/fba_accumulator_id.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
|
|
@ -33,6 +34,7 @@
|
||||||
#include <graphene/chain/chain_property_object.hpp>
|
#include <graphene/chain/chain_property_object.hpp>
|
||||||
#include <graphene/chain/committee_member_object.hpp>
|
#include <graphene/chain/committee_member_object.hpp>
|
||||||
#include <graphene/chain/confidential_object.hpp>
|
#include <graphene/chain/confidential_object.hpp>
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
#include <graphene/chain/global_property_object.hpp>
|
#include <graphene/chain/global_property_object.hpp>
|
||||||
#include <graphene/chain/market_object.hpp>
|
#include <graphene/chain/market_object.hpp>
|
||||||
#include <graphene/chain/operation_history_object.hpp>
|
#include <graphene/chain/operation_history_object.hpp>
|
||||||
|
|
@ -212,6 +214,8 @@ void database::initialize_indexes()
|
||||||
add_index< primary_index<simple_index<budget_record_object > > >();
|
add_index< primary_index<simple_index<budget_record_object > > >();
|
||||||
add_index< primary_index< special_authority_index > >();
|
add_index< primary_index< special_authority_index > >();
|
||||||
add_index< primary_index< buyback_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)
|
void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
|
|
@ -663,6 +667,36 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
wso.current_shuffled_witnesses.push_back( wid );
|
wso.current_shuffled_witnesses.push_back( wid );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create FBA counters
|
||||||
|
create<fba_accumulator_object>([&]( 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>([&]( 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>([&]( 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<fba_accumulator_object>().get_next_id() == fba_accumulator_id_type( fba_accumulator_id_count ) );
|
||||||
|
|
||||||
debug_dump();
|
debug_dump();
|
||||||
|
|
||||||
_undo_db.enable();
|
_undo_db.enable();
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <fc/uint128.hpp>
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
|
#include <graphene/chain/fba_accumulator_id.hpp>
|
||||||
#include <graphene/chain/hardfork.hpp>
|
#include <graphene/chain/hardfork.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
|
|
@ -36,6 +37,7 @@
|
||||||
#include <graphene/chain/buyback_object.hpp>
|
#include <graphene/chain/buyback_object.hpp>
|
||||||
#include <graphene/chain/chain_property_object.hpp>
|
#include <graphene/chain/chain_property_object.hpp>
|
||||||
#include <graphene/chain/committee_member_object.hpp>
|
#include <graphene/chain/committee_member_object.hpp>
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
#include <graphene/chain/global_property_object.hpp>
|
#include <graphene/chain/global_property_object.hpp>
|
||||||
#include <graphene/chain/market_object.hpp>
|
#include <graphene/chain/market_object.hpp>
|
||||||
#include <graphene/chain/special_authority_object.hpp>
|
#include <graphene/chain/special_authority_object.hpp>
|
||||||
|
|
@ -512,11 +514,100 @@ void update_top_n_authorities( database& db )
|
||||||
db.modify( acct, [&]( account_object& a )
|
db.modify( acct, [&]( account_object& a )
|
||||||
{
|
{
|
||||||
vc.finish( is_owner ? a.owner : a.active );
|
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 )
|
void create_buyback_orders( database& db )
|
||||||
{
|
{
|
||||||
const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
|
const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
|
||||||
|
|
@ -597,6 +688,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
||||||
{
|
{
|
||||||
const auto& gpo = get_global_properties();
|
const auto& gpo = get_global_properties();
|
||||||
|
|
||||||
|
distribute_fba_balances(*this);
|
||||||
create_buyback_orders(*this);
|
create_buyback_orders(*this);
|
||||||
|
|
||||||
struct vote_tally_helper {
|
struct vote_tally_helper {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
#include <graphene/chain/committee_member_object.hpp>
|
#include <graphene/chain/committee_member_object.hpp>
|
||||||
#include <graphene/chain/market_evaluator.hpp>
|
#include <graphene/chain/market_evaluator.hpp>
|
||||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||||
|
|
@ -103,4 +104,18 @@ database& generic_evaluator::db()const { return trx_state->db(); }
|
||||||
}
|
}
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
} 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;
|
||||||
|
} );
|
||||||
|
}
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
103
libraries/chain/fba_object.cpp
Normal file
103
libraries/chain/fba_object.cpp
Normal file
|
|
@ -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 <graphene/chain/database.hpp>
|
||||||
|
#include <graphene/chain/evaluator.hpp>
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
||||||
4
libraries/chain/hardfork.d/563.hf
Normal file
4
libraries/chain/hardfork.d/563.hf
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// #563 Stealth fee routing
|
||||||
|
#ifndef HARDFORK_563_TIME
|
||||||
|
#define HARDFORK_563_TIME (fc::time_point_sec( 1455127200 ))
|
||||||
|
#endif
|
||||||
4
libraries/chain/hardfork.d/572.hf
Normal file
4
libraries/chain/hardfork.d/572.hf
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// #572 Allow asset to update permission flags when no supply exists
|
||||||
|
#ifndef HARDFORK_572_TIME
|
||||||
|
#define HARDFORK_572_TIME (fc::time_point_sec( 1450378800 ))
|
||||||
|
#endif
|
||||||
|
|
@ -208,6 +208,14 @@ namespace graphene { namespace chain {
|
||||||
special_authority owner_special_authority = no_special_authority();
|
special_authority owner_special_authority = no_special_authority();
|
||||||
special_authority active_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 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.
|
* 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,
|
||||||
(whitelisted_accounts)(blacklisted_accounts)
|
(whitelisted_accounts)(blacklisted_accounts)
|
||||||
(cashback_vb)
|
(cashback_vb)
|
||||||
(owner_special_authority)(active_special_authority)
|
(owner_special_authority)(active_special_authority)
|
||||||
|
(top_n_control_flags)
|
||||||
(allowed_assets)
|
(allowed_assets)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ class transfer_to_blind_evaluator : public evaluator<transfer_to_blind_evaluator
|
||||||
|
|
||||||
void_result do_evaluate( const transfer_to_blind_operation& o );
|
void_result do_evaluate( const transfer_to_blind_operation& o );
|
||||||
void_result do_apply( const transfer_to_blind_operation& o ) ;
|
void_result do_apply( const transfer_to_blind_operation& o ) ;
|
||||||
|
|
||||||
|
virtual void pay_fee() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class transfer_from_blind_evaluator : public evaluator<transfer_from_blind_evaluator>
|
class transfer_from_blind_evaluator : public evaluator<transfer_from_blind_evaluator>
|
||||||
|
|
@ -46,6 +48,8 @@ class transfer_from_blind_evaluator : public evaluator<transfer_from_blind_evalu
|
||||||
|
|
||||||
void_result do_evaluate( const transfer_from_blind_operation& o );
|
void_result do_evaluate( const transfer_from_blind_operation& o );
|
||||||
void_result do_apply( const transfer_from_blind_operation& o ) ;
|
void_result do_apply( const transfer_from_blind_operation& o ) ;
|
||||||
|
|
||||||
|
virtual void pay_fee() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class blind_transfer_evaluator : public evaluator<blind_transfer_evaluator>
|
class blind_transfer_evaluator : public evaluator<blind_transfer_evaluator>
|
||||||
|
|
@ -55,6 +59,8 @@ class blind_transfer_evaluator : public evaluator<blind_transfer_evaluator>
|
||||||
|
|
||||||
void_result do_evaluate( const blind_transfer_operation& o );
|
void_result do_evaluate( const blind_transfer_operation& o );
|
||||||
void_result do_apply( const blind_transfer_operation& o ) ;
|
void_result do_apply( const blind_transfer_operation& o ) ;
|
||||||
|
|
||||||
|
virtual void pay_fee() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace graphene::chain
|
} } // namespace graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -167,3 +167,6 @@
|
||||||
/// Sentinel value used in the scheduler.
|
/// Sentinel value used in the scheduler.
|
||||||
#define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0))
|
#define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0))
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
// hack for unit test
|
||||||
|
#define GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET (asset_id_type(1))
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,11 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
object_id_type get_relative_id( object_id_type rel_id )const;
|
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;
|
asset fee_from_account;
|
||||||
share_type core_fee_paid;
|
share_type core_fee_paid;
|
||||||
const account_object* fee_paying_account = nullptr;
|
const account_object* fee_paying_account = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -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 <graphene/chain/protocol/types.hpp>
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
52
libraries/chain/include/graphene/chain/fba_object.hpp
Normal file
52
libraries/chain/include/graphene/chain/fba_object.hpp
Normal file
|
|
@ -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 <graphene/chain/protocol/types.hpp>
|
||||||
|
#include <graphene/db/object.hpp>
|
||||||
|
#include <graphene/db/generic_index.hpp>
|
||||||
|
|
||||||
|
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) )
|
||||||
47
libraries/chain/include/graphene/chain/protocol/fba.hpp
Normal file
47
libraries/chain/include/graphene/chain/protocol/fba.hpp
Normal file
|
|
@ -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 <graphene/chain/protocol/base.hpp>
|
||||||
|
|
||||||
|
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) )
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
#include <graphene/chain/protocol/balance.hpp>
|
#include <graphene/chain/protocol/balance.hpp>
|
||||||
#include <graphene/chain/protocol/custom.hpp>
|
#include <graphene/chain/protocol/custom.hpp>
|
||||||
#include <graphene/chain/protocol/committee_member.hpp>
|
#include <graphene/chain/protocol/committee_member.hpp>
|
||||||
|
#include <graphene/chain/protocol/confidential.hpp>
|
||||||
|
#include <graphene/chain/protocol/fba.hpp>
|
||||||
#include <graphene/chain/protocol/market.hpp>
|
#include <graphene/chain/protocol/market.hpp>
|
||||||
#include <graphene/chain/protocol/proposal.hpp>
|
#include <graphene/chain/protocol/proposal.hpp>
|
||||||
#include <graphene/chain/protocol/transfer.hpp>
|
#include <graphene/chain/protocol/transfer.hpp>
|
||||||
|
|
@ -36,7 +38,6 @@
|
||||||
#include <graphene/chain/protocol/withdraw_permission.hpp>
|
#include <graphene/chain/protocol/withdraw_permission.hpp>
|
||||||
#include <graphene/chain/protocol/witness.hpp>
|
#include <graphene/chain/protocol/witness.hpp>
|
||||||
#include <graphene/chain/protocol/worker.hpp>
|
#include <graphene/chain/protocol/worker.hpp>
|
||||||
#include <graphene/chain/protocol/confidential.hpp>
|
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
|
@ -89,7 +90,8 @@ namespace graphene { namespace chain {
|
||||||
blind_transfer_operation,
|
blind_transfer_operation,
|
||||||
transfer_from_blind_operation,
|
transfer_from_blind_operation,
|
||||||
asset_settle_cancel_operation, // VIRTUAL
|
asset_settle_cancel_operation, // VIRTUAL
|
||||||
asset_claim_fees_operation
|
asset_claim_fees_operation,
|
||||||
|
fba_distribute_operation // VIRTUAL
|
||||||
> operation;
|
> operation;
|
||||||
|
|
||||||
/// @} // operations group
|
/// @} // operations group
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,8 @@ namespace graphene { namespace chain {
|
||||||
impl_witness_schedule_object_type,
|
impl_witness_schedule_object_type,
|
||||||
impl_budget_record_object_type,
|
impl_budget_record_object_type,
|
||||||
impl_special_authority_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;
|
//typedef fc::unsigned_int object_id_type;
|
||||||
|
|
@ -205,6 +206,7 @@ namespace graphene { namespace chain {
|
||||||
class budget_record_object;
|
class budget_record_object;
|
||||||
class special_authority_object;
|
class special_authority_object;
|
||||||
class buyback_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_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;
|
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_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_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_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<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
|
typedef fc::array<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> symbol_type;
|
||||||
typedef fc::ripemd160 block_id_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_budget_record_object_type)
|
||||||
(impl_special_authority_object_type)
|
(impl_special_authority_object_type)
|
||||||
(impl_buyback_object_type)
|
(impl_buyback_object_type)
|
||||||
|
(impl_fba_accumulator_object_type)
|
||||||
)
|
)
|
||||||
|
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::share_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::account_transaction_history_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::budget_record_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::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( graphene::chain::void_t, )
|
||||||
|
|
||||||
FC_REFLECT_ENUM( graphene::chain::asset_issuer_permission_flags,
|
FC_REFLECT_ENUM( graphene::chain::asset_issuer_permission_flags,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,11 @@ struct vote_counter
|
||||||
out_auth = auth;
|
out_auth = auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_empty()const
|
||||||
|
{
|
||||||
|
return (total_votes == 0);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t last_votes = std::numeric_limits<uint64_t>::max();
|
uint64_t last_votes = std::numeric_limits<uint64_t>::max();
|
||||||
uint64_t total_votes = 0;
|
uint64_t total_votes = 0;
|
||||||
int8_t bitshift = -1;
|
int8_t bitshift = -1;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/committee_member_object.hpp>
|
#include <graphene/chain/committee_member_object.hpp>
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
#include <graphene/chain/market_object.hpp>
|
#include <graphene/chain/market_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
|
|
@ -195,6 +196,8 @@ void database_fixture::verify_asset_supplies( const database& db )
|
||||||
}
|
}
|
||||||
for( const vesting_balance_object& vbo : db.get_index_type< vesting_balance_index >().indices() )
|
for( const vesting_balance_object& vbo : db.get_index_type< vesting_balance_index >().indices() )
|
||||||
total_balances[ vbo.balance.asset_id ] += vbo.balance.amount;
|
total_balances[ vbo.balance.asset_id ] += vbo.balance.amount;
|
||||||
|
for( const fba_accumulator_object& fba : db.get_index_type< simple_index< fba_accumulator_object > >() )
|
||||||
|
total_balances[ asset_id_type() ] += fba.accumulated_fba_fees;
|
||||||
|
|
||||||
total_balances[asset_id_type()] += db.get_dynamic_global_properties().witness_budget;
|
total_balances[asset_id_type()] += db.get_dynamic_global_properties().witness_budget;
|
||||||
|
|
||||||
|
|
@ -1033,6 +1036,24 @@ int64_t database_fixture::get_balance( const account_object& account, const asse
|
||||||
return db.get_balance(account.get_id(), a.get_id()).amount.value;
|
return db.get_balance(account.get_id(), a.get_id()).amount.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector< operation_history_object > database_fixture::get_operation_history( account_id_type account_id )const
|
||||||
|
{
|
||||||
|
vector< operation_history_object > result;
|
||||||
|
const auto& stats = account_id(db).statistics(db);
|
||||||
|
if(stats.most_recent_op == account_transaction_history_id_type())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
const account_transaction_history_object* node = &stats.most_recent_op(db);
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
result.push_back( node->operation_id(db) );
|
||||||
|
if(node->next == account_transaction_history_id_type())
|
||||||
|
break;
|
||||||
|
node = db.find(node->next);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
void set_expiration( const database& db, transaction& tx )
|
void set_expiration( const database& db, transaction& tx )
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include <fc/io/json.hpp>
|
#include <fc/io/json.hpp>
|
||||||
#include <fc/smart_ref_impl.hpp>
|
#include <fc/smart_ref_impl.hpp>
|
||||||
|
|
||||||
|
#include <graphene/chain/operation_history_object.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace graphene::db;
|
using namespace graphene::db;
|
||||||
|
|
@ -278,6 +280,7 @@ struct database_fixture {
|
||||||
void print_joint_market( const string& syma, const string& symb )const;
|
void print_joint_market( const string& syma, const string& symb )const;
|
||||||
int64_t get_balance( account_id_type account, asset_id_type a )const;
|
int64_t get_balance( account_id_type account, asset_id_type a )const;
|
||||||
int64_t get_balance( const account_object& account, const asset_object& a )const;
|
int64_t get_balance( const account_object& account, const asset_object& a )const;
|
||||||
|
vector< operation_history_object > get_operation_history( account_id_type account_id )const;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,12 @@
|
||||||
|
|
||||||
#include <fc/smart_ref_impl.hpp>
|
#include <fc/smart_ref_impl.hpp>
|
||||||
#include <fc/uint128.hpp>
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
#include <graphene/chain/hardfork.hpp>
|
#include <graphene/chain/hardfork.hpp>
|
||||||
|
|
||||||
|
#include <graphene/chain/fba_accumulator_id.hpp>
|
||||||
|
|
||||||
|
#include <graphene/chain/fba_object.hpp>
|
||||||
#include <graphene/chain/market_object.hpp>
|
#include <graphene/chain/market_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
|
|
||||||
|
|
@ -721,4 +726,210 @@ BOOST_AUTO_TEST_CASE( fee_refund_test )
|
||||||
FC_LOG_AND_RETHROW()
|
FC_LOG_AND_RETHROW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( stealth_fba_test )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ACTORS( (alice)(bob)(chloe)(dan)(izzy)(philbin)(tom) );
|
||||||
|
upgrade_to_lifetime_member(philbin_id);
|
||||||
|
|
||||||
|
generate_blocks( HARDFORK_538_TIME );
|
||||||
|
generate_blocks( HARDFORK_555_TIME );
|
||||||
|
generate_blocks( HARDFORK_563_TIME );
|
||||||
|
generate_blocks( HARDFORK_572_TIME );
|
||||||
|
|
||||||
|
// Philbin (registrar who registers Rex)
|
||||||
|
|
||||||
|
// Izzy (initial issuer of stealth asset, will later transfer to Tom)
|
||||||
|
// Alice, Bob, Chloe, Dan (ABCD)
|
||||||
|
// Rex (recycler -- buyback account for stealth asset)
|
||||||
|
// Tom (owner of stealth asset who will be set as top_n authority)
|
||||||
|
|
||||||
|
// Izzy creates STEALTH
|
||||||
|
asset_id_type stealth_id = create_user_issued_asset( "STEALTH", izzy_id(db),
|
||||||
|
disable_confidential | transfer_restricted | override_authority | white_list | charge_market_fee ).id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// this is disabled because it doesn't work, our modify() is probably being overwritten by undo
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init blockchain with stealth ID's
|
||||||
|
// On a real chain, this would be done with #define GRAPHENE_FBA_STEALTH_DESIGNATED_ASSET
|
||||||
|
// causing the designated_asset fields of these objects to be set at genesis, but for
|
||||||
|
// this test we modify the db directly.
|
||||||
|
//
|
||||||
|
auto set_fba_asset = [&]( uint64_t fba_acc_id, asset_id_type asset_id )
|
||||||
|
{
|
||||||
|
db.modify( fba_accumulator_id_type(fba_acc_id)(db), [&]( fba_accumulator_object& fba )
|
||||||
|
{
|
||||||
|
fba.designated_asset = asset_id;
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
set_fba_asset( fba_accumulator_id_transfer_to_blind , stealth_id );
|
||||||
|
set_fba_asset( fba_accumulator_id_blind_transfer , stealth_id );
|
||||||
|
set_fba_asset( fba_accumulator_id_transfer_from_blind, stealth_id );
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Izzy kills some permission bits (this somehow happened to the real STEALTH in production)
|
||||||
|
{
|
||||||
|
asset_update_operation update_op;
|
||||||
|
update_op.issuer = izzy_id;
|
||||||
|
update_op.asset_to_update = stealth_id;
|
||||||
|
asset_options new_options;
|
||||||
|
new_options = stealth_id(db).options;
|
||||||
|
new_options.issuer_permissions = charge_market_fee;
|
||||||
|
new_options.flags = disable_confidential | transfer_restricted | override_authority | white_list | charge_market_fee;
|
||||||
|
// after fixing #579 you should be able to delete the following line
|
||||||
|
new_options.core_exchange_rate = price( asset( 1, stealth_id ), asset( 1, asset_id_type() ) );
|
||||||
|
update_op.new_options = new_options;
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( update_op );
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, izzy_private_key );
|
||||||
|
PUSH_TX( db, tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Izzy transfers issuer duty to Tom
|
||||||
|
{
|
||||||
|
asset_update_operation update_op;
|
||||||
|
update_op.issuer = izzy_id;
|
||||||
|
update_op.asset_to_update = stealth_id;
|
||||||
|
update_op.new_issuer = tom_id;
|
||||||
|
// new_options should be optional, but isn't...the following line should be unnecessary #580
|
||||||
|
update_op.new_options = stealth_id(db).options;
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( update_op );
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, izzy_private_key );
|
||||||
|
PUSH_TX( db, tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tom re-enables the permission bits to clear the flags, then clears them again
|
||||||
|
// Allowed by #572 when current_supply == 0
|
||||||
|
{
|
||||||
|
asset_update_operation update_op;
|
||||||
|
update_op.issuer = tom_id;
|
||||||
|
update_op.asset_to_update = stealth_id;
|
||||||
|
asset_options new_options;
|
||||||
|
new_options = stealth_id(db).options;
|
||||||
|
new_options.issuer_permissions = new_options.flags | charge_market_fee;
|
||||||
|
update_op.new_options = new_options;
|
||||||
|
signed_transaction tx;
|
||||||
|
// enable perms is one op
|
||||||
|
tx.operations.push_back( update_op );
|
||||||
|
|
||||||
|
new_options.issuer_permissions = charge_market_fee;
|
||||||
|
new_options.flags = charge_market_fee;
|
||||||
|
update_op.new_options = new_options;
|
||||||
|
// reset wrongly set flags and reset permissions can be done in a single op
|
||||||
|
tx.operations.push_back( update_op );
|
||||||
|
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, tom_private_key );
|
||||||
|
PUSH_TX( db, tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Philbin registers Rex who will be the asset's buyback, including sig from the new issuer (Tom)
|
||||||
|
account_id_type rex_id;
|
||||||
|
{
|
||||||
|
buyback_account_options bbo;
|
||||||
|
bbo.asset_to_buy = stealth_id;
|
||||||
|
bbo.asset_to_buy_issuer = tom_id;
|
||||||
|
bbo.markets.emplace( asset_id_type() );
|
||||||
|
account_create_operation create_op = make_account( "rex" );
|
||||||
|
create_op.registrar = philbin_id;
|
||||||
|
create_op.extensions.value.buyback_options = bbo;
|
||||||
|
create_op.owner = authority::null_authority();
|
||||||
|
create_op.active = authority::null_authority();
|
||||||
|
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( create_op );
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, philbin_private_key );
|
||||||
|
sign( tx, tom_private_key );
|
||||||
|
|
||||||
|
processed_transaction ptx = PUSH_TX( db, tx );
|
||||||
|
rex_id = ptx.operation_results.back().get< object_id_type >();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tom issues some asset to Alice and Bob
|
||||||
|
set_expiration( db, trx ); // #11
|
||||||
|
issue_uia( alice_id, asset( 1000, stealth_id ) );
|
||||||
|
issue_uia( bob_id, asset( 1000, stealth_id ) );
|
||||||
|
|
||||||
|
// Tom sets his authority to the top_n of the asset
|
||||||
|
{
|
||||||
|
top_holders_special_authority top2;
|
||||||
|
top2.num_top_holders = 2;
|
||||||
|
top2.asset = stealth_id;
|
||||||
|
|
||||||
|
account_update_operation op;
|
||||||
|
op.account = tom_id;
|
||||||
|
op.extensions.value.active_special_authority = top2;
|
||||||
|
op.extensions.value.owner_special_authority = top2;
|
||||||
|
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( op );
|
||||||
|
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, tom_private_key );
|
||||||
|
|
||||||
|
PUSH_TX( db, tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the next maintenance interval for top_n to take effect
|
||||||
|
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||||
|
|
||||||
|
// Do a blind op to add some fees to the pool.
|
||||||
|
fund( chloe_id(db), asset( 100000, asset_id_type() ) );
|
||||||
|
|
||||||
|
auto create_transfer_to_blind = [&]( account_id_type account, asset amount, const std::string& key ) -> transfer_to_blind_operation
|
||||||
|
{
|
||||||
|
fc::ecc::private_key blind_key = fc::ecc::private_key::regenerate( fc::sha256::hash( key+"-privkey" ) );
|
||||||
|
public_key_type blind_pub = blind_key.get_public_key();
|
||||||
|
|
||||||
|
fc::sha256 secret = fc::sha256::hash( key+"-secret" );
|
||||||
|
fc::sha256 nonce = fc::sha256::hash( key+"-nonce" );
|
||||||
|
|
||||||
|
transfer_to_blind_operation op;
|
||||||
|
blind_output blind_out;
|
||||||
|
blind_out.owner = authority( 1, blind_pub, 1 );
|
||||||
|
blind_out.commitment = fc::ecc::blind( secret, amount.amount.value );
|
||||||
|
blind_out.range_proof = fc::ecc::range_proof_sign( 0, blind_out.commitment, secret, nonce, 0, 0, amount.amount.value );
|
||||||
|
|
||||||
|
op.amount = amount;
|
||||||
|
op.from = account;
|
||||||
|
op.blinding_factor = fc::ecc::blind_sum( {secret}, 1 );
|
||||||
|
op.outputs = {blind_out};
|
||||||
|
|
||||||
|
return op;
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
transfer_to_blind_operation op = create_transfer_to_blind( chloe_id, asset( 5000, asset_id_type() ), "chloe-key" );
|
||||||
|
op.fee = asset( 1000, asset_id_type() );
|
||||||
|
|
||||||
|
signed_transaction tx;
|
||||||
|
tx.operations.push_back( op );
|
||||||
|
set_expiration( db, tx );
|
||||||
|
sign( tx, chloe_private_key );
|
||||||
|
|
||||||
|
PUSH_TX( db, tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until next maint interval
|
||||||
|
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||||
|
|
||||||
|
idump( ( get_operation_history( chloe_id ) ) );
|
||||||
|
idump( ( get_operation_history( rex_id ) ) );
|
||||||
|
idump( ( get_operation_history( tom_id ) ) );
|
||||||
|
}
|
||||||
|
catch( const fc::exception& e )
|
||||||
|
{
|
||||||
|
elog( "caught exception ${e}", ("e", e.to_detail_string()) );
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue