* Resolve #210: [HF] Check authorities on custom_operation The required_auths field on custom_operation was being ignored during authority checking. This commit causes it to be checked correctly, and adds a unit test verifying as much. * Ref #381: Fixes Build and logic fixes for Pull Request #381 * Ref #381: Fix bad merge During merge conflict resolution, I accidentally broke custom authorities. This fixes it. * compilation fix Co-authored-by: Nathan Hourt <nathan@followmyvote.com>
This commit is contained in:
parent
adb22299d9
commit
c46e899cf4
14 changed files with 164 additions and 87 deletions
|
|
@ -789,12 +789,14 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
|||
|
||||
if( !(skip & (skip_transaction_signatures | skip_authority_check) ) )
|
||||
{
|
||||
auto get_active = [&]( account_id_type id ) { return &id(*this).active; };
|
||||
auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; };
|
||||
auto get_custom = [&]( account_id_type id, const operation& op ) {
|
||||
auto get_active = [this]( account_id_type id ) { return &id(*this).active; };
|
||||
auto get_owner = [this]( account_id_type id ) { return &id(*this).owner; };
|
||||
auto get_custom = [this]( account_id_type id, const operation& op ) {
|
||||
return get_account_custom_authorities(id, op);
|
||||
};
|
||||
trx.verify_authority( chain_id, get_active, get_owner, get_custom, get_global_properties().parameters.max_authority_depth );
|
||||
trx.verify_authority( chain_id, get_active, get_owner, get_custom,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()),
|
||||
get_global_properties().parameters.max_authority_depth );
|
||||
}
|
||||
|
||||
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
#include <graphene/chain/transaction_object.hpp>
|
||||
#include <graphene/chain/impacted.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
|
||||
using namespace fc;
|
||||
|
|
@ -49,8 +50,13 @@ using namespace graphene::chain;
|
|||
struct get_impacted_account_visitor
|
||||
{
|
||||
flat_set<account_id_type>& _impacted;
|
||||
get_impacted_account_visitor( flat_set<account_id_type>& impact ):_impacted(impact) {}
|
||||
typedef void result_type;
|
||||
bool _ignore_custom_op_reqd_auths;
|
||||
|
||||
get_impacted_account_visitor( flat_set<account_id_type>& impact, bool ignore_custom_operation_required_auths )
|
||||
: _impacted( impact ), _ignore_custom_op_reqd_auths( ignore_custom_operation_required_auths )
|
||||
{}
|
||||
|
||||
using result_type = void;
|
||||
|
||||
void operator()( const transfer_operation& op )
|
||||
{
|
||||
|
|
@ -136,7 +142,7 @@ struct get_impacted_account_visitor
|
|||
{
|
||||
vector<authority> other;
|
||||
for( const auto& proposed_op : op.proposed_ops )
|
||||
operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other );
|
||||
operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other, _ignore_custom_op_reqd_auths );
|
||||
for( auto& o : other )
|
||||
add_authority_accounts( _impacted, o );
|
||||
}
|
||||
|
|
@ -346,20 +352,17 @@ struct get_impacted_account_visitor
|
|||
}
|
||||
};
|
||||
|
||||
void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
{
|
||||
get_impacted_account_visitor vtor = get_impacted_account_visitor( result );
|
||||
void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result, bool ignore_custom_operation_required_auths ) {
|
||||
get_impacted_account_visitor vtor = get_impacted_account_visitor( result, ignore_custom_operation_required_auths );
|
||||
op.visit( vtor );
|
||||
}
|
||||
|
||||
void graphene::chain::transaction_get_impacted_accounts( const transaction& tx, flat_set<account_id_type>& result )
|
||||
{
|
||||
void graphene::chain::transaction_get_impacted_accounts( const transaction& tx, flat_set<account_id_type>& result, bool ignore_custom_operation_required_auths ) {
|
||||
for( const auto& op : tx.operations )
|
||||
operation_get_impacted_accounts( op, result );
|
||||
operation_get_impacted_accounts( op, result, ignore_custom_operation_required_auths );
|
||||
}
|
||||
|
||||
void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accounts )
|
||||
{
|
||||
void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accounts, bool ignore_custom_operation_required_auths ) {
|
||||
if( obj->id.space() == protocol_ids )
|
||||
{
|
||||
switch( (object_type)obj->id.type() )
|
||||
|
|
@ -406,12 +409,14 @@ void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accoun
|
|||
} case proposal_object_type:{
|
||||
const auto& aobj = dynamic_cast<const proposal_object*>(obj);
|
||||
assert( aobj != nullptr );
|
||||
transaction_get_impacted_accounts( aobj->proposed_transaction, accounts );
|
||||
transaction_get_impacted_accounts( aobj->proposed_transaction, accounts,
|
||||
ignore_custom_operation_required_auths);
|
||||
break;
|
||||
} case operation_history_object_type:{
|
||||
const auto& aobj = dynamic_cast<const operation_history_object*>(obj);
|
||||
assert( aobj != nullptr );
|
||||
operation_get_impacted_accounts( aobj->op, accounts );
|
||||
operation_get_impacted_accounts( aobj->op, accounts,
|
||||
ignore_custom_operation_required_auths);
|
||||
break;
|
||||
} case withdraw_permission_object_type:{
|
||||
const auto& aobj = dynamic_cast<const withdraw_permission_object*>(obj);
|
||||
|
|
@ -462,7 +467,8 @@ void get_relevant_accounts( const object* obj, flat_set<account_id_type>& accoun
|
|||
} case impl_transaction_object_type:{
|
||||
const auto& aobj = dynamic_cast<const transaction_object*>(obj);
|
||||
assert( aobj != nullptr );
|
||||
transaction_get_impacted_accounts( aobj->trx, accounts );
|
||||
transaction_get_impacted_accounts( aobj->trx, accounts,
|
||||
ignore_custom_operation_required_auths);
|
||||
break;
|
||||
} case impl_blinded_balance_object_type:{
|
||||
const auto& aobj = dynamic_cast<const blinded_balance_object*>(obj);
|
||||
|
|
@ -507,6 +513,7 @@ void database::notify_changed_objects()
|
|||
if( _undo_db.enabled() )
|
||||
{
|
||||
const auto& head_undo = _undo_db.head();
|
||||
auto chain_time = head_block_time();
|
||||
|
||||
// New
|
||||
if( !new_objects.empty() )
|
||||
|
|
@ -518,7 +525,8 @@ void database::notify_changed_objects()
|
|||
new_ids.push_back(item);
|
||||
auto obj = find_object(item);
|
||||
if(obj != nullptr)
|
||||
get_relevant_accounts(obj, new_accounts_impacted);
|
||||
get_relevant_accounts(obj, new_accounts_impacted,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time));
|
||||
}
|
||||
|
||||
GRAPHENE_TRY_NOTIFY( new_objects, new_ids, new_accounts_impacted)
|
||||
|
|
@ -532,7 +540,8 @@ void database::notify_changed_objects()
|
|||
for( const auto& item : head_undo.old_values )
|
||||
{
|
||||
changed_ids.push_back(item.first);
|
||||
get_relevant_accounts(item.second.get(), changed_accounts_impacted);
|
||||
get_relevant_accounts(item.second.get(), changed_accounts_impacted,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time));
|
||||
}
|
||||
|
||||
GRAPHENE_TRY_NOTIFY( changed_objects, changed_ids, changed_accounts_impacted)
|
||||
|
|
@ -549,7 +558,8 @@ void database::notify_changed_objects()
|
|||
removed_ids.emplace_back( item.first );
|
||||
auto obj = item.second.get();
|
||||
removed.emplace_back( obj );
|
||||
get_relevant_accounts(obj, removed_accounts_impacted);
|
||||
get_relevant_accounts(obj, removed_accounts_impacted,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time));
|
||||
}
|
||||
|
||||
GRAPHENE_TRY_NOTIFY( removed_objects, removed_ids, removed, removed_accounts_impacted)
|
||||
|
|
|
|||
6
libraries/chain/hardfork.d/CORE_210.hf
Normal file
6
libraries/chain/hardfork.d/CORE_210.hf
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// #210 Check authorities on custom_operation
|
||||
#ifndef HARDFORK_CORE_210_TIME
|
||||
#define HARDFORK_CORE_210_TIME (fc::time_point_sec(1893456000)) // Jan 1 00:00:00 2030 (Not yet scheduled)
|
||||
// Bugfix: pre-HF 210, custom_operation's required_auths field was ignored.
|
||||
#define MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time) (chain_time <= HARDFORK_CORE_210_TIME)
|
||||
#endif
|
||||
|
|
@ -30,13 +30,12 @@
|
|||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void operation_get_impacted_accounts(
|
||||
const graphene::chain::operation& op,
|
||||
fc::flat_set<graphene::chain::account_id_type>& result );
|
||||
void operation_get_impacted_accounts( const graphene::chain::operation& op,
|
||||
fc::flat_set<graphene::chain::account_id_type>& result,
|
||||
bool ignore_custom_operation_required_auths );
|
||||
|
||||
void transaction_get_impacted_accounts(
|
||||
const graphene::chain::transaction& tx,
|
||||
fc::flat_set<graphene::chain::account_id_type>& result
|
||||
);
|
||||
void transaction_get_impacted_accounts( const graphene::chain::transaction& tx,
|
||||
fc::flat_set<graphene::chain::account_id_type>& result,
|
||||
bool ignore_custom_operation_required_auths );
|
||||
|
||||
} } // graphene::app
|
||||
} } // graphene::app
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ namespace graphene { namespace chain {
|
|||
account_id_type fee_payer()const { return payer; }
|
||||
void validate()const;
|
||||
share_type calculate_fee(const fee_parameters_type& k)const;
|
||||
void get_required_active_authorities( flat_set<account_id_type>& auths )const {
|
||||
auths.insert( required_auths.begin(), required_auths.end() );
|
||||
}
|
||||
};
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
|
|
|||
|
|
@ -166,10 +166,11 @@ namespace graphene { namespace chain {
|
|||
*
|
||||
* @return a set of required authorities for @ref op
|
||||
*/
|
||||
void operation_get_required_authorities( const operation& op,
|
||||
void operation_get_required_authorities( const operation& op,
|
||||
flat_set<account_id_type>& active,
|
||||
flat_set<account_id_type>& owner,
|
||||
vector<authority>& other );
|
||||
vector<authority>& other,
|
||||
bool ignore_custom_operation_required_auths );
|
||||
|
||||
void operation_validate( const operation& op );
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,10 @@ namespace graphene { namespace chain {
|
|||
return results;
|
||||
}
|
||||
|
||||
void get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const;
|
||||
void get_required_authorities( flat_set<account_id_type>& active,
|
||||
flat_set<account_id_type>& owner,
|
||||
vector<authority>& other,
|
||||
bool ignore_custom_operation_required_auths )const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -142,6 +145,7 @@ namespace graphene { namespace chain {
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_authorities,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
)const;
|
||||
|
||||
|
|
@ -150,6 +154,7 @@ namespace graphene { namespace chain {
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;
|
||||
|
||||
/**
|
||||
|
|
@ -158,13 +163,13 @@ namespace graphene { namespace chain {
|
|||
* some cases where get_required_signatures() returns a
|
||||
* non-minimal set.
|
||||
*/
|
||||
|
||||
set<public_key_type> minimize_required_signatures(
|
||||
const chain_id_type& chain_id,
|
||||
const flat_set<public_key_type>& available_keys,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
) const;
|
||||
|
||||
|
|
@ -198,10 +203,11 @@ namespace graphene { namespace chain {
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH,
|
||||
bool allow_committe = false,
|
||||
bool allow_committee = false,
|
||||
const flat_set<account_id_type>& active_aprovals = flat_set<account_id_type>(),
|
||||
const flat_set<account_id_type>& owner_approvals = flat_set<account_id_type>());
|
||||
const flat_set<account_id_type>& owner_approvals = flat_set<account_id_type>() );
|
||||
|
||||
/**
|
||||
* @brief captures the result of evaluating the operations contained in the transaction
|
||||
|
|
|
|||
|
|
@ -204,19 +204,20 @@ struct proposal_operation_hardfork_visitor
|
|||
}
|
||||
};
|
||||
|
||||
void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o)
|
||||
void_result proposal_create_evaluator::do_evaluate( const proposal_create_operation& o )
|
||||
{ try {
|
||||
const database& d = db();
|
||||
auto block_time = d.head_block_time();
|
||||
|
||||
proposal_operation_hardfork_visitor vtor( d.head_block_time() );
|
||||
proposal_operation_hardfork_visitor vtor( block_time );
|
||||
vtor( o );
|
||||
|
||||
const auto& global_parameters = d.get_global_properties().parameters;
|
||||
|
||||
FC_ASSERT( o.expiration_time > d.head_block_time(), "Proposal has already expired on creation." );
|
||||
FC_ASSERT( o.expiration_time <= d.head_block_time() + global_parameters.maximum_proposal_lifetime,
|
||||
FC_ASSERT( o.expiration_time > block_time, "Proposal has already expired on creation." );
|
||||
FC_ASSERT( o.expiration_time <= block_time + global_parameters.maximum_proposal_lifetime,
|
||||
"Proposal expiration time is too far in the future.");
|
||||
FC_ASSERT( !o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - d.head_block_time()),
|
||||
FC_ASSERT( !o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - block_time),
|
||||
"Proposal review period must be less than its overall lifetime." );
|
||||
|
||||
{
|
||||
|
|
@ -225,7 +226,8 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati
|
|||
vector<authority> other;
|
||||
for( auto& op : o.proposed_ops )
|
||||
{
|
||||
operation_get_required_authorities(op.op, auths, auths, other);
|
||||
operation_get_required_authorities( op.op, auths, auths, other,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(block_time) );
|
||||
}
|
||||
|
||||
FC_ASSERT( other.size() == 0 ); // TODO: what about other???
|
||||
|
|
@ -248,18 +250,19 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati
|
|||
}
|
||||
}
|
||||
|
||||
for( const op_wrapper& op : o.proposed_ops )
|
||||
for (const op_wrapper& op : o.proposed_ops)
|
||||
_proposed_trx.operations.push_back(op.op);
|
||||
_proposed_trx.validate();
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
object_id_type proposal_create_evaluator::do_apply(const proposal_create_operation& o)
|
||||
object_id_type proposal_create_evaluator::do_apply( const proposal_create_operation& o )
|
||||
{ try {
|
||||
database& d = db();
|
||||
auto chain_time = d.head_block_time();
|
||||
|
||||
const proposal_object& proposal = d.create<proposal_object>([&](proposal_object& proposal) {
|
||||
const proposal_object& proposal = d.create<proposal_object>( [&o, this, chain_time](proposal_object& proposal) {
|
||||
_proposed_trx.expiration = o.expiration_time;
|
||||
proposal.proposed_transaction = _proposed_trx;
|
||||
proposal.proposer = o.fee_paying_account;
|
||||
|
|
@ -273,7 +276,8 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
|
|||
|
||||
// TODO: consider caching values from evaluate?
|
||||
for( auto& op : _proposed_trx.operations )
|
||||
operation_get_required_authorities(op, required_active, proposal.required_owner_approvals, other);
|
||||
operation_get_required_authorities( op, required_active, proposal.required_owner_approvals, other,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time) );
|
||||
|
||||
//All accounts which must provide both owner and active authority should be omitted from the active authority set;
|
||||
//owner authority approval implies active authority approval.
|
||||
|
|
@ -285,7 +289,7 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati
|
|||
return proposal.id;
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
void_result proposal_update_evaluator::do_evaluate(const proposal_update_operation& o)
|
||||
void_result proposal_update_evaluator::do_evaluate( const proposal_update_operation& o )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,13 @@
|
|||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
bool proposal_object::is_authorized_to_execute(database& db) const
|
||||
bool proposal_object::is_authorized_to_execute( database& db ) const
|
||||
{
|
||||
transaction_evaluation_state dry_run_eval(&db);
|
||||
transaction_evaluation_state dry_run_eval( &db );
|
||||
|
||||
try {
|
||||
verify_authority( proposed_transaction.operations,
|
||||
|
|
@ -38,6 +39,7 @@ bool proposal_object::is_authorized_to_execute(database& db) const
|
|||
[&]( account_id_type id ){ return &id(db).owner; },
|
||||
[&]( account_id_type id, const operation& op ){
|
||||
return db.get_account_custom_authorities(id, op); },
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ),
|
||||
db.get_global_properties().parameters.max_authority_depth,
|
||||
true, /* allow committee */
|
||||
available_active_approvals,
|
||||
|
|
|
|||
|
|
@ -53,25 +53,38 @@ struct operation_validator
|
|||
|
||||
struct operation_get_required_auth
|
||||
{
|
||||
typedef void result_type;
|
||||
using result_type = void;
|
||||
|
||||
flat_set<account_id_type>& active;
|
||||
flat_set<account_id_type>& owner;
|
||||
vector<authority>& other;
|
||||
bool ignore_custom_op_reqd_auths;
|
||||
|
||||
|
||||
operation_get_required_auth( flat_set<account_id_type>& a,
|
||||
flat_set<account_id_type>& own,
|
||||
vector<authority>& oth ):active(a),owner(own),other(oth){}
|
||||
flat_set<account_id_type>& own,
|
||||
vector<authority>& oth,
|
||||
bool ignore_custom_operation_required_auths )
|
||||
: active( a ), owner( own ), other( oth ),
|
||||
ignore_custom_op_reqd_auths( ignore_custom_operation_required_auths )
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
void operator()( const T& v )const
|
||||
{
|
||||
void operator()( const T& v ) const {
|
||||
active.insert( v.fee_payer() );
|
||||
v.get_required_active_authorities( active );
|
||||
v.get_required_owner_authorities( owner );
|
||||
v.get_required_active_authorities( active );
|
||||
v.get_required_owner_authorities( owner );
|
||||
v.get_required_authorities( other );
|
||||
}
|
||||
|
||||
void operator()( const custom_operation& op ) const {
|
||||
active.insert( op.fee_payer() );
|
||||
if( !ignore_custom_op_reqd_auths ) {
|
||||
op.get_required_active_authorities( active );
|
||||
op.get_required_owner_authorities( owner );
|
||||
op.get_required_authorities( other );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void operation_validate( const operation& op )
|
||||
|
|
@ -79,12 +92,13 @@ void operation_validate( const operation& op )
|
|||
op.visit( operation_validator() );
|
||||
}
|
||||
|
||||
void operation_get_required_authorities( const operation& op,
|
||||
void operation_get_required_authorities( const operation& op,
|
||||
flat_set<account_id_type>& active,
|
||||
flat_set<account_id_type>& owner,
|
||||
vector<authority>& other )
|
||||
vector<authority>& other,
|
||||
bool ignore_custom_operation_required_auths )
|
||||
{
|
||||
op.visit( operation_get_required_auth( active, owner, other ) );
|
||||
op.visit( operation_get_required_auth( active, owner, other, ignore_custom_operation_required_auths ) );
|
||||
}
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
|
|
|||
|
|
@ -95,10 +95,13 @@ void transaction::set_reference_block( const block_id_type& reference_block )
|
|||
ref_block_prefix = reference_block._hash[1];
|
||||
}
|
||||
|
||||
void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
|
||||
void transaction::get_required_authorities( flat_set<account_id_type>& active,
|
||||
flat_set<account_id_type>& owner,
|
||||
vector<authority>& other,
|
||||
bool ignore_custom_operation_required_auths )const
|
||||
{
|
||||
for( const auto& op : operations )
|
||||
operation_get_required_authorities( op, active, owner, other );
|
||||
for ( const auto& op : operations )
|
||||
operation_get_required_authorities( op, active, owner, other, ignore_custom_operation_required_auths );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -249,8 +252,9 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion_depth,
|
||||
bool allow_committe,
|
||||
bool allow_committee,
|
||||
const flat_set<account_id_type>& active_aprovals,
|
||||
const flat_set<account_id_type>& owner_approvals )
|
||||
{ try {
|
||||
|
|
@ -276,7 +280,8 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
|
||||
for( const auto& op : ops ) {
|
||||
flat_set<account_id_type> operation_required_active;
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other );
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other,
|
||||
ignore_custom_operation_required_auths );
|
||||
|
||||
auto itr = operation_required_active.begin();
|
||||
while ( itr != operation_required_active.end() ) {
|
||||
|
|
@ -289,7 +294,7 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
required_active.insert( operation_required_active.begin(), operation_required_active.end() );
|
||||
}
|
||||
|
||||
if( !allow_committe )
|
||||
if( !allow_committee )
|
||||
GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
|
||||
invalid_committee_approval, "Committee account may only propose transactions" );
|
||||
|
||||
|
|
@ -349,6 +354,7 @@ set<public_key_type> signed_transaction::get_required_signatures(
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_authorities,
|
||||
uint32_t max_recursion_depth )const
|
||||
{
|
||||
flat_set<account_id_type> required_active;
|
||||
|
|
@ -370,7 +376,7 @@ set<public_key_type> signed_transaction::get_required_signatures(
|
|||
|
||||
for( const auto& op : operations ) {
|
||||
flat_set<account_id_type> operation_required_active;
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other );
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other, ignore_custom_operation_required_authorities );
|
||||
|
||||
auto itr = operation_required_active.begin();
|
||||
while ( itr != operation_required_active.end() ) {
|
||||
|
|
@ -383,7 +389,7 @@ set<public_key_type> signed_transaction::get_required_signatures(
|
|||
required_active.insert( operation_required_active.begin(), operation_required_active.end() );
|
||||
}
|
||||
|
||||
for( const auto& auth : other )
|
||||
for (const auto& auth : other)
|
||||
s.check_authority(&auth);
|
||||
for( auto& owner : required_owner )
|
||||
s.check_authority( get_owner( owner ) );
|
||||
|
|
@ -407,10 +413,12 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion
|
||||
) const
|
||||
{
|
||||
set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, get_custom, max_recursion );
|
||||
set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, get_custom,
|
||||
ignore_custom_operation_required_auths, max_recursion );
|
||||
flat_set< public_key_type > result( s.begin(), s.end() );
|
||||
|
||||
for( const public_key_type& k : s )
|
||||
|
|
@ -418,7 +426,8 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
|
|||
result.erase( k );
|
||||
try
|
||||
{
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, get_custom, max_recursion );
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, get_custom,
|
||||
ignore_custom_operation_required_auths, max_recursion );
|
||||
continue; // element stays erased if verify_authority is ok
|
||||
}
|
||||
catch( const tx_missing_owner_auth& e ) {}
|
||||
|
|
@ -434,6 +443,7 @@ void signed_transaction::verify_authority(
|
|||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
bool ignore_custom_operation_required_auths,
|
||||
uint32_t max_recursion )const
|
||||
{ try {
|
||||
graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, get_custom, max_recursion );
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
|
@ -123,12 +124,15 @@ void account_history_plugin_impl::update_account_histories( const signed_block&
|
|||
// get the set of accounts this operation applies to
|
||||
flat_set<account_id_type> impacted;
|
||||
vector<authority> other;
|
||||
operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here
|
||||
// fee payer is added here
|
||||
operation_get_required_authorities( op.op, impacted, impacted, other,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) );
|
||||
|
||||
if( op.op.which() == operation::tag< account_create_operation >::value )
|
||||
impacted.insert( op.result.get<object_id_type>() );
|
||||
else
|
||||
graphene::chain::operation_get_impacted_accounts( op.op, impacted );
|
||||
graphene::chain::operation_get_impacted_accounts( op.op, impacted,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time()) );
|
||||
if( op.op.which() == operation::tag< lottery_end_operation >::value )
|
||||
{
|
||||
auto lop = op.op.get< lottery_end_operation >();
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <graphene/elasticsearch/elasticsearch_plugin.hpp>
|
||||
#include <graphene/chain/impacted.hpp>
|
||||
#include <graphene/chain/account_evaluator.hpp>
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace graphene { namespace elasticsearch {
|
||||
|
|
@ -157,12 +157,15 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b
|
|||
// get the set of accounts this operation applies to
|
||||
flat_set<account_id_type> impacted;
|
||||
vector<authority> other;
|
||||
operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here
|
||||
// fee_payer is added here
|
||||
operation_get_required_authorities( op.op, impacted, impacted, other,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) );
|
||||
|
||||
if( op.op.which() == operation::tag< account_create_operation >::value )
|
||||
impacted.insert( op.result.get<object_id_type>() );
|
||||
else
|
||||
graphene::chain::operation_get_impacted_accounts( op.op, impacted );
|
||||
operation_get_impacted_accounts( op.op, impacted,
|
||||
MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) );
|
||||
|
||||
for( auto& a : other )
|
||||
for( auto& item : a.account_auths )
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE( proposed_single_account )
|
|||
{
|
||||
vector<authority> other;
|
||||
flat_set<account_id_type> active_set, owner_set;
|
||||
operation_get_required_authorities(op,active_set,owner_set,other);
|
||||
operation_get_required_authorities(op, active_set, owner_set, other, false);
|
||||
BOOST_CHECK_EQUAL(active_set.size(), 1lu);
|
||||
BOOST_CHECK_EQUAL(owner_set.size(), 0lu);
|
||||
BOOST_CHECK_EQUAL(other.size(), 0lu);
|
||||
|
|
@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE( proposed_single_account )
|
|||
|
||||
active_set.clear();
|
||||
other.clear();
|
||||
operation_get_required_authorities(op.proposed_ops.front().op,active_set,owner_set,other);
|
||||
operation_get_required_authorities(op.proposed_ops.front().op, active_set, owner_set, other, false);
|
||||
BOOST_CHECK_EQUAL(active_set.size(), 1lu);
|
||||
BOOST_CHECK_EQUAL(owner_set.size(), 0lu);
|
||||
BOOST_CHECK_EQUAL(other.size(), 0lu);
|
||||
|
|
@ -1055,7 +1055,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
|
|||
|
||||
flat_set<account_id_type> active_set, owner_set;
|
||||
vector<authority> others;
|
||||
trx.get_required_authorities( active_set, owner_set, others );
|
||||
trx.get_required_authorities(active_set, owner_set, others, false);
|
||||
|
||||
PUSH_TX( db, trx, skip );
|
||||
|
||||
|
|
@ -1204,9 +1204,12 @@ BOOST_FIXTURE_TEST_CASE( get_required_signatures_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.get_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, false);
|
||||
set<public_key_type> result_set2 = tx.get_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, true);
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
set_auth( well_id, authority( 60, alice_id, 50, bob_id, 50 ) );
|
||||
|
|
@ -1326,9 +1329,12 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.get_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, false);
|
||||
set<public_key_type> result_set2 = tx.get_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, true);
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
auto chk_min = [&](
|
||||
|
|
@ -1338,9 +1344,12 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, false);
|
||||
set<public_key_type> result_set2 = tx.minimize_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, get_custom, true);
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
set_auth( roco_id, authority( 2, styx_id, 1, thud_id, 2 ) );
|
||||
|
|
@ -1357,9 +1366,13 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
BOOST_CHECK( chk( tx, { alice_public_key, bob_public_key }, { alice_public_key, bob_public_key } ) );
|
||||
BOOST_CHECK( chk_min( tx, { alice_public_key, bob_public_key }, { alice_public_key } ) );
|
||||
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom ), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom, false ),
|
||||
fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom, true ),
|
||||
fc::exception );
|
||||
sign( tx, alice_private_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom, false );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom, true );
|
||||
}
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue