Moved check for duplicates to the database. Removed code duplication from unit-tests
This commit is contained in:
parent
9fd4fe6713
commit
1c74bba60d
3 changed files with 63 additions and 65 deletions
|
|
@ -36,9 +36,32 @@
|
||||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||||
#include <graphene/chain/exceptions.hpp>
|
#include <graphene/chain/exceptions.hpp>
|
||||||
#include <graphene/chain/evaluator.hpp>
|
#include <graphene/chain/evaluator.hpp>
|
||||||
|
#include <fc/crypto/digest.hpp>
|
||||||
|
|
||||||
#include <fc/smart_ref_impl.hpp>
|
#include <fc/smart_ref_impl.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct proposed_operations_digest_accumulator
|
||||||
|
{
|
||||||
|
typedef void result_type;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void operator()(const T&)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void operator()(const graphene::chain::proposal_create_operation& proposal)
|
||||||
|
{
|
||||||
|
for (auto& operation: proposal.proposed_ops)
|
||||||
|
{
|
||||||
|
proposed_operations_digests.push_back(fc::digest(operation.op));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<fc::sha256> proposed_operations_digests;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
bool database::is_known_block( const block_id_type& id )const
|
bool database::is_known_block( const block_id_type& id )const
|
||||||
|
|
@ -104,6 +127,31 @@ std::vector<block_id_type> database::get_block_ids_on_fork(block_id_type head_of
|
||||||
result.emplace_back(branches.first.back()->previous_id());
|
result.emplace_back(branches.first.back()->previous_id());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void database::check_tansaction_for_duplicated_operations(const signed_transaction& trx)
|
||||||
|
{
|
||||||
|
const auto& proposal_index = this->get_index<proposal_object>();
|
||||||
|
std::set<fc::sha256> existed_operations_digests;
|
||||||
|
|
||||||
|
proposal_index.inspect_all_objects( [&](const object& obj){
|
||||||
|
const proposal_object& proposal = static_cast<const proposal_object&>(obj);
|
||||||
|
for (auto& operation: proposal.proposed_transaction.operations)
|
||||||
|
{
|
||||||
|
existed_operations_digests.insert(fc::digest(operation));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
proposed_operations_digest_accumulator digest_accumulator;
|
||||||
|
for (auto& operation: trx.operations)
|
||||||
|
{
|
||||||
|
operation.visit(digest_accumulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& digest: digest_accumulator.proposed_operations_digests)
|
||||||
|
{
|
||||||
|
FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for approval.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push block "may fail" in which case every partial change is unwound. After
|
* Push block "may fail" in which case every partial change is unwound. After
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,8 @@ namespace graphene { namespace chain {
|
||||||
void add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts );
|
void add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts );
|
||||||
const flat_map<uint32_t,block_id_type> get_checkpoints()const { return _checkpoints; }
|
const flat_map<uint32_t,block_id_type> get_checkpoints()const { return _checkpoints; }
|
||||||
bool before_last_checkpoint()const;
|
bool before_last_checkpoint()const;
|
||||||
|
|
||||||
|
void check_tansaction_for_duplicated_operations(const signed_transaction& trx);
|
||||||
|
|
||||||
bool push_block( const signed_block& b, uint32_t skip = skip_nothing );
|
bool push_block( const signed_block& b, uint32_t skip = skip_nothing );
|
||||||
processed_transaction push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
|
processed_transaction push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
|
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
|
||||||
*
|
*
|
||||||
|
|
@ -61,48 +59,16 @@ namespace
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct proposed_operations_digest_accumulator
|
signed_transaction make_signed_transaction_with_proposed_operation(database_fixture& fixture, const operation& op)
|
||||||
{
|
{
|
||||||
typedef void result_type;
|
proposal_create_operation operation_proposal;
|
||||||
|
operation_proposal.proposed_ops = {op_wrapper(op)};
|
||||||
|
|
||||||
template<class T>
|
signed_transaction transaction;
|
||||||
void operator()(const T&) const
|
set_expiration( fixture.db, transaction );
|
||||||
{}
|
transaction.operations = {operation_proposal};
|
||||||
|
|
||||||
void operator()(const proposal_create_operation& proposal) const
|
return transaction;
|
||||||
{
|
|
||||||
for (auto& operation: proposal.proposed_ops)
|
|
||||||
{
|
|
||||||
proposed_operations_digests.push_back(fc::digest(operation.op));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutable std::vector<fc::sha256> proposed_operations_digests;
|
|
||||||
};
|
|
||||||
|
|
||||||
void check_transactions_duplicates(database& db, const signed_transaction& transaction)
|
|
||||||
{
|
|
||||||
const auto& proposal_index = db.get_index<proposal_object>();
|
|
||||||
std::set<fc::sha256> existed_operations_digests;
|
|
||||||
|
|
||||||
proposal_index.inspect_all_objects( [&](const object& obj){
|
|
||||||
const proposal_object& proposal = static_cast<const proposal_object&>(obj);
|
|
||||||
for (auto& operation: proposal.proposed_transaction.operations)
|
|
||||||
{
|
|
||||||
existed_operations_digests.insert(fc::digest(operation));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
proposed_operations_digest_accumulator digest_accumulator;
|
|
||||||
for (auto& operation: transaction.operations)
|
|
||||||
{
|
|
||||||
operation.visit(digest_accumulator);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& digest: digest_accumulator.proposed_operations_digests)
|
|
||||||
{
|
|
||||||
FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for approval.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,14 +82,8 @@ BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_tw
|
||||||
|
|
||||||
::propose_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
::propose_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
||||||
|
|
||||||
proposal_create_operation operation_proposal;
|
auto trx = make_signed_transaction_with_proposed_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
||||||
operation_proposal.proposed_ops = {op_wrapper(make_transfer_operation(account_id_type(), alice_id, asset(500)))};
|
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||||
|
|
||||||
signed_transaction trx;
|
|
||||||
set_expiration( db, trx );
|
|
||||||
trx.operations = {operation_proposal};
|
|
||||||
|
|
||||||
BOOST_CHECK_THROW(check_transactions_duplicates(db, trx), fc::exception);
|
|
||||||
}
|
}
|
||||||
catch( const fc::exception& e )
|
catch( const fc::exception& e )
|
||||||
{
|
{
|
||||||
|
|
@ -138,14 +98,8 @@ BOOST_AUTO_TEST_CASE( test_check_passes_without_duplication )
|
||||||
{
|
{
|
||||||
ACTORS((alice))
|
ACTORS((alice))
|
||||||
|
|
||||||
proposal_create_operation operation_proposal;
|
auto trx = make_signed_transaction_with_proposed_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
||||||
operation_proposal.proposed_ops = {op_wrapper(make_transfer_operation(account_id_type(), alice_id, asset(500)))};
|
BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx));
|
||||||
|
|
||||||
signed_transaction trx;
|
|
||||||
set_expiration( db, trx );
|
|
||||||
trx.operations = {operation_proposal};
|
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(check_transactions_duplicates(db, trx));
|
|
||||||
}
|
}
|
||||||
catch( const fc::exception& e )
|
catch( const fc::exception& e )
|
||||||
{
|
{
|
||||||
|
|
@ -162,14 +116,8 @@ BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_with_differ
|
||||||
|
|
||||||
::propose_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
::propose_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(500)));
|
||||||
|
|
||||||
proposal_create_operation operation_proposal;
|
auto trx = make_signed_transaction_with_proposed_operation(*this, make_transfer_operation(account_id_type(), alice_id, asset(501)));
|
||||||
operation_proposal.proposed_ops = {op_wrapper(make_transfer_operation(account_id_type(), alice_id, asset(501)))};
|
BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx));
|
||||||
|
|
||||||
signed_transaction trx;
|
|
||||||
set_expiration( db, trx );
|
|
||||||
trx.operations = {operation_proposal};
|
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(check_transactions_duplicates(db, trx));
|
|
||||||
}
|
}
|
||||||
catch( const fc::exception& e )
|
catch( const fc::exception& e )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue