/* * Copyright (c) 2015, Cryptonomex, Inc. * All rights reserved. * * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, * are permitted until September 8, 2015, provided that the following conditions are met: * * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include /* * This file provides with() functions which modify the database * temporarily, then restore it. These functions are mostly internal * implementation detail of the database. * * Essentially, we want to be able to use "finally" to restore the * database regardless of whether an exception is thrown or not, but there * is no "finally" in C++. Instead, C++ requires us to create a struct * and put the finally block in a destructor. Aagh! */ namespace graphene { namespace chain { namespace detail { /** * Class used to help the with_skip_flags implementation. * It must be defined in this header because it must be * available to the with_skip_flags implementation, * which is a template and therefore must also be defined * in this header. */ struct skip_flags_restorer { skip_flags_restorer( node_property_object& npo, uint32_t old_skip_flags ) : _npo( npo ), _old_skip_flags( old_skip_flags ) {} ~skip_flags_restorer() { _npo.skip_flags = _old_skip_flags; } node_property_object& _npo; uint32_t _old_skip_flags; // initialized in ctor }; /** * Class used to help the without_pending_transactions * implementation. * * TODO: Change the name of this class to better reflect the fact * that it restores popped transactions as well as pending transactions. */ struct pending_transactions_restorer { pending_transactions_restorer( database& db, std::vector&& pending_transactions ) : _db(db), _pending_transactions( std::move(pending_transactions) ) { _db.clear_pending(); } ~pending_transactions_restorer() { for( const auto& tx : _db._popped_tx ) { try { if( !_db.is_known_transaction( tx.id() ) ) { // since push_transaction() takes a signed_transaction, // the operation_results field will be ignored. _db._push_transaction( tx ); } } catch ( const fc::exception& ) { } } _db._popped_tx.clear(); for( const processed_transaction& tx : _pending_transactions ) { try { if( !_db.is_known_transaction( tx.id() ) ) { // since push_transaction() takes a signed_transaction, // the operation_results field will be ignored. _db._push_transaction( tx ); } } catch( const fc::exception& e ) { /* wlog( "Pending transaction became invalid after switching to block ${b} ${t}", ("b", _db.head_block_id())("t",_db.head_block_time()) ); wlog( "The invalid pending transaction caused exception ${e}", ("e", e.to_detail_string() ) ); */ } } } database& _db; std::vector< processed_transaction > _pending_transactions; }; /** * Set the skip_flags to the given value, call callback, * then reset skip_flags to their previous value after * callback is done. */ template< typename Lambda > void with_skip_flags( database& db, uint32_t skip_flags, Lambda callback ) { node_property_object& npo = db.node_properties(); skip_flags_restorer restorer( npo, npo.skip_flags ); npo.skip_flags = skip_flags; callback(); return; } /** * Empty pending_transactions, call callback, * then reset pending_transactions after callback is done. * * Pending transactions which no longer validate will be culled. */ template< typename Lambda > void without_pending_transactions( database& db, std::vector&& pending_transactions, Lambda callback ) { pending_transactions_restorer restorer( db, std::move(pending_transactions) ); callback(); return; } } } } // graphene::chain::detail