Refactor Authority Checking
transaction_evaluation_state no longer tracks authority validation. Authority validation is now compeltely independent of the database.
This commit is contained in:
parent
b08b6cb553
commit
8c6e0b9e55
8 changed files with 34 additions and 75 deletions
|
|
@ -43,7 +43,6 @@ add_library( graphene_chain
|
||||||
proposal_object.cpp
|
proposal_object.cpp
|
||||||
vesting_balance_object.cpp
|
vesting_balance_object.cpp
|
||||||
|
|
||||||
transaction_evaluation_state.cpp
|
|
||||||
fork_database.cpp
|
fork_database.cpp
|
||||||
block_database.cpp
|
block_database.cpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,22 +215,6 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
|
||||||
transaction_evaluation_state eval_state(this);
|
transaction_evaluation_state eval_state(this);
|
||||||
eval_state._is_proposed_trx = true;
|
eval_state._is_proposed_trx = true;
|
||||||
|
|
||||||
//Inject the approving authorities into the transaction eval state
|
|
||||||
/*
|
|
||||||
std::transform(proposal.required_active_approvals.begin(),
|
|
||||||
proposal.required_active_approvals.end(),
|
|
||||||
std::inserter(eval_state.approved_by, eval_state.approved_by.begin()),
|
|
||||||
[]( account_id_type id ) {
|
|
||||||
return std::make_pair(id, authority::active);
|
|
||||||
});
|
|
||||||
std::transform(proposal.required_owner_approvals.begin(),
|
|
||||||
proposal.required_owner_approvals.end(),
|
|
||||||
std::inserter(eval_state.approved_by, eval_state.approved_by.begin()),
|
|
||||||
[]( account_id_type id ) {
|
|
||||||
return std::make_pair(id, authority::owner);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
|
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
|
||||||
processed_transaction ptrx(proposal.proposed_transaction);
|
processed_transaction ptrx(proposal.proposed_transaction);
|
||||||
eval_state._trx = &ptrx;
|
eval_state._trx = &ptrx;
|
||||||
|
|
@ -489,17 +473,6 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
||||||
auto get_active = [&]( account_id_type id ) { return &id(*this).active; };
|
auto get_active = [&]( account_id_type id ) { return &id(*this).active; };
|
||||||
auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; };
|
auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; };
|
||||||
trx.verify_authority( get_active, get_owner );
|
trx.verify_authority( get_active, get_owner );
|
||||||
|
|
||||||
/*
|
|
||||||
eval_state._sigs.reserve(trx.signatures.size());
|
|
||||||
|
|
||||||
for( const auto& sig : trx.signatures )
|
|
||||||
{
|
|
||||||
FC_ASSERT( eval_state._sigs.insert(std::make_pair(public_key_type(fc::ecc::public_key(sig, trx.digest())),
|
|
||||||
false)).second,
|
|
||||||
"Multiple signatures by same key detected" );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
||||||
|
|
@ -545,17 +518,6 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
||||||
auto range = index.equal_range(GRAPHENE_TEMP_ACCOUNT);
|
auto range = index.equal_range(GRAPHENE_TEMP_ACCOUNT);
|
||||||
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
|
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
|
||||||
|
|
||||||
//Make sure all signatures were needed to validate the transaction
|
|
||||||
/*
|
|
||||||
if( !(skip & (skip_transaction_signatures|skip_authority_check)) )
|
|
||||||
{
|
|
||||||
for( const auto& item : eval_state._sigs )
|
|
||||||
{
|
|
||||||
FC_ASSERT( item.second, "All signatures must be used", ("item",item) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return ptrx;
|
return ptrx;
|
||||||
} FC_CAPTURE_AND_RETHROW( (trx) ) }
|
} FC_CAPTURE_AND_RETHROW( (trx) ) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,9 @@ namespace graphene { namespace chain {
|
||||||
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, graphene::chain::transaction_exception, 3030001, "missing required active authority" )
|
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, graphene::chain::transaction_exception, 3030001, "missing required active authority" )
|
||||||
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, graphene::chain::transaction_exception, 3030002, "missing required owner authority" )
|
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, graphene::chain::transaction_exception, 3030002, "missing required owner authority" )
|
||||||
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_other_auth, graphene::chain::transaction_exception, 3030003, "missing required other authority" )
|
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_other_auth, graphene::chain::transaction_exception, 3030003, "missing required other authority" )
|
||||||
//FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_authority, graphene::chain::transaction_exception, 3030004, "irrelevant authority" )
|
FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_authority, graphene::chain::transaction_exception, 3030004, "irrelevant authority" )
|
||||||
|
FC_DECLARE_DERIVED_EXCEPTION( invalid_committee_approval, graphene::chain::transaction_exception, 3030005,
|
||||||
|
"committee account cannot directly approve transaction" )
|
||||||
|
|
||||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" )
|
FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" )
|
||||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" )
|
FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" )
|
||||||
|
|
|
||||||
|
|
@ -122,11 +122,13 @@ namespace graphene { namespace chain {
|
||||||
*/
|
*/
|
||||||
set<public_key_type> get_required_signatures( const flat_set<public_key_type>& available_keys,
|
set<public_key_type> get_required_signatures( 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_active,
|
||||||
const std::function<const authority*(account_id_type)>& get_owner
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||||
)const;
|
)const;
|
||||||
|
|
||||||
void verify_authority( const std::function<const authority*(account_id_type)>& get_active,
|
void verify_authority( const std::function<const authority*(account_id_type)>& get_active,
|
||||||
const std::function<const authority*(account_id_type)>& get_owner )const;
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;
|
||||||
|
|
||||||
flat_set<public_key_type> get_signature_keys()const;
|
flat_set<public_key_type> get_signature_keys()const;
|
||||||
|
|
||||||
|
|
@ -139,6 +141,8 @@ namespace graphene { namespace chain {
|
||||||
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
||||||
const std::function<const authority*(account_id_type)>& get_active,
|
const std::function<const authority*(account_id_type)>& get_active,
|
||||||
const std::function<const authority*(account_id_type)>& get_owner,
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH,
|
||||||
|
bool allow_committe = false,
|
||||||
const flat_set<account_id_type>& active_aprovals = flat_set<account_id_type>(),
|
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>());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,34 +32,10 @@ namespace graphene { namespace chain {
|
||||||
transaction_evaluation_state( database* db = nullptr )
|
transaction_evaluation_state( database* db = nullptr )
|
||||||
:_db(db){}
|
:_db(db){}
|
||||||
|
|
||||||
/*
|
|
||||||
bool check_authority(const account_object&,
|
|
||||||
authority::classification auth_class = authority::active,
|
|
||||||
int depth = 0);
|
|
||||||
|
|
||||||
bool check_authority(const authority&,
|
|
||||||
authority::classification auth_class = authority::active,
|
|
||||||
int depth = 0);
|
|
||||||
*/
|
|
||||||
|
|
||||||
database& db()const { assert( _db ); return *_db; }
|
database& db()const { assert( _db ); return *_db; }
|
||||||
|
|
||||||
/*
|
|
||||||
bool signed_by(const public_key_type& k);
|
|
||||||
bool signed_by(const address& k);
|
|
||||||
|
|
||||||
/// cached approval (accounts and keys)
|
|
||||||
flat_set<pair<object_id_type,authority::classification>> approved_by;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// Used to look up new objects using transaction relative IDs
|
|
||||||
vector<operation_result> operation_results;
|
vector<operation_result> operation_results;
|
||||||
|
|
||||||
/**
|
|
||||||
* When an address is referenced via check authority it is flagged as being used, all addresses must be
|
|
||||||
* flagged as being used or the transaction will fail.
|
|
||||||
*/
|
|
||||||
// flat_map<public_key_type, bool> _sigs;
|
|
||||||
const signed_transaction* _trx = nullptr;
|
const signed_transaction* _trx = nullptr;
|
||||||
database* _db = nullptr;
|
database* _db = nullptr;
|
||||||
bool _is_proposed_trx = false;
|
bool _is_proposed_trx = false;
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,15 @@ bool proposal_object::is_authorized_to_execute(database& db) const
|
||||||
available_key_approvals,
|
available_key_approvals,
|
||||||
[&]( account_id_type id ){ return &id(db).active; },
|
[&]( account_id_type id ){ return &id(db).active; },
|
||||||
[&]( account_id_type id ){ return &id(db).owner; },
|
[&]( account_id_type id ){ return &id(db).owner; },
|
||||||
|
GRAPHENE_MAX_SIG_CHECK_DEPTH, // TODO make chain param
|
||||||
|
true, /* allow committeee */
|
||||||
available_active_approvals,
|
available_active_approvals,
|
||||||
available_owner_approvals );
|
available_owner_approvals );
|
||||||
} catch ( const fc::exception& e )
|
}
|
||||||
|
catch ( const fc::exception& e )
|
||||||
{
|
{
|
||||||
|
//idump((available_active_approvals));
|
||||||
|
//wlog((e.to_detail_string()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ struct sign_state
|
||||||
|
|
||||||
bool check_authority( account_id_type id )
|
bool check_authority( account_id_type id )
|
||||||
{
|
{
|
||||||
if( id == GRAPHENE_TEMP_ACCOUNT ) return true;
|
if( approved_by.find(id) != approved_by.end() ) return true;
|
||||||
return check_authority( get_active(id) );
|
return check_authority( get_active(id) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ struct sign_state
|
||||||
{
|
{
|
||||||
if( approved_by.find(a.first) == approved_by.end() )
|
if( approved_by.find(a.first) == approved_by.end() )
|
||||||
{
|
{
|
||||||
if( depth == GRAPHENE_MAX_SIG_CHECK_DEPTH )
|
if( depth == max_recursion )
|
||||||
return false;
|
return false;
|
||||||
if( check_authority( get_active( a.first ), depth+1 ) )
|
if( check_authority( get_active( a.first ), depth+1 ) )
|
||||||
{
|
{
|
||||||
|
|
@ -176,12 +176,15 @@ struct sign_state
|
||||||
|
|
||||||
flat_map<public_key_type,bool> provided_signatures;
|
flat_map<public_key_type,bool> provided_signatures;
|
||||||
flat_set<account_id_type> approved_by;
|
flat_set<account_id_type> approved_by;
|
||||||
|
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
||||||
const std::function<const authority*(account_id_type)>& get_active,
|
const std::function<const authority*(account_id_type)>& get_active,
|
||||||
const std::function<const authority*(account_id_type)>& get_owner,
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion_depth,
|
||||||
|
bool allow_committe,
|
||||||
const flat_set<account_id_type>& active_aprovals,
|
const flat_set<account_id_type>& active_aprovals,
|
||||||
const flat_set<account_id_type>& owner_approvals )
|
const flat_set<account_id_type>& owner_approvals )
|
||||||
{ try {
|
{ try {
|
||||||
|
|
@ -192,7 +195,12 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
||||||
for( const auto& op : ops )
|
for( const auto& op : ops )
|
||||||
operation_get_required_authorities( op, required_active, required_owner, other );
|
operation_get_required_authorities( op, required_active, required_owner, other );
|
||||||
|
|
||||||
|
if( !allow_committe )
|
||||||
|
GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
|
||||||
|
invalid_committee_approval, "Committee account may only propose transactions" );
|
||||||
|
|
||||||
sign_state s(sigs,get_active);
|
sign_state s(sigs,get_active);
|
||||||
|
s.max_recursion = max_recursion_depth;
|
||||||
for( auto& id : active_aprovals )
|
for( auto& id : active_aprovals )
|
||||||
s.approved_by.insert( id );
|
s.approved_by.insert( id );
|
||||||
for( auto& id : owner_approvals )
|
for( auto& id : owner_approvals )
|
||||||
|
|
@ -229,7 +237,8 @@ flat_set<public_key_type> signed_transaction::get_signature_keys()const
|
||||||
|
|
||||||
set<public_key_type> signed_transaction::get_required_signatures( const flat_set<public_key_type>& available_keys,
|
set<public_key_type> signed_transaction::get_required_signatures( 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_active,
|
||||||
const std::function<const authority*(account_id_type)>& get_owner )const
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion_depth )const
|
||||||
{
|
{
|
||||||
flat_set<account_id_type> required_active;
|
flat_set<account_id_type> required_active;
|
||||||
flat_set<account_id_type> required_owner;
|
flat_set<account_id_type> required_owner;
|
||||||
|
|
@ -238,6 +247,7 @@ set<public_key_type> signed_transaction::get_required_signatures( const flat_set
|
||||||
|
|
||||||
|
|
||||||
sign_state s(get_signature_keys(),get_active,available_keys);
|
sign_state s(get_signature_keys(),get_active,available_keys);
|
||||||
|
s.max_recursion = max_recursion_depth;
|
||||||
|
|
||||||
for( const auto& auth : other )
|
for( const auto& auth : other )
|
||||||
s.check_authority(&auth);
|
s.check_authority(&auth);
|
||||||
|
|
@ -259,9 +269,10 @@ set<public_key_type> signed_transaction::get_required_signatures( const flat_set
|
||||||
|
|
||||||
|
|
||||||
void signed_transaction::verify_authority( const std::function<const authority*(account_id_type)>& get_active,
|
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
|
const std::function<const authority*(account_id_type)>& get_owner,
|
||||||
|
uint32_t max_recursion )const
|
||||||
{ try {
|
{ try {
|
||||||
graphene::chain::verify_authority( operations, get_signature_keys(), get_active, get_owner );
|
graphene::chain::verify_authority( operations, get_signature_keys(), get_active, get_owner, max_recursion );
|
||||||
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,6 @@ BOOST_AUTO_TEST_CASE( proposed_single_account )
|
||||||
trx.set_expiration( db.head_block_time() + fc::seconds( 3 * db.get_global_properties().parameters.block_interval ));
|
trx.set_expiration( db.head_block_time() + fc::seconds( 3 * db.get_global_properties().parameters.block_interval ));
|
||||||
trx.set_reference_block( db.head_block_id() );
|
trx.set_reference_block( db.head_block_id() );
|
||||||
|
|
||||||
//idump((moneyman));
|
|
||||||
trx.sign( init_account_priv_key );
|
trx.sign( init_account_priv_key );
|
||||||
const proposal_object& proposal = db.get<proposal_object>(PUSH_TX( db, trx ).operation_results.front().get<object_id_type>());
|
const proposal_object& proposal = db.get<proposal_object>(PUSH_TX( db, trx ).operation_results.front().get<object_id_type>());
|
||||||
|
|
||||||
|
|
@ -353,6 +352,7 @@ BOOST_AUTO_TEST_CASE( proposed_single_account )
|
||||||
proposal_update_operation pup;
|
proposal_update_operation pup;
|
||||||
pup.proposal = proposal.id;
|
pup.proposal = proposal.id;
|
||||||
pup.fee_paying_account = nathan.id;
|
pup.fee_paying_account = nathan.id;
|
||||||
|
BOOST_TEST_MESSAGE( "Updating the proposal to have nathan's authority" );
|
||||||
pup.active_approvals_to_add.insert(nathan.id);
|
pup.active_approvals_to_add.insert(nathan.id);
|
||||||
|
|
||||||
trx.operations = {pup};
|
trx.operations = {pup};
|
||||||
|
|
@ -399,13 +399,13 @@ BOOST_AUTO_TEST_CASE( committee_authority )
|
||||||
p.parameters.committee_proposal_review_period = fc::days(1).to_seconds();
|
p.parameters.committee_proposal_review_period = fc::days(1).to_seconds();
|
||||||
});
|
});
|
||||||
|
|
||||||
BOOST_TEST_MESSAGE( "transfering 100000 CORE to nathan, signing with committee key" );
|
BOOST_TEST_MESSAGE( "transfering 100000 CORE to nathan, signing with committee key should fail because this requires it to be part of a proposal" );
|
||||||
transfer_operation top;
|
transfer_operation top;
|
||||||
top.to = nathan.id;
|
top.to = nathan.id;
|
||||||
top.amount = asset(100000);
|
top.amount = asset(100000);
|
||||||
trx.operations.push_back(top);
|
trx.operations.push_back(top);
|
||||||
sign(trx, committee_key);
|
sign(trx, committee_key);
|
||||||
GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception);
|
GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), graphene::chain::invalid_committee_approval );
|
||||||
|
|
||||||
auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key); };
|
auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key); };
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue