Skip to content

Commit

Permalink
move code for collecting potential keys to use for transaction signin…
Browse files Browse the repository at this point in the history
…g from wallet to protocol

Also fixes bug where automatic detection would use indirect owner key instead of active.
  • Loading branch information
ABW committed Jul 18, 2024
1 parent 119f230 commit b30796a
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 193 deletions.
35 changes: 35 additions & 0 deletions libraries/protocol/include/hive/protocol/transaction_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,40 @@ void verify_authority(const vector<AuthContainerType>& auth_containers,
*/
void collect_potential_keys( std::vector< public_key_type >* keys, const account_name_type& account, const std::string& str );

/**
* Class that encapsulates process of detecting which keys need to be used for signing transaction.
*/
class signing_keys_collector
{
public:
virtual ~signing_keys_collector() {}

// disables automatic detection and adds given account's active authority to set of used authorities
void use_active_authority( const account_name_type& account_name );
// disables automatic detection and adds given account's owner authority to set of used authorities
void use_owner_authority( const account_name_type& account_name );
// disables automatic detection and adds given account's posting authority to set of used authorities
void use_posting_authority( const account_name_type& account_name );
// clears set of used authorities and enables automatic detection
void use_automatic_authority();

bool automatic_detection_enabled() const { return automatic_detection; }

virtual void collect_signing_keys( flat_set< public_key_type >* keys, const transaction& tx );

// called before get_active/get_owner/get_posting for each given account
virtual void prepare_account_authority_data( const std::vector< account_name_type >& accounts ) = 0;

virtual const authority& get_active( const account_name_type& account_name ) const = 0;
virtual const authority& get_owner( const account_name_type& account_name ) const = 0;
virtual const authority& get_posting( const account_name_type& account_name ) const = 0;

protected:
flat_set<account_name_type> use_active;
flat_set<account_name_type> use_owner;
flat_set<account_name_type> use_posting;
bool automatic_detection = true;
};

} } // hive::protocol

149 changes: 149 additions & 0 deletions libraries/protocol/transaction_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,153 @@ void collect_potential_keys( std::vector< public_key_type >* keys,
keys->push_back( generate_key( "memo" ) );
}

void signing_keys_collector::use_active_authority( const account_name_type& account_name )
{
automatic_detection = false;
use_active.emplace( account_name );
// note: we are not enforcing rule that says posting and active/owner are mutually exclusive
}

void signing_keys_collector::use_owner_authority( const account_name_type& account_name )
{
automatic_detection = false;
use_owner.emplace( account_name );
// note: we are not enforcing rule that says posting and active/owner are mutually exclusive
}

void signing_keys_collector::use_posting_authority( const account_name_type& account_name )
{
automatic_detection = false;
use_posting.emplace( account_name );
// note: we are not enforcing rule that says posting and active/owner are mutually exclusive
}

void signing_keys_collector::use_automatic_authority()
{
automatic_detection = true;
use_active.clear();
use_owner.clear();
use_posting.clear();
}

void signing_keys_collector::collect_signing_keys( flat_set< public_key_type >* keys, const transaction& tx )
{
flat_set< account_name_type > req_active_approvals;
flat_set< account_name_type > req_owner_approvals;
flat_set< account_name_type > req_posting_approvals;
flat_set< account_name_type > req_witness_approvals;
vector< authority > other_auths;

if( automatic_detection )
{
tx.get_required_authorities( req_active_approvals, req_owner_approvals, req_posting_approvals, req_witness_approvals, other_auths );
}
else
{
req_active_approvals.insert( use_active.begin(), use_active.end() );
req_owner_approvals.insert( use_owner.begin(), use_owner.end() );
req_posting_approvals.insert( use_posting.begin(), use_posting.end() );
}

for( const auto& auth : other_auths )
for( const auto& a : auth.account_auths )
req_active_approvals.insert( a.first );

// std::merge lets us de-duplicate account_id's that occur in both sets, and dump them into
// a vector at the same time
vector< account_name_type > v_approving_accounts;
std::merge( req_active_approvals.begin(), req_active_approvals.end(),
req_owner_approvals.begin(), req_owner_approvals.end(),
std::back_inserter( v_approving_accounts ) );
// in correct case above and below are mutually exclusive (at least for now, since mixing posting
// with active/owner is forbidden), but we are not enforcing it here
for( const auto& a : req_posting_approvals )
v_approving_accounts.push_back( a );

/// TODO: handle the op that must be signed using witness keys

prepare_account_authority_data( v_approving_accounts );

auto get_authorities = [&]( flat_set< account_name_type > authorities_names,
authority::classification type ) -> std::vector< account_name_type >
{
std::vector< account_name_type > v_authorities_names_next_level, all_extra_approving_accounts;

uint32_t depth = 1;
while( depth <= HIVE_MAX_SIG_CHECK_DEPTH )
{
flat_set< account_name_type > authorities_names_next_level;

for( const auto& name : authorities_names )
{
const authority* current_auth = nullptr;
switch( type )
{
case authority::owner: current_auth = &get_owner( name ); break;
case authority::active: current_auth = &get_active( name ); break;
case authority::posting: current_auth = &get_posting( name ); break;
}
for( const auto& kv : current_auth->account_auths )
authorities_names_next_level.insert( kv.first );
}

if( authorities_names_next_level.empty() )
break;

for( const auto& name : authorities_names_next_level )
{
v_authorities_names_next_level.emplace_back( name );
all_extra_approving_accounts.emplace_back( name );
}
authorities_names = std::move( authorities_names_next_level );

prepare_account_authority_data( v_authorities_names_next_level );
++depth;
if( type != authority::posting )
type = authority::active;
}

return all_extra_approving_accounts;
};

if( automatic_detection )
{
auto additional_approving_accounts = get_authorities( req_active_approvals, authority::active );
req_active_approvals.insert( additional_approving_accounts.begin(), additional_approving_accounts.end() );
additional_approving_accounts = get_authorities( req_owner_approvals, authority::owner );
req_active_approvals.insert( additional_approving_accounts.begin(), additional_approving_accounts.end() );
additional_approving_accounts = get_authorities( req_posting_approvals, authority::posting );
req_posting_approvals.insert( additional_approving_accounts.begin(), additional_approving_accounts.end() );
}

for( const auto& name : req_active_approvals )
{
auto v_approving_keys = get_active( name ).get_keys();
wdump( ( v_approving_keys ) );
keys->insert( v_approving_keys.begin(), v_approving_keys.end() );
}
for( const auto& name : req_owner_approvals )
{
auto v_approving_keys = get_owner( name ).get_keys();
wdump( ( v_approving_keys ) );
keys->insert( v_approving_keys.begin(), v_approving_keys.end() );
}

for( const auto& name : req_posting_approvals )
{
auto v_approving_keys = get_posting( name ).get_keys();
wdump( ( v_approving_keys ) );
keys->insert( v_approving_keys.begin(), v_approving_keys.end() );
}

for( const authority& a : other_auths )
{
for( const auto& kv : a.key_auths )
{
wdump( ( kv.first ) );
keys->insert( kv.first );
}
}
}

} } // hive::protocol
Loading

0 comments on commit b30796a

Please sign in to comment.