diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 5fedbd02f8..56c9db82e8 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -248,6 +248,11 @@ void_result call_order_update_evaluator::do_apply(const call_order_update_operat call_obj = &*itr; old_collateralization = call_obj->collateralization(); old_debt = call_obj->debt; + auto new_collateral = call_obj->collateral + o.delta_collateral.amount; + auto new_debt = *old_debt + o.delta_debt.amount; + + // Forbid zero collateral with nonzero debt (avoids divide by zero when calculating call price below) + FC_ASSERT(!(new_collateral == 0 && new_debt != 0), "Cannot have zero collateral and nonzero debt"); d.modify( *call_obj, [&]( call_order_object& call ){ call.collateral += o.delta_collateral.amount; diff --git a/libraries/db/include/graphene/db/generic_index.hpp b/libraries/db/include/graphene/db/generic_index.hpp index 8a433264e1..8302881950 100644 --- a/libraries/db/include/graphene/db/generic_index.hpp +++ b/libraries/db/include/graphene/db/generic_index.hpp @@ -67,10 +67,25 @@ namespace graphene { namespace chain { virtual void modify( const object& obj, const std::function& m )override { - assert( nullptr != dynamic_cast(&obj) ); - auto ok = _indices.modify( _indices.iterator_to( static_cast(obj) ), - [&m]( ObjectType& o ){ m(o); } ); - FC_ASSERT( ok, "Could not modify object, most likely a index constraint was violated" ); + assert(nullptr != dynamic_cast(&obj)); + std::exception_ptr exc; + auto ok = _indices.modify(_indices.iterator_to(static_cast(obj)), + [&m, &exc](ObjectType& o) mutable { + try { + m(o); + } catch (fc::exception e) { + exc = std::current_exception(); + elog("Exception while modifying object: ${e} -- object may be corrupted", + ("e", e)); + } catch (...) { + exc = std::current_exception(); + elog("Unknown exception while modifying object"); + } + } + ); + if (exc) + std::rethrow_exception(exc); + FC_ASSERT(ok, "Could not modify object, most likely a index constraint was violated"); } virtual void remove( const object& obj )override diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5fd06115fd..ccdfc93d70 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,10 @@ if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) +file(GLOB SLOW_UNIT_TESTS "slow_tests/*.cpp") +add_executable( slow_chain_test ${SLOW_UNIT_TESTS} ${COMMON_SOURCES} ) +target_link_libraries( slow_chain_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) + file(GLOB PERFORMANCE_TESTS "performance/*.cpp") add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} ) target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/tests/tests/call_order_tests.cpp b/tests/slow_tests/call_order_tests.cpp similarity index 100% rename from tests/tests/call_order_tests.cpp rename to tests/slow_tests/call_order_tests.cpp diff --git a/tests/slow_tests/main.cpp b/tests/slow_tests/main.cpp new file mode 100644 index 0000000000..405e7c1059 --- /dev/null +++ b/tests/slow_tests/main.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; + +boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { + std::srand(time(NULL)); + std::cout << "Random number generator seeded to " << time(NULL) << std::endl; + const char* genesis_timestamp_str = getenv("GRAPHENE_TESTING_GENESIS_TIMESTAMP"); + if( genesis_timestamp_str != nullptr ) + { + GRAPHENE_TESTING_GENESIS_TIMESTAMP = std::stoul( genesis_timestamp_str ); + } + std::cout << "GRAPHENE_TESTING_GENESIS_TIMESTAMP is " << GRAPHENE_TESTING_GENESIS_TIMESTAMP << std::endl; + return nullptr; +} diff --git a/tests/tests/database_tests.cpp b/tests/tests/database_tests.cpp index 8546210df4..6b5ea8b96b 100644 --- a/tests/tests/database_tests.cpp +++ b/tests/tests/database_tests.cpp @@ -62,6 +62,32 @@ BOOST_AUTO_TEST_CASE( undo_test ) } } +/** + * Check that database modify() functors that throw do not get caught by boost, which will remove the object + */ +BOOST_AUTO_TEST_CASE(failed_modify_test) +{ try { + database db; + // Create dummy object + const auto& obj = db.create([](account_balance_object& obj) { + obj.owner = account_id_type(123); + }); + account_balance_id_type obj_id = obj.id; + BOOST_CHECK_EQUAL(obj.owner.instance.value, 123); + + // Modify dummy object, check that changes stick + db.modify(obj, [](account_balance_object& obj) { + obj.owner = account_id_type(234); + }); + BOOST_CHECK_EQUAL(obj_id(db).owner.instance.value, 234); + + // Throw exception when modifying object, check that object still exists after + BOOST_CHECK_THROW(db.modify(obj, [](account_balance_object& obj) { + throw 5; + }), int); + BOOST_CHECK_NE((long)db.find_object(obj_id), (long)nullptr); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE( flat_index_test ) { try { ACTORS((sam)); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 345500f7b3..e354bdf57c 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -145,6 +145,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_test ) GRAPHENE_REQUIRE_THROW( borrow( dan, bitusd.amount(80000), asset(0)), fc::exception ); BOOST_TEST_MESSAGE( "attempting to claim all collateral without paying off debt" ); GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000)), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000-1)), fc::exception ); borrow( sam, bitusd.amount(1000), asset(10000)); transfer( sam, dan, bitusd.amount(1000) );