Skip to content

Commit

Permalink
Merge pull request #1384 from bitshares/jmj_1366
Browse files Browse the repository at this point in the history
have verify_account_authority check passed-in keys
  • Loading branch information
pmconrad authored Oct 25, 2018
2 parents 8d09a46 + b078310 commit 2e15e77
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 14 deletions.
27 changes: 18 additions & 9 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
map< pair<asset_id_type,asset_id_type>, std::function<void(const variant&)> > _market_subscriptions;
graphene::chain::database& _db;
const application_options* _app_options = nullptr;

};

//////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -2068,17 +2067,27 @@ bool database_api::verify_account_authority( const string& account_name_or_id, c
return my->verify_account_authority( account_name_or_id, signers );
}

bool database_api_impl::verify_account_authority( const string& account_name_or_id, const flat_set<public_key_type>& keys )const
bool database_api_impl::verify_account_authority( const string& account_name_or_id,
const flat_set<public_key_type>& keys )const
{
const account_object* account = get_account_from_string(account_name_or_id);

/// reuse trx.verify_authority by creating a dummy transfer
signed_transaction trx;
// create a dummy transfer
transfer_operation op;
op.from = account->id;
trx.operations.emplace_back(op);
op.from = get_account_from_string(account_name_or_id)->id;
std::vector<operation> ops;
ops.emplace_back(op);

return verify_authority( trx );
try
{
graphene::chain::verify_authority(ops, keys,
[this]( account_id_type id ){ return &id(_db).active; },
[this]( account_id_type id ){ return &id(_db).owner; } );
}
catch (fc::exception& ex)
{
return false;
}

return true;
}

processed_transaction database_api::validate_transaction( const signed_transaction& trx )const
Expand Down
7 changes: 5 additions & 2 deletions libraries/app/include/graphene/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,9 +669,12 @@ class database_api
bool verify_authority( const signed_transaction& trx )const;

/**
* @return true if the signers have enough authority to authorize an account
* @brief Verify that the public keys have enough authority to approve an operation for this account
* @param account_name_or_id the account to check
* @param signers the public keys
* @return true if the passed in keys have enough authority to approve an operation for this account
*/
bool verify_account_authority( const string& account_name_or_id, const flat_set<public_key_type>& signers )const;
bool verify_account_authority( const string& account_name_or_id, const flat_set<public_key_type>& signers )const;

/**
* Validates a transaction against the current state without broadcasting it on the network.
Expand Down
110 changes: 110 additions & 0 deletions tests/tests/database_api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,4 +831,114 @@ BOOST_AUTO_TEST_CASE( get_transaction_hex )

} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE(verify_account_authority)
{
try {

ACTORS( (nathan) );
graphene::app::database_api db_api(db);

// good keys
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_public_key);
BOOST_CHECK(db_api.verify_account_authority( "nathan", public_keys));

// bad keys
flat_set<public_key_type> bad_public_keys;
bad_public_keys.emplace(public_key_type("BTS6MkMxwBjFWmcDjXRoJ4mW9Hd4LCSPwtv9tKG1qYW5Kgu4AhoZy"));
BOOST_CHECK(!db_api.verify_account_authority( "nathan", bad_public_keys));

} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_CASE( any_two_of_three )
{
try {
fc::ecc::private_key nathan_key1 = fc::ecc::private_key::regenerate(fc::digest("key1"));
fc::ecc::private_key nathan_key2 = fc::ecc::private_key::regenerate(fc::digest("key2"));
fc::ecc::private_key nathan_key3 = fc::ecc::private_key::regenerate(fc::digest("key3"));
const account_object& nathan = create_account("nathan", nathan_key1.get_public_key() );
fund(nathan);
graphene::app::database_api db_api(db);

try {
account_update_operation op;
op.account = nathan.id;
op.active = authority(2, public_key_type(nathan_key1.get_public_key()), 1,
public_key_type(nathan_key2.get_public_key()), 1, public_key_type(nathan_key3.get_public_key()), 1);
op.owner = *op.active;
trx.operations.push_back(op);
sign(trx, nathan_key1);
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
trx.clear();
} FC_CAPTURE_AND_RETHROW ((nathan.active))

// two keys should work
{
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_key1.get_public_key());
public_keys.emplace(nathan_key2.get_public_key());
BOOST_CHECK(db_api.verify_account_authority("nathan", public_keys));
}

// the other two keys should work
{
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_key2.get_public_key());
public_keys.emplace(nathan_key3.get_public_key());
BOOST_CHECK(db_api.verify_account_authority("nathan", public_keys));
}

// just one key should not work
{
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_key1.get_public_key());
BOOST_CHECK(!db_api.verify_account_authority("nathan", public_keys));
}
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}

BOOST_AUTO_TEST_CASE( verify_authority_multiple_accounts )
{
try {
ACTORS( (nathan) (alice) (bob) );

graphene::app::database_api db_api(db);

try {
account_update_operation op;
op.account = nathan.id;
op.active = authority(3, nathan_public_key, 1, alice.id, 1, bob.id, 1);
op.owner = *op.active;
trx.operations.push_back(op);
sign(trx, nathan_private_key);
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
trx.clear();
} FC_CAPTURE_AND_RETHROW ((nathan.active))

// requires 3 signatures
{
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_public_key);
public_keys.emplace(alice_public_key);
public_keys.emplace(bob_public_key);
BOOST_CHECK(db_api.verify_account_authority("nathan", public_keys));
}

// only 2 signatures given
{
flat_set<public_key_type> public_keys;
public_keys.emplace(nathan_public_key);
public_keys.emplace(bob_public_key);
BOOST_CHECK(!db_api.verify_account_authority("nathan", public_keys));
}
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}

BOOST_AUTO_TEST_SUITE_END()
8 changes: 5 additions & 3 deletions tests/tests/wallet_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <graphene/app/database_api.hpp>
#include <graphene/wallet/wallet.hpp>
#include <fc/crypto/digest.hpp>

#include <iostream>

Expand All @@ -45,7 +46,7 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, database_fixture)
/***
* Act
*/
int nbr_keys_desired = 3;
unsigned int nbr_keys_desired = 3;
vector<brain_key_info> derived_keys = graphene::wallet::utility::derive_owner_keys_from_brain_key("SOME WORDS GO HERE", nbr_keys_desired);


Expand All @@ -70,10 +71,11 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, database_fixture)
string expected_prefix = GRAPHENE_ADDRESS_PREFIX;
for (auto info : derived_keys) {
string description = (string) info.pub_key;
BOOST_CHECK_EQUAL(0, description.find(expected_prefix));
BOOST_CHECK_EQUAL(0u, description.find(expected_prefix));
}

} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 2e15e77

Please sign in to comment.