Issues #112 Verifying all signatures are used
- refactor how signatures are stored on the transaction, removing key_id and extra_signatures maps and replacing with a vector - verify that each key only signs one time - update tests to handle stricter policies on signatures
This commit is contained in:
parent
0858018977
commit
e161e5a9fc
12 changed files with 158 additions and 112 deletions
|
|
@ -439,8 +439,8 @@ struct signature_check_visitor
|
|||
{
|
||||
typedef void result_type;
|
||||
|
||||
const signed_transaction& trx;
|
||||
signature_check_visitor( const signed_transaction& t ):trx(t){}
|
||||
flat_map<address,bool>& sigs;
|
||||
signature_check_visitor( flat_map<address,bool>& s ):sigs(s){}
|
||||
|
||||
template<typename T>
|
||||
result_type operator()( const T& o )const{}
|
||||
|
|
@ -448,7 +448,11 @@ struct signature_check_visitor
|
|||
result_type operator()( const balance_claim_operation& o )const
|
||||
{
|
||||
for( auto& owner : o.owners )
|
||||
FC_ASSERT( trx.extra_signatures.find(owner) != trx.extra_signatures.end() );
|
||||
{
|
||||
auto itr = sigs.find(owner);
|
||||
FC_ASSERT( itr != sigs.end() );
|
||||
itr->second = true;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -468,25 +472,12 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
//This check is used only if this transaction has an absolute expiration time.
|
||||
if( !(skip & skip_transaction_signatures) && trx.relative_expiration == 0 )
|
||||
{
|
||||
for( const auto& sig : trx.signatures )
|
||||
{
|
||||
FC_ASSERT( sig.first(*this).key_address() == fc::ecc::public_key( sig.second, trx.digest() ), "",
|
||||
("trx",trx)
|
||||
("digest",trx.digest())
|
||||
("sig.first",sig.first)
|
||||
("key_address",sig.first(*this).key_address())
|
||||
("addr", address(fc::ecc::public_key( sig.second, trx.digest() ))) );
|
||||
}
|
||||
eval_state._sigs.reserve( trx.signatures.size() );
|
||||
|
||||
for( const auto& sig : trx.extra_signatures )
|
||||
{
|
||||
FC_ASSERT( sig.first == address(fc::ecc::public_key( sig.second, trx.digest() )), "",
|
||||
("trx",trx)
|
||||
("digest",trx.digest())
|
||||
("sig.first",sig.first)
|
||||
("addr", address(fc::ecc::public_key( sig.second, trx.digest() ))) );
|
||||
}
|
||||
trx.visit( signature_check_visitor(trx) );
|
||||
for( const auto& sig : trx.signatures )
|
||||
FC_ASSERT( eval_state._sigs.insert( std::make_pair( address(fc::ecc::public_key( sig, trx.digest() )), false) ).second, "Multiple signatures by same key detected" ) ;
|
||||
|
||||
trx.visit( signature_check_visitor(eval_state._sigs) );
|
||||
}
|
||||
|
||||
//If we're skipping tapos check, but not dupe check, assume all transactions have maximum expiration time.
|
||||
|
|
@ -509,15 +500,12 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
//This is the signature check for transactions with relative expiration.
|
||||
if( !(skip & skip_transaction_signatures) )
|
||||
{
|
||||
eval_state._sigs.reserve( trx.signatures.size() );
|
||||
|
||||
for( const auto& sig : trx.signatures )
|
||||
{
|
||||
address trx_addr = fc::ecc::public_key(sig.second, trx.digest(tapos_block_summary.block_id));
|
||||
FC_ASSERT(sig.first(*this).key_address() == trx_addr,
|
||||
"",
|
||||
("sig.first",sig.first)
|
||||
("key_address",sig.first(*this).key_address())
|
||||
("addr", trx_addr));
|
||||
}
|
||||
FC_ASSERT( eval_state._sigs.insert( std::make_pair(address(fc::ecc::public_key( sig, trx.digest(tapos_block_summary.block_id) )),false) ).second, "Multiple signatures by same key detected" ) ;
|
||||
|
||||
trx.visit( signature_check_visitor(eval_state._sigs) );
|
||||
}
|
||||
|
||||
//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
|
||||
|
|
@ -560,11 +548,17 @@ processed_transaction database::_apply_transaction( const signed_transaction& tr
|
|||
auto range = index.equal_range(GRAPHENE_TEMP_ACCOUNT);
|
||||
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
|
||||
|
||||
if( !(skip & (skip_transaction_signatures|skip_authority_check)) )
|
||||
{
|
||||
for( const auto& item : eval_state._sigs )
|
||||
FC_ASSERT( item.second, "All signatures must be used", ("item",item) );
|
||||
}
|
||||
|
||||
return ptrx;
|
||||
} FC_CAPTURE_AND_RETHROW( (trx) ) }
|
||||
|
||||
operation_result database::apply_operation(transaction_evaluation_state& eval_state, const operation& op)
|
||||
{
|
||||
{ try {
|
||||
int i_which = op.which();
|
||||
uint64_t u_which = uint64_t( i_which );
|
||||
if( i_which < 0 )
|
||||
|
|
@ -578,7 +572,7 @@ operation_result database::apply_operation(transaction_evaluation_state& eval_st
|
|||
auto result = eval->evaluate( eval_state, op, true );
|
||||
set_applied_operation_result( op_id, result );
|
||||
return result;
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (eval_state._sigs) ) }
|
||||
|
||||
const witness_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@
|
|||
namespace graphene { namespace chain {
|
||||
database& generic_evaluator::db()const { return trx_state->db(); }
|
||||
operation_result generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
|
||||
{
|
||||
{ try {
|
||||
trx_state = &eval_state;
|
||||
check_required_authorities(op);
|
||||
auto result = evaluate( op );
|
||||
|
||||
if( apply ) result = this->apply( op );
|
||||
return result;
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void generic_evaluator::prepare_fee(account_id_type account_id, asset fee)
|
||||
{
|
||||
|
|
@ -75,11 +75,12 @@ namespace graphene { namespace chain {
|
|||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
bool generic_evaluator::verify_authority( const account_object& a, authority::classification c )
|
||||
{
|
||||
{ try {
|
||||
return trx_state->check_authority( a, c );
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (a)(c) ) }
|
||||
|
||||
void generic_evaluator::check_required_authorities(const operation& op)
|
||||
{
|
||||
{ try {
|
||||
flat_set<account_id_type> active_auths;
|
||||
flat_set<account_id_type> owner_auths;
|
||||
op.visit(operation_get_required_auths(active_auths, owner_auths));
|
||||
|
|
@ -93,7 +94,7 @@ namespace graphene { namespace chain {
|
|||
{
|
||||
FC_ASSERT(verify_authority(id(db()), authority::owner), "", ("id", id));
|
||||
}
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type generic_evaluator::get_relative_id( object_id_type rel_id )const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -147,19 +147,22 @@ namespace graphene { namespace chain {
|
|||
signed_transaction( const transaction& trx = transaction() )
|
||||
: transaction(trx){}
|
||||
|
||||
void sign( key_id_type id, const private_key_type& key );
|
||||
void sign( const address& addr, const private_key_type& key );
|
||||
/** deprecated, TODO: remove when all references are gone */
|
||||
void sign( key_id_type id, const private_key_type& key ) { sign(key); }
|
||||
void sign( const private_key_type& key );
|
||||
|
||||
flat_map<key_id_type,signature_type> signatures;
|
||||
vector<signature_type> signatures;
|
||||
|
||||
// flat_map<key_id_type,signature_type> signatures;
|
||||
|
||||
/** some operations may depend only upon a signature and not
|
||||
* require account approval. This allows those extra signatures
|
||||
* to be added to the transaction.
|
||||
*/
|
||||
flat_map<address,signature_type> extra_signatures;
|
||||
// flat_map<address,signature_type> extra_signatures;
|
||||
|
||||
/// Removes all operations and signatures
|
||||
void clear() { operations.clear(); signatures.clear(); extra_signatures.clear(); }
|
||||
void clear() { operations.clear(); signatures.clear(); /*extra_signatures.clear();*/ }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -191,5 +194,5 @@ namespace graphene { namespace chain {
|
|||
} }
|
||||
|
||||
FC_REFLECT( graphene::chain::transaction, (ref_block_num)(ref_block_prefix)(relative_expiration)(operations) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures)(extra_signatures) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::processed_transaction, (graphene::chain::signed_transaction), (operation_results) )
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
database& db()const { FC_ASSERT( _db ); return *_db; }
|
||||
|
||||
bool signed_by( key_id_type id )const;
|
||||
bool signed_by( key_id_type id );
|
||||
|
||||
/** derived from signatures on transaction
|
||||
flat_set<address> signed_by;
|
||||
|
|
@ -53,8 +53,12 @@ namespace graphene { namespace chain {
|
|||
*/
|
||||
vector<operation_result> operation_results;
|
||||
|
||||
const signed_transaction* _trx = nullptr;
|
||||
database* _db = nullptr;
|
||||
bool _is_proposed_trx = false;
|
||||
/** When an address is referenced via check authority it is flagged as being used,
|
||||
* all addresses must be flagged as being used or the transaction will fail.
|
||||
*/
|
||||
flat_map<address, bool> _sigs;
|
||||
const signed_transaction* _trx = nullptr;
|
||||
database* _db = nullptr;
|
||||
bool _is_proposed_trx = false;
|
||||
};
|
||||
} } // namespace graphene::chain
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ bool proposal_object::is_authorized_to_execute(database& db) const
|
|||
signed_transaction tmp;
|
||||
dry_run_eval._trx = &tmp;
|
||||
for( auto key_id : available_key_approvals )
|
||||
tmp.signatures[key_id] = fc::ecc::compact_signature();
|
||||
dry_run_eval._sigs.insert( std::make_pair(key_id(db).key_address(),true) );
|
||||
|
||||
//insert into dry_run_eval->_trx.signatures
|
||||
//dry_run_eval.signed_by.insert(available_key_approvals.begin(), available_key_approvals.end());
|
||||
|
|
|
|||
|
|
@ -60,26 +60,15 @@ graphene::chain::transaction_id_type graphene::chain::transaction::id() const
|
|||
memcpy(result._hash, hash._hash, std::min(sizeof(result), sizeof(hash)));
|
||||
return result;
|
||||
}
|
||||
void graphene::chain::signed_transaction::sign( key_id_type id, const private_key_type& key )
|
||||
void graphene::chain::signed_transaction::sign( const private_key_type& key )
|
||||
{
|
||||
if( relative_expiration != 0 )
|
||||
{
|
||||
if( !block_id_cache.valid() ) edump((*this));
|
||||
assert(block_id_cache.valid());
|
||||
signatures[id] = key.sign_compact( digest(*block_id_cache) );
|
||||
signatures.push_back( key.sign_compact( digest(*block_id_cache) ) );
|
||||
} else {
|
||||
signatures[id] = key.sign_compact( digest() );
|
||||
}
|
||||
}
|
||||
void graphene::chain::signed_transaction::sign( const address& addr, const private_key_type& key )
|
||||
{
|
||||
if( relative_expiration != 0 )
|
||||
{
|
||||
if( !block_id_cache.valid() ) edump((*this));
|
||||
assert(block_id_cache.valid());
|
||||
extra_signatures[addr] = key.sign_compact( digest(*block_id_cache) );
|
||||
} else {
|
||||
extra_signatures[addr] = key.sign_compact( digest() );
|
||||
signatures.push_back( key.sign_compact( digest() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
|
@ -25,7 +26,9 @@
|
|||
namespace graphene { namespace chain {
|
||||
bool transaction_evaluation_state::check_authority( const account_object& account, authority::classification auth_class, int depth )
|
||||
{
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_authority_check) )
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_authority_check) )
|
||||
return true;
|
||||
if( (!_is_proposed_trx) && (_db->get_node_properties().skip_flags & database::skip_transaction_signatures) )
|
||||
return true;
|
||||
if( account.get_id() == GRAPHENE_TEMP_ACCOUNT ||
|
||||
approved_by.find(make_pair(account.id, auth_class)) != approved_by.end() )
|
||||
|
|
@ -91,10 +94,15 @@ namespace graphene { namespace chain {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
bool transaction_evaluation_state::signed_by( key_id_type id )const
|
||||
bool transaction_evaluation_state::signed_by( key_id_type id )
|
||||
{
|
||||
assert(_trx);
|
||||
return _trx->signatures.find(id) != _trx->signatures.end();
|
||||
assert(_db);
|
||||
//wdump((_sigs)(id(*_db).key_address())(*_trx) );
|
||||
auto itr = _sigs.find( id(*_db).key_address() );
|
||||
if( itr != _sigs.end() )
|
||||
return itr->second = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
|
|
|||
|
|
@ -2168,7 +2168,7 @@ signed_transaction wallet_api::import_balance( string name_or_id, const vector<s
|
|||
auto tx = sign_transaction( trx, false );
|
||||
|
||||
for( auto a : required_addrs )
|
||||
tx.sign( a, keys[a] );
|
||||
tx.sign( keys[a] );
|
||||
|
||||
if( broadcast )
|
||||
my->_remote_net->broadcast_transaction(tx);
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ database_fixture::database_fixture()
|
|||
}
|
||||
|
||||
database_fixture::~database_fixture()
|
||||
{
|
||||
{ try {
|
||||
// If we're unwinding due to an exception, don't do any more checks.
|
||||
// This way, boost test's last checkpoint tells us approximately where the error was.
|
||||
if( !std::uncaught_exception() )
|
||||
|
|
@ -102,7 +102,7 @@ database_fixture::~database_fixture()
|
|||
if( data_dir )
|
||||
db.close();
|
||||
return;
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
fc::ecc::private_key database_fixture::generate_private_key(string seed)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -125,9 +125,11 @@ BOOST_AUTO_TEST_CASE( recursive_accounts )
|
|||
const key_object& key2 = register_key(parent2_key.get_public_key());
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Creating parent1 and parent2 accounts" );
|
||||
const account_object& parent1 = create_account("parent1", key1.id);
|
||||
const account_object& parent2 = create_account("parent2", key2.id);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Creating child account that requires both parent1 and parent2 to approve" );
|
||||
{
|
||||
auto make_child_op = make_account("child");
|
||||
make_child_op.owner = authority(2, account_id_type(parent1.id), 1, account_id_type(parent2.id), 1);
|
||||
|
|
@ -140,23 +142,28 @@ BOOST_AUTO_TEST_CASE( recursive_accounts )
|
|||
const account_object& child = get_account("child");
|
||||
auto old_balance = fund(child);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting to transfer with no signatures, should fail" );
|
||||
transfer_operation op = {asset(), child.id, account_id_type(), core.amount(500)};
|
||||
trx.operations.push_back(op);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
sign(trx, key1.id,parent1_key);
|
||||
sign(trx, key1.id,parent1_key);
|
||||
sign(trx, key1.id,parent1_key);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 signature, should fail" );
|
||||
sign(trx, key1.id,parent1_key);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
trx.signatures.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting to transfer with parent2 signature, should fail" );
|
||||
sign(trx, key2.id,parent2_key);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 and parent2 signature, should succeed" );
|
||||
sign(trx, key1.id,parent1_key);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
BOOST_CHECK_EQUAL(get_balance(child, core), old_balance - 500);
|
||||
trx.operations.clear();
|
||||
trx.signatures.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Adding a key for the child that can override parents" );
|
||||
fc::ecc::private_key child_key = fc::ecc::private_key::generate();
|
||||
const key_object& child_key_obj = register_key(child_key.get_public_key());
|
||||
{
|
||||
|
|
@ -175,22 +182,30 @@ BOOST_AUTO_TEST_CASE( recursive_accounts )
|
|||
|
||||
op = {asset(),child.id, account_id_type(), core.amount(500)};
|
||||
trx.operations.push_back(op);
|
||||
BOOST_TEST_MESSAGE( "Attempting transfer with no signatures, should fail" );
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
BOOST_TEST_MESSAGE( "Attempting transfer just parent1, should fail" );
|
||||
sign(trx, key1.id,parent1_key);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
trx.signatures.clear();
|
||||
BOOST_TEST_MESSAGE( "Attempting transfer just parent2, should fail" );
|
||||
sign(trx, key2.id,parent2_key);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting transfer both parents, should succeed" );
|
||||
sign(trx, key1.id, parent1_key);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
BOOST_CHECK_EQUAL(get_balance(child, core), old_balance - 1000);
|
||||
trx.signatures.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempting transfer with just child key, should succeed" );
|
||||
sign(trx, child_key_obj.id, child_key);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
BOOST_CHECK_EQUAL(get_balance(child, core), old_balance - 1500);
|
||||
trx.operations.clear();
|
||||
trx.signatures.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Creating grandparent account, parent1 now requires authority of grandparent" );
|
||||
auto grandparent = create_account("grandparent");
|
||||
fc::ecc::private_key grandparent_key = fc::ecc::private_key::generate();
|
||||
const key_object& grandparent_key_obj = register_key(grandparent_key.get_public_key());
|
||||
|
|
@ -209,16 +224,21 @@ BOOST_AUTO_TEST_CASE( recursive_accounts )
|
|||
trx.signatures.clear();
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempt to transfer using old parent keys, should fail" );
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, key1.id, parent1_key);
|
||||
sign(trx, key2.id, parent2_key);
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
sign(trx, grandparent_key_obj.id, grandparent_key);
|
||||
trx.signatures.clear();
|
||||
trx.sign( parent2_key );
|
||||
trx.sign( grandparent_key );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Attempt to transfer using parent2_key and grandparent_key" );
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
BOOST_CHECK_EQUAL(get_balance(child, core), old_balance - 2000);
|
||||
trx.operations.clear();
|
||||
trx.signatures.clear();
|
||||
trx.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Update grandparent account authority to be genesis account" );
|
||||
{
|
||||
account_update_operation op;
|
||||
op.account = grandparent.id;
|
||||
|
|
@ -230,18 +250,22 @@ BOOST_AUTO_TEST_CASE( recursive_accounts )
|
|||
trx.signatures.clear();
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE( "Create recursion depth failure" );
|
||||
trx.operations.push_back(op);
|
||||
sign(trx, key2.id,parent2_key);
|
||||
sign(trx, grandparent_key_obj.id,grandparent_key);
|
||||
sign(trx, key_id_type(), delegate_priv_key);
|
||||
//Fails due to recursion depth.
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception);
|
||||
BOOST_TEST_MESSAGE( "verify child key can override recursion checks" );
|
||||
trx.signatures.clear();
|
||||
sign(trx, child_key_obj.id, child_key);
|
||||
PUSH_TX( db, trx, database::skip_transaction_dupe_check );
|
||||
BOOST_CHECK_EQUAL(get_balance(child, core), old_balance - 2500);
|
||||
trx.operations.clear();
|
||||
trx.signatures.clear();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify a cycle fails" );
|
||||
{
|
||||
account_update_operation op;
|
||||
op.account = parent1.id;
|
||||
|
|
@ -401,12 +425,14 @@ BOOST_AUTO_TEST_CASE( genesis_authority )
|
|||
uop.key_approvals_to_add.emplace(5);
|
||||
uop.key_approvals_to_add.emplace(6);
|
||||
trx.operations.push_back(uop);
|
||||
trx.sign(key_id_type(1), genesis_key);
|
||||
trx.sign(genesis_key);
|
||||
/*
|
||||
trx.signatures[key_id_type(2)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(3)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(4)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(5)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(6)] = trx.signatures[key_id_type(1)];
|
||||
*/
|
||||
db.push_transaction(trx);
|
||||
BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0);
|
||||
BOOST_CHECK(db.get<proposal_object>(prop.id).is_authorized_to_execute(db));
|
||||
|
|
@ -473,16 +499,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture )
|
|||
uop.key_approvals_to_add.emplace(8);
|
||||
uop.key_approvals_to_add.emplace(9);
|
||||
trx.operations.back() = uop;
|
||||
trx.sign(key_id_type(1), genesis_key);
|
||||
trx.signatures[key_id_type(2)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(3)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(4)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(5)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(6)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(7)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(8)] = trx.signatures[key_id_type(1)];
|
||||
trx.signatures[key_id_type(9)] = trx.signatures[key_id_type(1)];
|
||||
trx.sign(key_id_type(), genesis_key);
|
||||
trx.sign(genesis_key);
|
||||
PUSH_TX( db, trx );
|
||||
BOOST_CHECK(pid(db).is_authorized_to_execute(db));
|
||||
|
||||
|
|
@ -968,6 +985,8 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
|
|||
|
||||
trx.clear();
|
||||
trx.operations.push_back( xfer_op );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Transfer signed by alice" );
|
||||
trx.sign( alice_key_id, alice_key );
|
||||
|
||||
flat_set<account_id_type> active_set, owner_set;
|
||||
|
|
@ -977,33 +996,20 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
|
|||
PUSH_TX( db, trx, skip );
|
||||
|
||||
trx.operations.push_back( xfer_op );
|
||||
BOOST_TEST_MESSAGE( "Invalidating Alices Signature" );
|
||||
// Alice's signature is now invalid
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||
// Re-sign, now OK (sig is replaced)
|
||||
trx.sign( alice_key_id, alice_key );
|
||||
BOOST_TEST_MESSAGE( "Resign with Alice's Signature" );
|
||||
trx.signatures.clear();
|
||||
trx.sign( alice_key );
|
||||
PUSH_TX( db, trx, skip );
|
||||
|
||||
trx.signatures.clear();
|
||||
trx.sign( charlie_key_id, alice_key );
|
||||
// Sign with Alice's key (valid) claiming to be Charlie
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||
// and with Charlie's key (invalid) claiming to be Alice
|
||||
trx.sign( charlie_key_id, alice_key );
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||
trx.signatures.clear();
|
||||
// okay, now sign ONLY with Charlie's key claiming to be Alice
|
||||
trx.sign( charlie_key_id, alice_key );
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||
|
||||
trx.signatures.clear();
|
||||
trx.operations.pop_back();
|
||||
trx.sign( alice_key_id, alice_key );
|
||||
trx.sign( charlie_key_id, charlie_key );
|
||||
trx.sign( alice_key );
|
||||
trx.sign( charlie_key );
|
||||
// Signed by third-party Charlie (irrelevant key, not in authority)
|
||||
PUSH_TX( db, trx, skip );
|
||||
trx.operations.push_back( xfer_op );
|
||||
trx.sign( alice_key_id, alice_key );
|
||||
// Alice's sig is valid but Charlie's is invalid
|
||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||
}
|
||||
FC_LOG_AND_RETHROW()
|
||||
|
|
@ -1032,7 +1038,7 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
|
|||
op.new_options->votes = flat_set<vote_id_type>{nathan_delegate(db).vote_id};
|
||||
op.new_options->num_committee = 1;
|
||||
trx.operations.push_back(op);
|
||||
trx.sign(nathan_key_id, nathan_private_key);
|
||||
trx.sign(nathan_private_key);
|
||||
PUSH_TX( db, trx );
|
||||
trx.clear();
|
||||
}
|
||||
|
|
@ -1043,12 +1049,13 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
|
|||
op.new_options->votes.insert(vikram_delegate(db).vote_id);
|
||||
op.new_options->num_committee = 11;
|
||||
trx.operations.push_back(op);
|
||||
trx.sign(vikram_key_id, vikram_private_key);
|
||||
trx.sign(vikram_private_key);
|
||||
// Fails because num_committee is larger than the cardinality of committee members being voted for
|
||||
BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception);
|
||||
op.new_options->num_committee = 3;
|
||||
trx.operations = {op};
|
||||
trx.sign(vikram_key_id, vikram_private_key);
|
||||
trx.signatures.clear();
|
||||
trx.sign(vikram_private_key);
|
||||
PUSH_TX( db, trx );
|
||||
trx.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE( undo_pending )
|
|||
cop.name = "nathan";
|
||||
cop.owner = authority(1, key_id_type(), 1);
|
||||
trx.operations.push_back(cop);
|
||||
trx.sign( key_id_type(), delegate_priv_key );
|
||||
//trx.sign( delegate_priv_key );
|
||||
PUSH_TX( db, trx );
|
||||
|
||||
now += db.block_interval();
|
||||
|
|
@ -576,6 +576,43 @@ BOOST_FIXTURE_TEST_CASE( limit_order_expiration, database_fixture )
|
|||
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 50000 );
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( double_sign_check, database_fixture )
|
||||
{ try {
|
||||
generate_block();
|
||||
const auto& from = account_id_type()(db);
|
||||
ACTOR(to);
|
||||
asset amount(1000);
|
||||
|
||||
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||
trx.operations.push_back(transfer_operation({ asset(), from.id, to.id, amount, memo_data() }));
|
||||
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||
trx.validate();
|
||||
|
||||
db.push_transaction(trx, ~0);
|
||||
|
||||
trx.operations.clear();
|
||||
trx.operations.push_back(transfer_operation({ asset(), to.id, from.id, amount, memo_data() }));
|
||||
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||
trx.validate();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify that not-signing causes an exception" );
|
||||
BOOST_REQUIRE_THROW( db.push_transaction(trx, 0 ), fc::exception );
|
||||
trx.sign( to_private_key );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify that double-signing causes an exception" );
|
||||
BOOST_REQUIRE_THROW( db.push_transaction(trx, 0 ), fc::exception );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify that signing with an extra, unused key fails" );
|
||||
trx.signatures.pop_back();
|
||||
trx.sign( generate_private_key("bogus") );
|
||||
BOOST_REQUIRE_THROW( db.push_transaction(trx, 0 ), fc::exception );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify that signing once with the proper key passes" );
|
||||
db.push_transaction(trx, 0 );
|
||||
trx.sign( to_private_key );
|
||||
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture )
|
||||
{ try {
|
||||
generate_block();
|
||||
|
|
@ -603,6 +640,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture )
|
|||
get_account("init6").get_id(), get_account("init7").get_id()};
|
||||
trx.operations.push_back(uop);
|
||||
trx.sign(get_account("init0").active.get_keys().front(),delegate_priv_key);
|
||||
/*
|
||||
trx.sign(get_account("init1").active.get_keys().front(),delegate_priv_key);
|
||||
trx.sign(get_account("init2").active.get_keys().front(),delegate_priv_key);
|
||||
trx.sign(get_account("init3").active.get_keys().front(),delegate_priv_key);
|
||||
|
|
@ -610,6 +648,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture )
|
|||
trx.sign(get_account("init5").active.get_keys().front(),delegate_priv_key);
|
||||
trx.sign(get_account("init6").active.get_keys().front(),delegate_priv_key);
|
||||
trx.sign(get_account("init7").active.get_keys().front(),delegate_priv_key);
|
||||
*/
|
||||
db.push_transaction(trx);
|
||||
BOOST_CHECK(proposal_id_type()(db).is_authorized_to_execute(db));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -962,15 +962,15 @@ BOOST_AUTO_TEST_CASE( balance_object_test )
|
|||
op.total_claimed = asset(1);
|
||||
op.owners.insert(genesis_state.initial_balances.back().owner);
|
||||
trx.operations = {op};
|
||||
trx.sign(*op.owners.begin(), generate_private_key("n"));
|
||||
trx.sign(op.deposit_to_account(db).active.get_keys().front(), generate_private_key("n"));
|
||||
trx.sign(generate_private_key("n"));
|
||||
//trx.sign(generate_private_key("n"));
|
||||
// Fail because I'm claiming the wrong address
|
||||
BOOST_CHECK_THROW(db.push_transaction(trx), fc::exception);
|
||||
trx.clear();
|
||||
op.owners = {genesis_state.initial_balances.front().owner};
|
||||
trx.operations = {op};
|
||||
trx.sign(*op.owners.begin(), generate_private_key("n"));
|
||||
trx.sign(op.deposit_to_account(db).active.get_keys().front(), generate_private_key("n"));
|
||||
trx.sign(generate_private_key("n"));
|
||||
//trx.sign(generate_private_key("n"));
|
||||
db.push_transaction(trx);
|
||||
|
||||
// Not using fixture's get_balance() here because it uses fixture's db, not my override
|
||||
|
|
|
|||
Loading…
Reference in a new issue