Merged changes from bitshares PR #1259
This commit is contained in:
parent
1d5372d432
commit
58b1872d6c
8 changed files with 1312 additions and 31 deletions
|
|
@ -26,6 +26,7 @@
|
|||
#include <graphene/chain/get_config.hpp>
|
||||
#include <graphene/chain/tournament_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
#include <fc/bloom_filter.hpp>
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
|
|
@ -1773,10 +1774,12 @@ set<public_key_type> database_api::get_required_signatures( const signed_transac
|
|||
set<public_key_type> database_api_impl::get_required_signatures( const signed_transaction& trx, const flat_set<public_key_type>& available_keys )const
|
||||
{
|
||||
wdump((trx)(available_keys));
|
||||
bool allow_non_immediate_owner = ( _db.head_block_time() >= HARDFORK_1002_TIME );
|
||||
auto result = trx.get_required_signatures( _db.get_chain_id(),
|
||||
available_keys,
|
||||
[&]( account_id_type id ){ return &id(_db).active; },
|
||||
[&]( account_id_type id ){ return &id(_db).owner; },
|
||||
allow_non_immediate_owner,
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
wdump((result));
|
||||
return result;
|
||||
|
|
@ -1794,7 +1797,11 @@ set<address> database_api::get_potential_address_signatures( const signed_transa
|
|||
set<public_key_type> database_api_impl::get_potential_signatures( const signed_transaction& trx )const
|
||||
{
|
||||
wdump((trx));
|
||||
auto chain_time = _db.head_block_time();
|
||||
bool allow_non_immediate_owner = ( chain_time >= HARDFORK_1002_TIME );
|
||||
|
||||
set<public_key_type> result;
|
||||
|
||||
trx.get_required_signatures(
|
||||
_db.get_chain_id(),
|
||||
flat_set<public_key_type>(),
|
||||
|
|
@ -1812,15 +1819,28 @@ set<public_key_type> database_api_impl::get_potential_signatures( const signed_t
|
|||
result.insert(k);
|
||||
return &auth;
|
||||
},
|
||||
allow_non_immediate_owner,
|
||||
_db.get_global_properties().parameters.max_authority_depth
|
||||
);
|
||||
|
||||
// Insert keys in required "other" authories
|
||||
flat_set<account_id_type> required_active;
|
||||
flat_set<account_id_type> required_owner;
|
||||
vector<authority> other;
|
||||
trx.get_required_authorities( required_active, required_owner, other );
|
||||
for( const auto& auth : other )
|
||||
for( const auto& key : auth.get_keys() )
|
||||
result.insert( key );
|
||||
|
||||
wdump((result));
|
||||
return result;
|
||||
}
|
||||
|
||||
set<address> database_api_impl::get_potential_address_signatures( const signed_transaction& trx )const
|
||||
{
|
||||
auto chain_time = _db.head_block_time();
|
||||
bool allow_non_immediate_owner = ( chain_time >= HARDFORK_1002_TIME );
|
||||
|
||||
set<address> result;
|
||||
trx.get_required_signatures(
|
||||
_db.get_chain_id(),
|
||||
|
|
@ -1839,6 +1859,7 @@ set<address> database_api_impl::get_potential_address_signatures( const signed_t
|
|||
result.insert(k);
|
||||
return &auth;
|
||||
},
|
||||
allow_non_immediate_owner,
|
||||
_db.get_global_properties().parameters.max_authority_depth
|
||||
);
|
||||
return result;
|
||||
|
|
@ -1851,9 +1872,11 @@ bool database_api::verify_authority( const signed_transaction& trx )const
|
|||
|
||||
bool database_api_impl::verify_authority( const signed_transaction& trx )const
|
||||
{
|
||||
bool allow_non_immediate_owner = ( _db.head_block_time() >= HARDFORK_1002_TIME );
|
||||
trx.verify_authority( _db.get_chain_id(),
|
||||
[&]( account_id_type id ){ return &id(_db).active; },
|
||||
[&]( account_id_type id ){ return &id(_db).owner; },
|
||||
allow_non_immediate_owner,
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -680,9 +680,10 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
|||
|
||||
if( !(skip & (skip_transaction_signatures | skip_authority_check) ) )
|
||||
{
|
||||
bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_1002_TIME );
|
||||
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( chain_id, get_active, get_owner, get_global_properties().parameters.max_authority_depth );
|
||||
trx.verify_authority( chain_id, get_active, get_owner, allow_non_immediate_owner, get_global_properties().parameters.max_authority_depth );
|
||||
}
|
||||
|
||||
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
||||
|
|
|
|||
7
libraries/chain/hardfork.d/1002.hf
Normal file
7
libraries/chain/hardfork.d/1002.hf
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// added transaction size check
|
||||
// Bug fix of update commitee member update
|
||||
// bitshares-core issue #584 Owner keys of non-immediately required accounts can not authorize a transaction
|
||||
// https://github.com/bitshares/bitshares-core/issues/584
|
||||
#ifndef HARDFORK_1002_TIME
|
||||
#define HARDFORK_1002_TIME (fc::time_point_sec( 1567488600 )) //Tuesday, 3 September 2019 05:30:00 GMT
|
||||
#endif
|
||||
|
|
@ -141,13 +141,27 @@ namespace graphene { namespace chain {
|
|||
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,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
)const;
|
||||
|
||||
/**
|
||||
* Checks whether signatures in this signed transaction are sufficient to authorize the transaction.
|
||||
* Throws an exception when failed.
|
||||
*
|
||||
* @param chain_id the ID of a block chain
|
||||
* @param get_active callback function to retrieve active authorities of a given account
|
||||
* @param get_owner callback function to retrieve owner authorities of a given account
|
||||
* @param allow_non_immediate_owner whether to allow owner authority of non-immediately
|
||||
* required accounts to authorize operations in the transaction
|
||||
* @param max_recursion maximum level of recursion when verifying, since an account
|
||||
* can have another account in active authorities and/or owner authorities
|
||||
*/
|
||||
void verify_authority(
|
||||
const chain_id_type& chain_id,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;
|
||||
|
||||
/**
|
||||
|
|
@ -162,6 +176,7 @@ namespace graphene { namespace chain {
|
|||
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,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
) const;
|
||||
|
||||
|
|
@ -171,11 +186,31 @@ namespace graphene { namespace chain {
|
|||
|
||||
/// Removes all operations and signatures
|
||||
void clear() { operations.clear(); signatures.clear(); }
|
||||
|
||||
/** Removes all signatures */
|
||||
void clear_signatures() { signatures.clear(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether given public keys and approvals are sufficient to authorize given operations.
|
||||
* Throws an exception when failed.
|
||||
*
|
||||
* @param ops a vector of operations
|
||||
* @param sigs a set of public keys
|
||||
* @param get_active callback function to retrieve active authorities of a given account
|
||||
* @param get_owner callback function to retrieve owner authorities of a given account
|
||||
* @param allow_non_immediate_owner whether to allow owner authority of non-immediately
|
||||
* required accounts to authorize operations
|
||||
* @param max_recursion maximum level of recursion when verifying, since an account
|
||||
* can have another account in active authorities and/or owner authorities
|
||||
* @param allow_committee whether to allow the special "committee account" to authorize the operations
|
||||
* @param active_approvals accounts that approved the operations with their active authories
|
||||
* @param owner_approvals accounts that approved the operations with their owner authories
|
||||
*/
|
||||
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,
|
||||
bool allow_non_immediate_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>(),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -32,10 +33,12 @@ bool proposal_object::is_authorized_to_execute(database& db) const
|
|||
transaction_evaluation_state dry_run_eval(&db);
|
||||
|
||||
try {
|
||||
bool allow_non_immediate_owner = ( db.head_block_time() >= HARDFORK_1002_TIME );
|
||||
verify_authority( proposed_transaction.operations,
|
||||
available_key_approvals,
|
||||
[&]( account_id_type id ){ return &id(db).active; },
|
||||
[&]( account_id_type id ){ return &id(db).owner; },
|
||||
allow_non_immediate_owner,
|
||||
db.get_global_properties().parameters.max_authority_depth,
|
||||
true, /* allow committeee */
|
||||
available_active_approvals,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ void transaction::get_required_authorities( flat_set<account_id_type>& active, f
|
|||
{
|
||||
for( const auto& op : operations )
|
||||
operation_get_required_authorities( op, active, owner, other );
|
||||
for( const auto& account : owner )
|
||||
active.erase( account );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -159,7 +161,7 @@ struct sign_state
|
|||
bool check_authority( account_id_type id )
|
||||
{
|
||||
if( approved_by.find(id) != approved_by.end() ) return true;
|
||||
return check_authority( get_active(id) );
|
||||
return check_authority( get_active(id) ) || ( allow_non_immediate_owner && check_authority( get_owner(id) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -194,7 +196,8 @@ struct sign_state
|
|||
{
|
||||
if( depth == max_recursion )
|
||||
continue;
|
||||
if( check_authority( get_active( a.first ), depth+1 ) )
|
||||
if( check_authority( get_active( a.first ), depth+1 )
|
||||
|| ( allow_non_immediate_owner && check_authority( get_owner( a.first ), depth+1 ) ) )
|
||||
{
|
||||
approved_by.insert( a.first );
|
||||
total_weight += a.second;
|
||||
|
|
@ -225,9 +228,16 @@ struct sign_state
|
|||
}
|
||||
|
||||
sign_state( const flat_set<public_key_type>& sigs,
|
||||
const std::function<const authority*(account_id_type)>& a,
|
||||
const std::function<const authority*(account_id_type)>& active,
|
||||
const std::function<const authority*(account_id_type)>& owner,
|
||||
bool allow_owner,
|
||||
uint32_t max_recursion_depth = GRAPHENE_MAX_SIG_CHECK_DEPTH,
|
||||
const flat_set<public_key_type>& keys = flat_set<public_key_type>() )
|
||||
:get_active(a),available_keys(keys)
|
||||
: get_active(active),
|
||||
get_owner(owner),
|
||||
allow_non_immediate_owner(allow_owner),
|
||||
max_recursion(max_recursion_depth),
|
||||
available_keys(keys)
|
||||
{
|
||||
for( const auto& key : sigs )
|
||||
provided_signatures[ key ] = false;
|
||||
|
|
@ -235,17 +245,20 @@ struct sign_state
|
|||
}
|
||||
|
||||
const std::function<const authority*(account_id_type)>& get_active;
|
||||
const flat_set<public_key_type>& available_keys;
|
||||
const std::function<const authority*(account_id_type)>& get_owner;
|
||||
const bool allow_non_immediate_owner;
|
||||
const uint32_t max_recursion;
|
||||
const flat_set<public_key_type>& available_keys;
|
||||
|
||||
flat_map<public_key_type,bool> provided_signatures;
|
||||
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,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion_depth,
|
||||
bool allow_committe,
|
||||
const flat_set<account_id_type>& active_aprovals,
|
||||
|
|
@ -262,8 +275,7 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
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);
|
||||
s.max_recursion = max_recursion_depth;
|
||||
sign_state s( sigs, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth );
|
||||
for( auto& id : active_aprovals )
|
||||
s.approved_by.insert( id );
|
||||
for( auto& id : owner_approvals )
|
||||
|
|
@ -318,6 +330,7 @@ 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,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion_depth )const
|
||||
{
|
||||
flat_set<account_id_type> required_active;
|
||||
|
|
@ -325,23 +338,23 @@ set<public_key_type> signed_transaction::get_required_signatures(
|
|||
vector<authority> other;
|
||||
get_required_authorities( required_active, required_owner, other );
|
||||
|
||||
|
||||
sign_state s(get_signature_keys( chain_id ),get_active,available_keys);
|
||||
s.max_recursion = max_recursion_depth;
|
||||
const flat_set<public_key_type>& signature_keys = get_signature_keys(chain_id);
|
||||
sign_state s( signature_keys, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth, 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.check_authority( active ) || s.check_authority( get_owner( 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() )
|
||||
if( available_keys.find( provided_sig.first ) != available_keys.end()
|
||||
&& signature_keys.find( provided_sig.first ) == signature_keys.end() )
|
||||
result.insert( provided_sig.first );
|
||||
|
||||
return result;
|
||||
|
|
@ -352,6 +365,7 @@ set<public_key_type> signed_transaction::minimize_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,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion
|
||||
) const
|
||||
{
|
||||
|
|
@ -363,7 +377,7 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
|
|||
result.erase( k );
|
||||
try
|
||||
{
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, allow_non_immediate_owner, max_recursion );
|
||||
continue; // element stays erased if verify_authority is ok
|
||||
}
|
||||
catch( const tx_missing_owner_auth& e ) {}
|
||||
|
|
@ -378,9 +392,15 @@ void signed_transaction::verify_authority(
|
|||
const chain_id_type& chain_id,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
bool allow_non_immediate_owner,
|
||||
uint32_t max_recursion )const
|
||||
{ try {
|
||||
graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
|
||||
graphene::chain::verify_authority( operations,
|
||||
get_signature_keys( chain_id ),
|
||||
get_active,
|
||||
get_owner,
|
||||
allow_non_immediate_owner,
|
||||
max_recursion );
|
||||
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/committee_member_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
#include <graphene/db/simple_index.hpp>
|
||||
|
||||
|
|
@ -79,7 +80,10 @@ BOOST_AUTO_TEST_CASE( any_two_of_three )
|
|||
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.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);
|
||||
|
|
@ -1159,10 +1163,12 @@ BOOST_FIXTURE_TEST_CASE( get_required_signatures_test, database_fixture )
|
|||
set<public_key_type> ref_set
|
||||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, false );
|
||||
set<public_key_type> result_set2 = tx.get_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, true );
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
set_auth( well_id, authority( 60, alice_id, 50, bob_id, 50 ) );
|
||||
|
|
@ -1273,10 +1279,12 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
set<public_key_type> ref_set
|
||||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, false );
|
||||
set<public_key_type> result_set2 = tx.get_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, true );
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
auto chk_min = [&](
|
||||
|
|
@ -1285,10 +1293,12 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
set<public_key_type> ref_set
|
||||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, false );
|
||||
set<public_key_type> result_set2 = tx.minimize_required_signatures( db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, true );
|
||||
//wdump( (result_set)(result_set2)(ref_set) );
|
||||
return result_set == ref_set && result_set2 == ref_set;
|
||||
} ;
|
||||
|
||||
set_auth( roco_id, authority( 2, styx_id, 1, thud_id, 2 ) );
|
||||
|
|
@ -1305,9 +1315,510 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
BOOST_CHECK( chk( tx, { alice_public_key, bob_public_key }, { alice_public_key, bob_public_key } ) );
|
||||
BOOST_CHECK( chk_min( tx, { alice_public_key, bob_public_key }, { alice_public_key } ) );
|
||||
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner ), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), fc::exception );
|
||||
sign( tx, alice_private_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true );
|
||||
}
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Active vs Owner https://github.com/bitshares/bitshares-core/issues/584
|
||||
*
|
||||
* All weights and all thresholds are 1, so every single key should be able to sign if within max_depth
|
||||
*
|
||||
* Bob --+--(a)--+-- Alice --+--(a)--+-- Daisy --(a/o)-- Daisy_active_key / Daisy_owner_key
|
||||
* | | | |
|
||||
* | | | +-- Alice_active_key
|
||||
* | | |
|
||||
* | | +--(o)--+-- Cindy --(a/o)-- Cindy_active_key / Cindy_owner_key
|
||||
* | | |
|
||||
* | | +-- Alice_owner_key
|
||||
* | |
|
||||
* | +-- Bob_active_key
|
||||
* |
|
||||
* +--(o)--+-- Edwin --+--(a)--+-- Gavin --(a/o)-- Gavin_active_key / Gavin_owner_key
|
||||
* | | |
|
||||
* | | +-- Edwin_active_key
|
||||
* | |
|
||||
* | +--(o)--+-- Frank --(a/o)-- Frank_active_key / Frank_owner_key
|
||||
* | |
|
||||
* | +-- Edwin_owner_key
|
||||
* |
|
||||
* +-- Bob_owner_key
|
||||
*/
|
||||
BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture )
|
||||
{
|
||||
try
|
||||
{
|
||||
ACTORS(
|
||||
(alice)(bob)(cindy)(daisy)(edwin)(frank)(gavin)
|
||||
);
|
||||
|
||||
transfer( account_id_type(), bob_id, asset(100000) );
|
||||
|
||||
auto set_auth = [&](
|
||||
account_id_type aid,
|
||||
const authority& active,
|
||||
const authority& owner
|
||||
)
|
||||
{
|
||||
signed_transaction tx;
|
||||
account_update_operation op;
|
||||
op.account = aid;
|
||||
op.active = active;
|
||||
op.owner = owner;
|
||||
tx.operations.push_back( op );
|
||||
set_expiration( db, tx );
|
||||
PUSH_TX( db, tx, database::skip_transaction_signatures );
|
||||
} ;
|
||||
|
||||
auto get_active = [&](
|
||||
account_id_type aid
|
||||
) -> const authority*
|
||||
{
|
||||
return &(aid(db).active);
|
||||
} ;
|
||||
|
||||
auto get_owner = [&](
|
||||
account_id_type aid
|
||||
) -> const authority*
|
||||
{
|
||||
return &(aid(db).owner);
|
||||
} ;
|
||||
|
||||
auto chk = [&](
|
||||
const signed_transaction& tx,
|
||||
bool after_hf_584,
|
||||
flat_set<public_key_type> available_keys,
|
||||
set<public_key_type> ref_set
|
||||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures(db.get_chain_id(), available_keys,
|
||||
get_active, get_owner, after_hf_584);
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
} ;
|
||||
|
||||
fc::ecc::private_key alice_active_key = fc::ecc::private_key::regenerate(fc::digest("alice_active"));
|
||||
fc::ecc::private_key alice_owner_key = fc::ecc::private_key::regenerate(fc::digest("alice_owner"));
|
||||
fc::ecc::private_key bob_active_key = fc::ecc::private_key::regenerate(fc::digest("bob_active"));
|
||||
fc::ecc::private_key bob_owner_key = fc::ecc::private_key::regenerate(fc::digest("bob_owner"));
|
||||
fc::ecc::private_key cindy_active_key = fc::ecc::private_key::regenerate(fc::digest("cindy_active"));
|
||||
fc::ecc::private_key cindy_owner_key = fc::ecc::private_key::regenerate(fc::digest("cindy_owner"));
|
||||
fc::ecc::private_key daisy_active_key = fc::ecc::private_key::regenerate(fc::digest("daisy_active"));
|
||||
fc::ecc::private_key daisy_owner_key = fc::ecc::private_key::regenerate(fc::digest("daisy_owner"));
|
||||
fc::ecc::private_key edwin_active_key = fc::ecc::private_key::regenerate(fc::digest("edwin_active"));
|
||||
fc::ecc::private_key edwin_owner_key = fc::ecc::private_key::regenerate(fc::digest("edwin_owner"));
|
||||
fc::ecc::private_key frank_active_key = fc::ecc::private_key::regenerate(fc::digest("frank_active"));
|
||||
fc::ecc::private_key frank_owner_key = fc::ecc::private_key::regenerate(fc::digest("frank_owner"));
|
||||
fc::ecc::private_key gavin_active_key = fc::ecc::private_key::regenerate(fc::digest("gavin_active"));
|
||||
fc::ecc::private_key gavin_owner_key = fc::ecc::private_key::regenerate(fc::digest("gavin_owner"));
|
||||
|
||||
public_key_type alice_active_pub( alice_active_key.get_public_key() );
|
||||
public_key_type alice_owner_pub( alice_owner_key.get_public_key() );
|
||||
public_key_type bob_active_pub( bob_active_key.get_public_key() );
|
||||
public_key_type bob_owner_pub( bob_owner_key.get_public_key() );
|
||||
public_key_type cindy_active_pub( cindy_active_key.get_public_key() );
|
||||
public_key_type cindy_owner_pub( cindy_owner_key.get_public_key() );
|
||||
public_key_type daisy_active_pub( daisy_active_key.get_public_key() );
|
||||
public_key_type daisy_owner_pub( daisy_owner_key.get_public_key() );
|
||||
public_key_type edwin_active_pub( edwin_active_key.get_public_key() );
|
||||
public_key_type edwin_owner_pub( edwin_owner_key.get_public_key() );
|
||||
public_key_type frank_active_pub( frank_active_key.get_public_key() );
|
||||
public_key_type frank_owner_pub( frank_owner_key.get_public_key() );
|
||||
public_key_type gavin_active_pub( gavin_active_key.get_public_key() );
|
||||
public_key_type gavin_owner_pub( gavin_owner_key.get_public_key() );
|
||||
|
||||
set_auth( alice_id, authority( 1, alice_active_pub, 1, daisy_id, 1 ), authority( 1, alice_owner_pub, 1, cindy_id, 1 ) );
|
||||
set_auth( bob_id, authority( 1, bob_active_pub, 1, alice_id, 1 ), authority( 1, bob_owner_pub, 1, edwin_id, 1 ) );
|
||||
|
||||
set_auth( cindy_id, authority( 1, cindy_active_pub, 1 ), authority( 1, cindy_owner_pub, 1 ) );
|
||||
set_auth( daisy_id, authority( 1, daisy_active_pub, 1 ), authority( 1, daisy_owner_pub, 1 ) );
|
||||
|
||||
set_auth( edwin_id, authority( 1, edwin_active_pub, 1, gavin_id, 1 ), authority( 1, edwin_owner_pub, 1, frank_id, 1 ) );
|
||||
|
||||
set_auth( frank_id, authority( 1, frank_active_pub, 1 ), authority( 1, frank_owner_pub, 1 ) );
|
||||
set_auth( gavin_id, authority( 1, gavin_active_pub, 1 ), authority( 1, gavin_owner_pub, 1 ) );
|
||||
|
||||
generate_block();
|
||||
|
||||
signed_transaction tx;
|
||||
transfer_operation op;
|
||||
op.from = bob_id;
|
||||
op.to = alice_id;
|
||||
op.amount = asset(1);
|
||||
tx.operations.push_back( op );
|
||||
set_expiration( db, tx );
|
||||
|
||||
// https://github.com/bitshares/bitshares-core/issues/584
|
||||
// If not allow non-immediate owner to authorize
|
||||
BOOST_CHECK( chk( tx, false, { alice_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { alice_active_pub }, { alice_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { alice_active_pub, alice_owner_pub }, { alice_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { bob_owner_pub }, { bob_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { bob_active_pub }, { bob_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { bob_active_pub, bob_owner_pub }, { bob_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { cindy_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { cindy_active_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { cindy_active_pub, cindy_owner_pub }, { } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { daisy_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { daisy_active_pub }, { daisy_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { daisy_active_pub, daisy_owner_pub }, { daisy_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { edwin_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { edwin_active_pub }, { edwin_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { edwin_active_pub, edwin_owner_pub }, { edwin_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { frank_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { frank_active_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { frank_active_pub, frank_owner_pub }, { } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, false, { gavin_owner_pub }, { } ) );
|
||||
BOOST_CHECK( chk( tx, false, { gavin_active_pub }, { gavin_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, false, { gavin_active_pub, gavin_owner_pub }, { gavin_active_pub } ) );
|
||||
|
||||
// If allow non-immediate owner to authorize
|
||||
BOOST_CHECK( chk( tx, true, { alice_owner_pub }, { alice_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { alice_active_pub }, { alice_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { alice_active_pub, alice_owner_pub }, { alice_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { bob_owner_pub }, { bob_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { bob_active_pub }, { bob_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { bob_active_pub, bob_owner_pub }, { bob_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { cindy_owner_pub }, { cindy_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { cindy_active_pub }, { cindy_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { cindy_active_pub, cindy_owner_pub }, { cindy_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { daisy_owner_pub }, { daisy_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { daisy_active_pub }, { daisy_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { daisy_active_pub, daisy_owner_pub }, { daisy_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { edwin_owner_pub }, { edwin_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { edwin_active_pub }, { edwin_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { edwin_active_pub, edwin_owner_pub }, { edwin_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { frank_owner_pub }, { frank_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { frank_active_pub }, { frank_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { frank_active_pub, frank_owner_pub }, { frank_active_pub } ) );
|
||||
|
||||
BOOST_CHECK( chk( tx, true, { gavin_owner_pub }, { gavin_owner_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { gavin_active_pub }, { gavin_active_pub } ) );
|
||||
BOOST_CHECK( chk( tx, true, { gavin_active_pub, gavin_owner_pub }, { gavin_active_pub } ) );
|
||||
|
||||
sign( tx, alice_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, alice_active_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, bob_owner_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, bob_active_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, cindy_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, cindy_active_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, daisy_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, daisy_active_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, edwin_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, edwin_active_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, frank_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, frank_active_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, gavin_owner_key );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, gavin_active_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, false);
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, true);
|
||||
tx.clear_signatures();
|
||||
|
||||
// proposal tests
|
||||
auto new_proposal = [&]() -> proposal_id_type {
|
||||
signed_transaction ptx;
|
||||
|
||||
proposal_create_operation pop;
|
||||
pop.proposed_ops.emplace_back(op);
|
||||
pop.fee_paying_account = bob_id;
|
||||
pop.expiration_time = db.head_block_time() + fc::days(1);
|
||||
ptx.operations.push_back(pop);
|
||||
set_expiration( db, ptx );
|
||||
sign( ptx, bob_active_key );
|
||||
|
||||
return PUSH_TX( db, ptx, database::skip_transaction_dupe_check ).operation_results[0].get<object_id_type>();
|
||||
};
|
||||
|
||||
auto approve_proposal = [&](
|
||||
proposal_id_type proposal,
|
||||
account_id_type account,
|
||||
bool approve_with_owner,
|
||||
fc::ecc::private_key key
|
||||
)
|
||||
{
|
||||
signed_transaction ptx;
|
||||
|
||||
proposal_update_operation pup;
|
||||
pup.fee_paying_account = account;
|
||||
pup.proposal = proposal;
|
||||
if( approve_with_owner )
|
||||
pup.owner_approvals_to_add.insert( account );
|
||||
else
|
||||
pup.active_approvals_to_add.insert( account );
|
||||
ptx.operations.push_back(pup);
|
||||
set_expiration( db, ptx );
|
||||
sign( ptx, key );
|
||||
PUSH_TX( db, ptx, database::skip_transaction_dupe_check );
|
||||
};
|
||||
|
||||
proposal_id_type pid;
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, alice_id, true, alice_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, alice_id, false, alice_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, bob_id, true, bob_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, bob_id, false, bob_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
// Cindy's approval doesn't work
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, cindy_id, true, cindy_owner_key );
|
||||
BOOST_CHECK( db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, cindy_id, false, cindy_active_key );
|
||||
BOOST_CHECK( db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, daisy_id, true, daisy_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, daisy_id, false, daisy_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, edwin_id, true, edwin_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, edwin_id, false, edwin_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
// Frank's approval doesn't work
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, frank_id, true, frank_owner_key );
|
||||
BOOST_CHECK( db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, frank_id, false, frank_active_key );
|
||||
BOOST_CHECK( db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, gavin_id, true, gavin_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, gavin_id, false, gavin_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
generate_block( database::skip_transaction_dupe_check );
|
||||
|
||||
// pass the hard fork time
|
||||
generate_blocks( HARDFORK_1002_TIME, true, database::skip_transaction_dupe_check );
|
||||
set_expiration( db, tx );
|
||||
|
||||
// signing tests
|
||||
sign( tx, alice_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, alice_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, bob_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, bob_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, cindy_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, cindy_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, daisy_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, daisy_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, edwin_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, edwin_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, frank_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, frank_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, gavin_owner_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
sign( tx, gavin_active_key );
|
||||
PUSH_TX( db, tx, database::skip_transaction_dupe_check );
|
||||
tx.clear_signatures();
|
||||
|
||||
// proposal tests
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, alice_id, true, alice_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, alice_id, false, alice_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, bob_id, true, bob_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, bob_id, false, bob_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, cindy_id, true, cindy_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, cindy_id, false, cindy_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, daisy_id, true, daisy_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, daisy_id, false, daisy_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, edwin_id, true, edwin_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, edwin_id, false, edwin_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, frank_id, true, frank_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, frank_id, false, frank_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, gavin_id, true, gavin_owner_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
pid = new_proposal();
|
||||
approve_proposal( pid, gavin_id, false, gavin_active_key );
|
||||
BOOST_CHECK( !db.find( pid ) );
|
||||
|
||||
generate_block( database::skip_transaction_dupe_check );
|
||||
}
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <graphene/app/database_api.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
|
|
@ -68,4 +71,682 @@ BOOST_FIXTURE_TEST_SUITE(database_api_tests, database_fixture)
|
|||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( get_potential_signatures_owner_and_active )
|
||||
{
|
||||
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"));
|
||||
public_key_type pub_key_active( nathan_key1.get_public_key() );
|
||||
public_key_type pub_key_owner( nathan_key2.get_public_key() );
|
||||
const account_object& nathan = create_account("nathan", nathan_key1.get_public_key() );
|
||||
|
||||
try {
|
||||
account_update_operation op;
|
||||
op.account = nathan.id;
|
||||
op.active = authority(1, pub_key_active, 1);
|
||||
op.owner = authority(1, pub_key_owner, 1);
|
||||
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))
|
||||
|
||||
// this op requires active
|
||||
transfer_operation op;
|
||||
op.from = nathan.id;
|
||||
op.to = account_id_type();
|
||||
trx.operations.push_back(op);
|
||||
|
||||
graphene::app::database_api db_api(db);
|
||||
set<public_key_type> pub_keys = db_api.get_potential_signatures( trx );
|
||||
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
trx.operations.clear();
|
||||
|
||||
// this op requires owner
|
||||
account_update_operation auop;
|
||||
auop.account = nathan.id;
|
||||
auop.owner = authority(1, pub_key_owner, 1);
|
||||
trx.operations.push_back(auop);
|
||||
|
||||
pub_keys = db_api.get_potential_signatures( trx );
|
||||
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) == pub_keys.end() ); // active key doesn't help in this case
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
/// Testing get_potential_signatures and get_required_signatures for non-immediate owner authority issue.
|
||||
/// https://github.com/bitshares/bitshares-core/issues/584
|
||||
BOOST_AUTO_TEST_CASE( get_signatures_non_immediate_owner )
|
||||
{
|
||||
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 ashley_key1 = fc::ecc::private_key::regenerate(fc::digest("akey1"));
|
||||
fc::ecc::private_key ashley_key2 = fc::ecc::private_key::regenerate(fc::digest("akey2"));
|
||||
fc::ecc::private_key oliver_key1 = fc::ecc::private_key::regenerate(fc::digest("okey1"));
|
||||
fc::ecc::private_key oliver_key2 = fc::ecc::private_key::regenerate(fc::digest("okey2"));
|
||||
public_key_type pub_key_active( nathan_key1.get_public_key() );
|
||||
public_key_type pub_key_owner( nathan_key2.get_public_key() );
|
||||
public_key_type a_pub_key_active( ashley_key1.get_public_key() );
|
||||
public_key_type a_pub_key_owner( ashley_key2.get_public_key() );
|
||||
public_key_type o_pub_key_active( oliver_key1.get_public_key() );
|
||||
public_key_type o_pub_key_owner( oliver_key2.get_public_key() );
|
||||
const account_object& nathan = create_account("nathan", nathan_key1.get_public_key() );
|
||||
const account_object& ashley = create_account("ashley", ashley_key1.get_public_key() );
|
||||
const account_object& oliver = create_account("oliver", oliver_key1.get_public_key() );
|
||||
account_id_type nathan_id = nathan.id;
|
||||
account_id_type ashley_id = ashley.id;
|
||||
account_id_type oliver_id = oliver.id;
|
||||
|
||||
try {
|
||||
account_update_operation op;
|
||||
op.account = nathan_id;
|
||||
op.active = authority(1, pub_key_active, 1, ashley_id, 1);
|
||||
op.owner = authority(1, pub_key_owner, 1, oliver_id, 1);
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, nathan_key1);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
trx.clear();
|
||||
|
||||
op.account = ashley_id;
|
||||
op.active = authority(1, a_pub_key_active, 1);
|
||||
op.owner = authority(1, a_pub_key_owner, 1);
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, ashley_key1);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
trx.clear();
|
||||
|
||||
op.account = oliver_id;
|
||||
op.active = authority(1, o_pub_key_active, 1);
|
||||
op.owner = authority(1, o_pub_key_owner, 1);
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, oliver_key1);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
trx.clear();
|
||||
} FC_CAPTURE_AND_RETHROW ((nathan.active))
|
||||
|
||||
// this transaction requires active
|
||||
signed_transaction trx_a;
|
||||
transfer_operation op;
|
||||
op.from = nathan_id;
|
||||
op.to = account_id_type();
|
||||
trx_a.operations.push_back(op);
|
||||
|
||||
// get potential signatures
|
||||
graphene::app::database_api db_api(db);
|
||||
set<public_key_type> pub_keys = db_api.get_potential_signatures( trx_a );
|
||||
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_active ) != pub_keys.end() );
|
||||
// doesn't work due to https://github.com/bitshares/bitshares-core/issues/584
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_active ) != pub_keys.end() );
|
||||
// doesn't work due to https://github.com/bitshares/bitshares-core/issues/584
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) == pub_keys.end() );
|
||||
|
||||
// get required signatures
|
||||
pub_keys = db_api.get_required_signatures( trx_a, { a_pub_key_owner, o_pub_key_owner } );
|
||||
BOOST_CHECK( pub_keys.empty() );
|
||||
|
||||
// this op requires owner
|
||||
signed_transaction trx_o;
|
||||
account_update_operation auop;
|
||||
auop.account = nathan_id;
|
||||
auop.owner = authority(1, pub_key_owner, 1);
|
||||
trx_o.operations.push_back(auop);
|
||||
|
||||
// get potential signatures
|
||||
pub_keys = db_api.get_potential_signatures( trx_o );
|
||||
|
||||
// active authorities doesn't help in this case
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_active ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) == pub_keys.end() );
|
||||
|
||||
// owner authorities should be ok
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_active ) != pub_keys.end() );
|
||||
// doesn't work due to https://github.com/bitshares/bitshares-core/issues/584
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) == pub_keys.end() );
|
||||
|
||||
// get required signatures
|
||||
pub_keys = db_api.get_required_signatures( trx_o, { a_pub_key_owner, o_pub_key_owner } );
|
||||
BOOST_CHECK( pub_keys.empty() );
|
||||
|
||||
// go beyond hard fork
|
||||
generate_blocks( HARDFORK_1002_TIME, true );
|
||||
|
||||
// for the transaction that requires active
|
||||
// get potential signatures
|
||||
pub_keys = db_api.get_potential_signatures( trx_a );
|
||||
|
||||
// all authorities should be ok
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
// get required signatures
|
||||
pub_keys = db_api.get_required_signatures( trx_a, { a_pub_key_owner } );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) != pub_keys.end() );
|
||||
pub_keys = db_api.get_required_signatures( trx_a, { o_pub_key_owner } );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
// for the transaction that requires owner
|
||||
// get potential signatures
|
||||
pub_keys = db_api.get_potential_signatures( trx_o );
|
||||
|
||||
// active authorities doesn't help in this case
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_active ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) == pub_keys.end() );
|
||||
|
||||
// owner authorities should help
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_active ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
// get required signatures
|
||||
pub_keys = db_api.get_required_signatures( trx_o, { a_pub_key_owner, o_pub_key_owner } );
|
||||
BOOST_CHECK( pub_keys.find( a_pub_key_owner ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( o_pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( get_potential_signatures_other )
|
||||
{
|
||||
try {
|
||||
fc::ecc::private_key priv_key1 = fc::ecc::private_key::regenerate(fc::digest("key1"));
|
||||
public_key_type pub_key1( priv_key1.get_public_key() );
|
||||
|
||||
const account_object& nathan = create_account( "nathan" );
|
||||
|
||||
balance_claim_operation op;
|
||||
op.deposit_to_account = nathan.id;
|
||||
op.balance_owner_key = pub_key1;
|
||||
trx.operations.push_back(op);
|
||||
|
||||
graphene::app::database_api db_api(db);
|
||||
set<public_key_type> pub_keys = db_api.get_potential_signatures( trx );
|
||||
|
||||
BOOST_CHECK( pub_keys.find( pub_key1 ) != pub_keys.end() );
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( get_required_signatures_owner_or_active )
|
||||
{
|
||||
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"));
|
||||
public_key_type pub_key_active( nathan_key1.get_public_key() );
|
||||
public_key_type pub_key_owner( nathan_key2.get_public_key() );
|
||||
const account_object& nathan = create_account("nathan", nathan_key1.get_public_key() );
|
||||
|
||||
try {
|
||||
account_update_operation op;
|
||||
op.account = nathan.id;
|
||||
op.active = authority(1, pub_key_active, 1);
|
||||
op.owner = authority(1, pub_key_owner, 1);
|
||||
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))
|
||||
|
||||
graphene::app::database_api db_api(db);
|
||||
|
||||
// prepare available keys sets
|
||||
flat_set<public_key_type> avail_keys1, avail_keys2, avail_keys3;
|
||||
avail_keys1.insert( pub_key_active );
|
||||
avail_keys2.insert( pub_key_owner );
|
||||
avail_keys3.insert( pub_key_active );
|
||||
avail_keys3.insert( pub_key_owner );
|
||||
|
||||
set<public_key_type> pub_keys;
|
||||
|
||||
// this op requires active
|
||||
transfer_operation op;
|
||||
op.from = nathan.id;
|
||||
op.to = account_id_type();
|
||||
trx.operations.push_back(op);
|
||||
|
||||
// provides active, should be ok
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) != pub_keys.end() );
|
||||
|
||||
// provides owner, should be ok
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
// provides both active and owner, should return one of them
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys3 );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) != pub_keys.end() || pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
trx.operations.clear();
|
||||
|
||||
// this op requires owner
|
||||
account_update_operation auop;
|
||||
auop.account = nathan.id;
|
||||
auop.owner = authority(1, pub_key_owner, 1);
|
||||
trx.operations.push_back(auop);
|
||||
|
||||
// provides active, should return an empty set
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys1 );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides owner, should return it
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
// provides both active and owner, should return owner only
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys3 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_active ) == pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_owner ) != pub_keys.end() );
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( get_required_signatures_partially_signed_or_not )
|
||||
{
|
||||
try {
|
||||
fc::ecc::private_key morgan_key = fc::ecc::private_key::regenerate(fc::digest("morgan_key"));
|
||||
fc::ecc::private_key nathan_key = fc::ecc::private_key::regenerate(fc::digest("nathan_key"));
|
||||
fc::ecc::private_key oliver_key = fc::ecc::private_key::regenerate(fc::digest("oliver_key"));
|
||||
public_key_type pub_key_morgan( morgan_key.get_public_key() );
|
||||
public_key_type pub_key_nathan( nathan_key.get_public_key() );
|
||||
public_key_type pub_key_oliver( oliver_key.get_public_key() );
|
||||
const account_object& morgan = create_account("morgan", morgan_key.get_public_key() );
|
||||
const account_object& nathan = create_account("nathan", nathan_key.get_public_key() );
|
||||
const account_object& oliver = create_account("oliver", oliver_key.get_public_key() );
|
||||
|
||||
graphene::app::database_api db_api(db);
|
||||
|
||||
// prepare available keys sets
|
||||
flat_set<public_key_type> avail_keys_empty, avail_keys_m, avail_keys_n, avail_keys_o;
|
||||
flat_set<public_key_type> avail_keys_mn, avail_keys_mo, avail_keys_no, avail_keys_mno;
|
||||
avail_keys_m.insert( pub_key_morgan );
|
||||
avail_keys_mn.insert( pub_key_morgan );
|
||||
avail_keys_mo.insert( pub_key_morgan );
|
||||
avail_keys_mno.insert( pub_key_morgan );
|
||||
avail_keys_n.insert( pub_key_nathan );
|
||||
avail_keys_mn.insert( pub_key_nathan );
|
||||
avail_keys_no.insert( pub_key_nathan );
|
||||
avail_keys_mno.insert( pub_key_nathan );
|
||||
avail_keys_o.insert( pub_key_oliver );
|
||||
avail_keys_mo.insert( pub_key_oliver );
|
||||
avail_keys_no.insert( pub_key_oliver );
|
||||
avail_keys_mno.insert( pub_key_oliver );
|
||||
|
||||
// result set
|
||||
set<public_key_type> pub_keys;
|
||||
|
||||
// make a transaction that require 1 signature (m)
|
||||
transfer_operation op;
|
||||
op.from = morgan.id;
|
||||
op.to = oliver.id;
|
||||
trx.operations.push_back(op);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// sign with n, but actually need m
|
||||
sign(trx, nathan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,o], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n,o], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// sign with m, should be enough
|
||||
trx.clear_signatures();
|
||||
sign(trx, morgan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// sign with m+n, although m only should be enough, this API won't complain
|
||||
sign(trx, nathan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// make a transaction that require 2 signatures (m+n)
|
||||
trx.clear_signatures();
|
||||
op.from = nathan.id;
|
||||
trx.operations.push_back(op);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [m,n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,o], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,n,o], should return [m,n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// sign with o, but actually need m+n
|
||||
sign(trx, oliver_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [m,n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,o], should return [m]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
|
||||
// provides [n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,n,o], should return [m,n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 2 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_morgan ) != pub_keys.end() );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// sign with m+o, but actually need m+n
|
||||
sign(trx, morgan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// sign with m, but actually need m+n
|
||||
trx.clear_signatures();
|
||||
sign(trx, morgan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// provides [m,n,o], should return [n]
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 1 );
|
||||
BOOST_CHECK( pub_keys.find( pub_key_nathan ) != pub_keys.end() );
|
||||
|
||||
// sign with m+n, should be enough
|
||||
sign(trx, nathan_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// sign with m+n+o, should be enough as well
|
||||
sign(trx, oliver_key);
|
||||
|
||||
// provides [], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_empty );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_m );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_n );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_o );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mn );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mo );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_no );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
// provides [m,n,o], should return []
|
||||
pub_keys = db_api.get_required_signatures( trx, avail_keys_mno );
|
||||
BOOST_CHECK( pub_keys.size() == 0 );
|
||||
|
||||
} FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
Loading…
Reference in a new issue