diff --git a/include/chainbase/chainbase.hpp b/include/chainbase/chainbase.hpp index 7ce93bc..ef7c25e 100644 --- a/include/chainbase/chainbase.hpp +++ b/include/chainbase/chainbase.hpp @@ -20,6 +20,13 @@ #include #include +#pragma push_macro("N") +#undef N + +#include + +#pragma pop_macro("N") + #include #include #include @@ -46,6 +53,7 @@ namespace chainbase { namespace bfs = boost::filesystem; using std::unique_ptr; using std::vector; + using boost::signals2::signal; template using allocator = bip::allocator; @@ -190,6 +198,8 @@ namespace chainbase { typedef typename index_type::value_type value_type; typedef bip::allocator< generic_index, segment_manager_type > allocator_type; typedef undo_state< value_type > undo_state_type; + typedef signal signal_op_type; + typedef signal signal_rev_type; generic_index( allocator a ) :_stack(a),_indices( a ),_size_of_value_type( sizeof(typename MultiIndexType::node_type) ),_size_of_this(sizeof(*this)){} @@ -220,6 +230,9 @@ namespace chainbase { ++_next_id; on_create( *insert_result.first ); + + emit(applied_emplace, *insert_result.first ); + return *insert_result.first; } @@ -228,10 +241,15 @@ namespace chainbase { on_modify( obj ); auto ok = _indices.modify( _indices.iterator_to( obj ), m ); if( !ok ) BOOST_THROW_EXCEPTION( std::logic_error( "Could not modify object, most likely a uniqueness constraint was violated" ) ); + + emit(applied_modify, obj ); } void remove( const value_type& obj ) { on_remove( obj ); + + emit(applied_remove, obj ); + _indices.erase( _indices.iterator_to( obj ) ); } @@ -316,22 +334,34 @@ namespace chainbase { void undo() { if( !enabled() ) return; + emit(applied_undo, _revision ); + const auto& head = _stack.back(); for( auto& item : head.old_values ) { - auto ok = _indices.modify( _indices.find( item.second.id ), [&]( value_type& v ) { + emit(applied_modify, item.second); + + auto ok = _indices.modify(_indices.find( item.second.id ), [&]( value_type& v ) { v = std::move( item.second ); }); + if( !ok ) BOOST_THROW_EXCEPTION( std::logic_error( "Could not modify object, most likely a uniqueness constraint was violated" ) ); } for( auto id : head.new_ids ) { - _indices.erase( _indices.find( id ) ); + const auto& itr = _indices.find( id ); + + if( itr != _indices.end()) + emit(applied_remove, *itr); + + _indices.erase( itr ); } _next_id = head.old_next_id; for( auto& item : head.removed_values ) { + emit(applied_emplace, item.second); + bool ok = _indices.emplace( std::move( item.second ) ).second; if( !ok ) BOOST_THROW_EXCEPTION( std::logic_error( "Could not restore object, most likely a uniqueness constraint was violated" ) ); } @@ -499,7 +529,39 @@ namespace chainbase { return {begin, end}; } - const auto& stack()const { return _stack; } + /** + * Plugins / observers listening to signals emited (such as accepted_transaction) might trigger + * errors and throw exceptions. Unless those exceptions are caught it could impact consensus and/or + * cause a node to fork. + * + * If it is ever desirable to let a signal handler bubble an exception out of this method + * a full audit of its uses needs to be undertaken. + * + */ + template + void emit(const Signal &s, Arg &&a) + { + try + { + s(std::forward(a)); + } + catch (boost::interprocess::bad_alloc &e) + { + std::cerr << "bad alloc"; + throw e; + } + catch (...) + { + std::cerr << "signal handler threw exception"; + } + } + + const auto &stack() const { return _stack; } + + mutable signal_op_type applied_emplace; + mutable signal_op_type applied_modify; + mutable signal_op_type applied_remove; + mutable signal_rev_type applied_undo; private: bool enabled()const { return _stack.size(); }