Skip to content

Commit

Permalink
Implement verify_signatures API call steemit#1674
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Vandeberg committed Oct 20, 2017
1 parent 56c4d89 commit 6d378ff
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 12 deletions.
60 changes: 60 additions & 0 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
set<public_key_type> get_potential_signatures( const signed_transaction& trx )const;
bool verify_authority( const signed_transaction& trx )const;
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
verify_signatures_return verify_signatures( const verify_signatures_args& args )const;

// signal handlers
void on_applied_block( const chain::signed_block& b );
Expand Down Expand Up @@ -964,6 +965,65 @@ bool database_api_impl::verify_account_authority( const string& name, const flat
return verify_authority( trx );
}

verify_signatures_return database_api_impl::verify_signatures( const verify_signatures_args& args )const
{
// get_signature_keys can throw for dup sigs. Allow this to throw.
flat_set< public_key_type > sig_keys;
for( const auto& sig : args.signatures )
{
STEEMIT_ASSERT(
sig_keys.insert( fc::ecc::public_key(sig,args.hash) ).second,
tx_duplicate_sig,
"Duplicate Signature detected" );
}

verify_signatures_return result;
result.valid = true;

// verify authority throws on failure, catch and return false
try
{
steemit::protocol::verify_authority(
[&args]( flat_set< account_name_type >& required_active,
flat_set< account_name_type >& required_owner,
flat_set< account_name_type >& required_posting,
vector< authority >& )
{
switch( args.auth_level )
{
case authority::owner:
std::copy( args.accounts.begin(), args.accounts.end(), required_owner.end() );
break;
case authority::active:
std::copy( args.accounts.begin(), args.accounts.end(), required_active.end() );
break;
case authority::posting:
std::copy( args.accounts.begin(), args.accounts.end(), required_posting.end() );
break;
case authority::key:
default:
FC_ASSERT( false, "verify_signatures only supports owner, active, and posting auths" );
}
},
sig_keys,
[this]( const string& name ) { return authority( _db.get< account_authority_object, by_account >( name ).owner ); },
[this]( const string& name ) { return authority( _db.get< account_authority_object, by_account >( name ).active ); },
[this]( const string& name ) { return authority( _db.get< account_authority_object, by_account >( name ).posting ); },
STEEMIT_MAX_SIG_CHECK_DEPTH );
}
catch( fc::exception& ) { result.valid = false; }

return result;
}

verify_signatures_return database_api::verify_signatures( const verify_signatures_args& args )const
{
return my->_db.with_read_lock( [&]()
{
return my->verify_signatures( args );
});
}

vector<convert_request_api_obj> database_api::get_conversion_requests( const string& account )const
{
return my->_db.with_read_lock( [&]()
Expand Down
23 changes: 23 additions & 0 deletions libraries/app/include/steemit/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ struct discussion_query {
optional<string> parent_permlink;
};

struct verify_signatures_args
{
fc::sha256 hash;
vector< signature_type > signatures;
vector< account_name_type > accounts;
authority::classification auth_level;
};

struct verify_signatures_return
{
bool valid;
};

/**
* @brief The database_api class implements the RPC API for the chain database.
*
Expand Down Expand Up @@ -326,6 +339,12 @@ class database_api
*/
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;

/*
* This is a general purpose API that checks signatures against accounts for an arbitrary sha256 hash
* using the existing authority structures in Steem
*/
verify_signatures_return verify_signatures( const verify_signatures_args& args )const;

/**
* if permlink is "" then it will return all votes for author
*/
Expand Down Expand Up @@ -447,6 +466,9 @@ FC_REFLECT( steemit::app::discussion_query, (tag)(filter_tags)(select_tags)(sele

FC_REFLECT_ENUM( steemit::app::withdraw_route_type, (incoming)(outgoing)(all) );

FC_REFLECT( steemit::app::verify_signatures_args, (hash)(signatures)(accounts)(auth_level) );
FC_REFLECT( steemit::app::verify_signatures_return, (valid) );

FC_API(steemit::app::database_api,
// Subscriptions
(set_block_applied_callback)
Expand Down Expand Up @@ -519,6 +541,7 @@ FC_API(steemit::app::database_api,
(get_potential_signatures)
(verify_authority)
(verify_account_authority)
(verify_signatures)

// votes
(get_active_votes)
Expand Down
5 changes: 5 additions & 0 deletions libraries/protocol/include/steemit/protocol/sign_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
namespace steemit { namespace protocol {

typedef std::function<authority(const string&)> authority_getter;
typedef std::function< void( flat_set< account_name_type >&,
flat_set< account_name_type >&,
flat_set< account_name_type >&,
vector< authority >& ) >
required_authority_getter;

struct sign_state
{
Expand Down
4 changes: 1 addition & 3 deletions libraries/protocol/include/steemit/protocol/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ namespace steemit { namespace protocol {
void clear() { operations.clear(); signatures.clear(); }
};

void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
void verify_authority( const required_authority_getter& ops, const flat_set<public_key_type>& sigs,
const authority_getter& get_active,
const authority_getter& get_owner,
const authority_getter& get_posting,
Expand All @@ -101,7 +101,6 @@ namespace steemit { namespace protocol {
const flat_set< account_name_type >& owner_aprovals = flat_set< account_name_type >(),
const flat_set< account_name_type >& posting_approvals = flat_set< account_name_type >());


struct annotated_signed_transaction : public signed_transaction {
annotated_signed_transaction(){}
annotated_signed_transaction( const signed_transaction& trx )
Expand All @@ -112,7 +111,6 @@ namespace steemit { namespace protocol {
uint32_t transaction_num = 0;
};


/// @} transactions group

} } // steemit::protocol
Expand Down
29 changes: 20 additions & 9 deletions libraries/protocol/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void transaction::get_required_authorities( flat_set< account_name_type >& activ
operation_get_required_authorities( op, active, owner, posting, other );
}

void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
void verify_authority( const required_authority_getter& get_required_authorities, const flat_set<public_key_type>& sigs,
const authority_getter& get_active,
const authority_getter& get_owner,
const authority_getter& get_posting,
Expand All @@ -98,8 +98,7 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
flat_set< account_name_type > required_posting;
vector< authority > other;

for( const auto& op : ops )
operation_get_required_authorities( op, required_active, required_owner, required_posting, other );
get_required_authorities( required_active, required_owner, required_posting, other );

/**
* Transactions with operations required posting authority cannot be combined
Expand Down Expand Up @@ -169,8 +168,7 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
tx_irrelevant_sig,
"Unnecessary signature(s) detected"
);
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }

} FC_CAPTURE_AND_RETHROW( (sigs) ) }

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
Expand All @@ -186,8 +184,6 @@ flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id
return result;
} FC_CAPTURE_AND_RETHROW() }



set<public_key_type> signed_transaction::get_required_signatures(
const chain_id_type& chain_id,
const flat_set<public_key_type>& available_keys,
Expand Down Expand Up @@ -262,7 +258,14 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
result.erase( k );
try
{
steemit::protocol::verify_authority( operations, result, get_active, get_owner, get_posting, max_recursion );
steemit::protocol::verify_authority( [this]( flat_set< account_name_type >& required_active,
flat_set< account_name_type >& required_owner,
flat_set< account_name_type >& required_posting,
vector< authority >& other )
{
for( const auto& op : operations )
operation_get_required_authorities( op, required_active, required_owner, required_posting, other );
}, result, get_active, get_owner, get_posting, max_recursion );
continue; // element stays erased if verify_authority is ok
}
catch( const tx_missing_owner_auth& e ) {}
Expand All @@ -281,7 +284,15 @@ void signed_transaction::verify_authority(
const authority_getter& get_posting,
uint32_t max_recursion )const
{ try {
steemit::protocol::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, get_posting, max_recursion );
steemit::protocol::verify_authority( [this]( flat_set< account_name_type >& required_active,
flat_set< account_name_type >& required_owner,
flat_set< account_name_type >& required_posting,
vector< authority >& other )
{
for( const auto& op : operations )
operation_get_required_authorities( op, required_active, required_owner, required_posting, other );
},
get_signature_keys( chain_id ), get_active, get_owner, get_posting, max_recursion );
} FC_CAPTURE_AND_RETHROW( (*this) ) }

} } // steemit::protocol

0 comments on commit 6d378ff

Please sign in to comment.