Partial work toward auth refactor

This commit is contained in:
Daniel Larimer 2015-07-16 18:13:11 -04:00
parent dc8849f23b
commit b08b6cb553
9 changed files with 164 additions and 98 deletions

View file

@ -216,6 +216,7 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
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()),
@ -228,6 +229,7 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
[]( account_id_type id ) {
return std::make_pair(id, authority::owner);
});
*/
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
processed_transaction ptrx(proposal.proposed_transaction);
@ -482,8 +484,13 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
const chain_parameters& chain_parameters = get_global_properties().parameters;
eval_state._trx = &trx;
if( !(skip & skip_transaction_signatures) )
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; };
trx.verify_authority( get_active, get_owner );
/*
eval_state._sigs.reserve(trx.signatures.size());
for( const auto& sig : trx.signatures )
@ -492,6 +499,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
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
@ -538,6 +546,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
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 )
@ -545,6 +554,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
FC_ASSERT( item.second, "All signatures must be used", ("item",item) );
}
}
*/
return ptrx;
} FC_CAPTURE_AND_RETHROW( (trx) ) }
@ -564,7 +574,7 @@ operation_result database::apply_operation(transaction_evaluation_state& eval_st
auto result = eval->evaluate( eval_state, op, true );
set_applied_operation_result( op_id, result );
return result;
} FC_CAPTURE_AND_RETHROW( (eval_state._sigs) ) }
} FC_CAPTURE_AND_RETHROW( ) }
const witness_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const
{

View file

@ -34,7 +34,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
operation_result generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
{ try {
trx_state = &eval_state;
check_required_authorities(op);
//check_required_authorities(op);
auto result = evaluate( op );
if( apply ) result = this->apply( op );
@ -77,6 +77,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
});
} FC_CAPTURE_AND_RETHROW() }
/*
bool generic_evaluator::verify_authority( const account_object& a, authority::classification c )
{ try {
return trx_state->check_authority( a, c );
@ -117,6 +118,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
}
} FC_CAPTURE_AND_RETHROW( (op) ) }
*/
void generic_evaluator::verify_authority_accounts( const authority& a )const
{

View file

@ -84,7 +84,7 @@ namespace graphene { namespace chain {
database& db()const;
void check_required_authorities(const operation& op);
//void check_required_authorities(const operation& op);
protected:
/**
* @brief Fetch objects relevant to fee payer and set pointer members
@ -98,7 +98,7 @@ namespace graphene { namespace chain {
/// Pays the fee and returns the number of CORE asset that were paid.
void pay_fee();
bool verify_authority(const account_object&, authority::classification);
//bool verify_authority(const account_object&, authority::classification);
object_id_type get_relative_id( object_id_type rel_id )const;
void verify_authority_accounts( const authority& a )const;

View file

@ -118,23 +118,17 @@ namespace graphene { namespace chain {
/**
* The purpose of this method is to identify the minimal subset of @ref available_keys that are
* required to sign
* required to sign given the signatures that are already provided.
*/
set<public_key_type> get_required_signatures( const set<public_key_type>& available_keys,
const map<account_id_type,authority>& active_authorities,
const map<account_id_type,authority>& owner_authorities )const;
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_owner
)const;
/**
* Given a set of private keys sign this transaction with a minimial subset of required keys.
*
* @pram get_auth - used to fetch the active authority required for an account referenced by another authority
*/
void sign( const vector<private_key_type>& keys,
const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner );
bool verify( const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner )const;
void verify_authority( const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner )const;
flat_set<public_key_type> get_signature_keys()const;
vector<signature_type> signatures;
@ -142,6 +136,12 @@ namespace graphene { namespace chain {
void clear() { operations.clear(); signatures.clear(); }
};
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_owner,
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>());
/**
* @brief captures the result of evaluating the operations contained in the transaction
*

View file

@ -32,6 +32,7 @@ namespace graphene { namespace chain {
transaction_evaluation_state( database* db = nullptr )
:_db(db){}
/*
bool check_authority(const account_object&,
authority::classification auth_class = authority::active,
int depth = 0);
@ -39,14 +40,17 @@ namespace graphene { namespace chain {
bool check_authority(const authority&,
authority::classification auth_class = authority::active,
int depth = 0);
*/
database& db()const { FC_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;
@ -55,7 +59,7 @@ namespace graphene { namespace chain {
* 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;
// flat_map<public_key_type, bool> _sigs;
const signed_transaction* _trx = nullptr;
database* _db = nullptr;
bool _is_proposed_trx = false;

View file

@ -121,7 +121,6 @@ void_result proposal_update_evaluator::do_evaluate(const proposal_update_operati
}
/* All authority checks happen outside of evaluators
*/
if( (d.get_node_properties().skip_flags & database::skip_authority_check) == 0 )
{
for( const auto& id : o.key_approvals_to_add )
@ -133,6 +132,7 @@ void_result proposal_update_evaluator::do_evaluate(const proposal_update_operati
FC_ASSERT( trx_state->signed_by(id) );
}
}
*/
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }

View file

@ -24,6 +24,22 @@ namespace graphene { namespace chain {
bool proposal_object::is_authorized_to_execute(database& db) const
{
transaction_evaluation_state dry_run_eval(&db);
try {
verify_authority( proposed_transaction.operations,
available_key_approvals,
[&]( account_id_type id ){ return &id(db).active; },
[&]( account_id_type id ){ return &id(db).owner; },
available_active_approvals,
available_owner_approvals );
} catch ( const fc::exception& e )
{
return false;
}
return true;
/*
dry_run_eval._is_proposed_trx = true;
std::transform(available_active_approvals.begin(), available_active_approvals.end(),
std::inserter(dry_run_eval.approved_by, dry_run_eval.approved_by.end()), [](object_id_type id) {
@ -50,8 +66,8 @@ bool proposal_object::is_authorized_to_execute(database& db) const
for( const auto& id : required_owner_approvals )
if( !dry_run_eval.check_authority(id(db), authority::owner) )
return false;
*/
return true;
}

View file

@ -15,7 +15,8 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
@ -79,6 +80,9 @@ void transaction::get_required_authorities( flat_set<account_id_type>& active, f
operation_get_required_authorities( op, active, owner, other );
}
struct sign_state
{
/** returns true if we have a signature for this key or can
@ -86,20 +90,21 @@ struct sign_state
*/
bool signed_by( const public_key_type& k )
{
auto itr = signatures.find(k);
if( itr == signatures.end() )
auto itr = provided_signatures.find(k);
if( itr == provided_signatures.end() )
{
auto pk = keys.find(k);
if( pk != keys.end() )
{
signatures[k] = trx.sign(pk->second);
checked_sigs.insert(k);
return true;
}
auto pk = available_keys.find(k);
if( pk != available_keys.end() )
return provided_signatures[k] = true;
return false;
}
checked_sigs.insert(k);
return true;
return itr->second = true;
}
bool check_authority( account_id_type id )
{
if( id == GRAPHENE_TEMP_ACCOUNT ) return true;
return check_authority( get_active(id) );
}
/**
@ -147,89 +152,116 @@ struct sign_state
bool remove_unused_signatures()
{
vector<public_key_type> remove_sigs;
for( const auto& sig : signatures )
if( checked_sigs.find(sig.first) == checked_sigs.end() )
remove_sigs.push_back( sig.first );
for( const auto& sig : provided_signatures )
if( !sig.second ) remove_sigs.push_back( sig.first );
for( auto& sig : remove_sigs )
signatures.erase(sig);
provided_signatures.erase(sig);
return remove_sigs.size() != 0;
}
sign_state( const signed_transaction& t, const std::function<const authority*(account_id_type)>& a,
const vector<private_key_type>& kys = vector<private_key_type>() )
:trx(t),get_active(a)
sign_state( const flat_set<public_key_type>& sigs,
const std::function<const authority*(account_id_type)>& a,
const flat_set<public_key_type>& keys = flat_set<public_key_type>() )
:get_active(a),available_keys(keys)
{
auto d = trx.digest();
for( const auto& sig : trx.signatures )
signatures[ fc::ecc::public_key( sig, d ) ] = sig;
for( const auto& key : kys )
keys[key.get_public_key()] = key;
for( const auto& key : sigs )
provided_signatures[ key ] = false;
approved_by.insert( GRAPHENE_TEMP_ACCOUNT );
}
const signed_transaction& trx;
const std::function<const authority*(account_id_type)>& get_active;
const flat_set<public_key_type>& available_keys;
flat_map<public_key_type,private_key_type> keys;
flat_map<public_key_type,signature_type> signatures;
set<public_key_type> checked_sigs;
flat_set<account_id_type> approved_by;
flat_map<public_key_type,bool> provided_signatures;
flat_set<account_id_type> approved_by;
};
/**
* Given a set of private keys sign this transaction with a minimial subset of required keys.
*/
void signed_transaction::sign( const vector<private_key_type>& keys,
const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner )
{
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_owner,
const flat_set<account_id_type>& active_aprovals,
const flat_set<account_id_type>& owner_approvals )
{ try {
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
get_required_authorities( required_active, required_owner, other );
sign_state s(*this,get_active,keys);
for( const auto& op : ops )
operation_get_required_authorities( op, required_active, required_owner, other );
sign_state s(sigs,get_active);
for( auto& id : active_aprovals )
s.approved_by.insert( id );
for( auto& id : owner_approvals )
s.approved_by.insert( id );
for( const auto& auth : other )
s.check_authority(&auth);
for( auto id : required_active )
s.check_authority(get_active(id));
for( auto id : required_owner )
s.check_authority(get_owner(id));
s.remove_unused_signatures();
signatures.clear();
for( const auto& sig : s.signatures )
signatures.push_back(sig.second);
}
bool signed_transaction::verify( const std::function<const authority*(account_id_type)>& get_active,
const std::function<const authority*(account_id_type)>& get_owner )const
{
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
get_required_authorities( required_active, required_owner, other );
sign_state s(*this,get_active);
for( const auto& auth : other )
if( !s.check_authority(&auth) )
return false;
GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
// fetch all of the top level authorities
for( auto id : required_active )
if( !s.check_authority(get_active(id)) )
return false;
GRAPHENE_ASSERT( s.check_authority(id) ||
s.check_authority(get_owner(id)),
tx_missing_active_auth, "Missing Active Authority ${id}", ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
for( auto id : required_owner )
if( !s.check_authority(get_owner(id)) )
return false;
if( s.remove_unused_signatures() )
return false;
return true;
GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
s.check_authority(get_owner(id)),
tx_missing_other_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
FC_ASSERT( !s.remove_unused_signatures(), "Unnecessary signatures detected" );
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }
flat_set<public_key_type> signed_transaction::get_signature_keys()const
{ try {
auto d = digest();
flat_set<public_key_type> result;
for( const auto& sig : signatures )
FC_ASSERT( result.insert( fc::ecc::public_key(sig,d) ).second, "Duplicate Signature detected" );
return result;
} FC_CAPTURE_AND_RETHROW() }
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_owner )const
{
flat_set<account_id_type> required_active;
flat_set<account_id_type> required_owner;
vector<authority> other;
get_required_authorities( required_active, required_owner, other );
sign_state s(get_signature_keys(),get_active,available_keys);
for( const auto& auth : other )
s.check_authority(&auth);
for( auto& owner : required_owner )
s.check_authority( get_owner( owner ) );
for( auto& active : required_active )
s.check_authority( active );
s.remove_unused_signatures();
set<public_key_type> result;
for( auto& provided_sig : s.provided_signatures )
if( available_keys.find( provided_sig.first ) != available_keys.end() )
result.insert( provided_sig.first );
return result;
}
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
{ try {
graphene::chain::verify_authority( operations, get_signature_keys(), get_active, get_owner );
} FC_CAPTURE_AND_RETHROW( (*this) ) }
} } // graphene::chain

View file

@ -23,6 +23,7 @@
#include <graphene/chain/exceptions.hpp>
namespace graphene { namespace chain {
/*
bool transaction_evaluation_state::check_authority( const account_object& account, authority::classification auth_class, int depth )
{
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_authority_check) )
@ -121,5 +122,6 @@ namespace graphene { namespace chain {
if( itr->first == k ) return itr->second = true;
return false;
}
*/
} } // namespace graphene::chain