diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 241678b3..bb1e725f 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -17,10 +17,8 @@ */ #include #include -#include #include #include -#include #include @@ -167,7 +165,7 @@ namespace graphene { namespace app { else { result.reserve(assets.size()); - + std::transform(assets.begin(), assets.end(), std::back_inserter(result), [this, acnt](asset_id_type id) { return _db.get_balance(acnt, id); }); } @@ -242,7 +240,7 @@ namespace graphene { namespace app { auto itr = assets_by_symbol.lower_bound(lower_bound_symbol); - if( lower_bound_symbol == "" ) + if( lower_bound_symbol == "" ) itr = assets_by_symbol.begin(); while(limit-- && itr != assets_by_symbol.end()) @@ -251,6 +249,24 @@ namespace graphene { namespace app { return result; } + fc::optional database_api::get_delegate_by_account(account_id_type account) const + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; + } + + fc::optional database_api::get_witness_by_account(account_id_type account) const + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; + } + login_api::login_api(application& a) :_app(a) { diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 6deec129..f9711780 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -153,14 +153,14 @@ namespace detail { secret_hash_type::encoder enc; fc::raw::pack(enc, nathan_key); fc::raw::pack(enc, secret_hash_type()); + auto secret = secret_hash_type::hash(enc.result()); for( int i = 0; i < 10; ++i ) { - initial_state.allocation_targets.emplace_back("init"+fc::to_string(i), nathan_key.get_public_key(), 0, true); - initial_state.initial_committee.push_back({"init"+fc::to_string(i)}); + auto name = "init"+fc::to_string(i); + initial_state.allocation_targets.emplace_back(name, nathan_key.get_public_key(), 0, true); + initial_state.initial_committee.push_back({name}); + initial_state.initial_witnesses.push_back({name, nathan_key.get_public_key(), secret}); } - initial_state.initial_witnesses = vector(10, {"committee-account", - nathan_key.get_public_key(), - secret_hash_type::hash(enc.result())}); initial_state.allocation_targets.emplace_back("nathan", address(public_key_type(nathan_key.get_public_key())), 1); if( _options->count("genesis-json") ) diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index e4729c3d..e1b2e3c9 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -24,7 +24,10 @@ #include #include #include +#include +#include #include + #include namespace graphene { namespace app { @@ -165,6 +168,19 @@ namespace graphene { namespace app { */ vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; + /** + * @brief Get the delegate owned by a given account + * @param account The ID of the account whose delegate should be retrieved + * @return The delegate object, or null if the account does not have a delegate + */ + fc::optional get_delegate_by_account(account_id_type account)const; + /** + * @brief Get the witness owned by a given account + * @param account The ID of the account whose witness should be retrieved + * @return The witness object, or null if the account does not have a witness + */ + fc::optional get_witness_by_account(account_id_type account)const; + /** * @group Push Notification Methods * These methods may be used to get push notifications whenever an object or market is changed @@ -338,6 +354,8 @@ FC_API(graphene::app::database_api, (get_call_orders) (get_settle_orders) (list_assets) + (get_delegate_by_account) + (get_witness_by_account) (subscribe_to_objects) (unsubscribe_from_objects) (subscribe_to_market) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index dea3be7e..0dbaa8c5 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -1,16 +1,42 @@ file(GLOB HEADERS "include/graphene/chain/*.hpp") +add_executable( field_reflector + field_reflector.cpp + types.cpp + type_id.cpp + address.cpp + key_object.cpp + ${HEADERS} ) + +target_include_directories( field_reflector + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +target_link_libraries( field_reflector fc graphene_db ) + +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp + COMMAND field_reflector ${CMAKE_CURRENT_SOURCE_DIR}/db_reflect_cmp.tmpl ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp.new + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp.new ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp.new + DEPENDS field_reflector db_reflect_cmp.tmpl + ) + ## SORT .cpp by most likely to change / break compile add_library( graphene_chain types.cpp + type_id.cpp + + ${CMAKE_CURRENT_BINARY_DIR}/db_reflect_cmp.cpp + address.cpp asset.cpp + predicate.cpp operations.cpp evaluator.cpp global_parameters_evaluator.cpp account_evaluator.cpp + assert_evaluator.cpp witness_evaluator.cpp delegate_evaluator.cpp asset_evaluator.cpp diff --git a/libraries/chain/assert_evaluator.cpp b/libraries/chain/assert_evaluator.cpp new file mode 100644 index 00000000..fe4891b7 --- /dev/null +++ b/libraries/chain/assert_evaluator.cpp @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#include +#include +#include + +#include + +namespace graphene { namespace chain { + +namespace detail { + +struct predicate_check_visitor +{ + predicate_check_visitor( const database& d ): _db(d){} + + typedef bool result_type; + template bool operator()( const Predicate& pred )const + { + return pred.check_predicate( _db ); + } + + const database& _db; +}; + +} // graphene::chain::detail + +void_result assert_evaluator::do_evaluate( const assert_operation& o ) +{ + const database& _db = db(); + uint32_t skip = _db.get_node_properties().skip_flags; + // TODO: Skip flags + if( skip & database::skip_assert_evaluation ) + return void_result(); + for( const vector& s_pred : o.predicates ) + { + std::istringstream is( string( s_pred.begin(), s_pred.end() ) ); + // de-serialize just the static_variant tag + unsigned_int t; + fc::raw::unpack( is, t ); + // everyone checks: delegates must have allocated an opcode for it + FC_ASSERT( t.value < _db.get_global_properties().parameters.max_predicate_opcode ); + if( t.value >= predicate::count() ) + { + // + // delegates allocated an opcode, but our client doesn't know + // the semantics (i.e. we are running an old client) + // + // skip_unknown_predicate indicates we're cool with assuming + // unknown predicates pass + // + if( skip & database::skip_unknown_predicate ) + continue; + // + // ok, unknown predicate must die + // + FC_ASSERT( false, "unknown predicate" ); + } + // rewind to beginning, unpack it, and check it + is.clear(); + is.seekg(0); + predicate pred; + fc::raw::unpack( is, pred ); + bool pred_passed = pred.visit( detail::predicate_check_visitor( _db ) ); + FC_ASSERT( pred_passed ); + } + return void_result(); +} + +void_result assert_evaluator::do_apply( const assert_operation& o ) +{ + // assert_operation is always a no-op + return void_result(); +} + +} } // graphene::chain diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index bd5a6bb6..f1a483ba 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -80,7 +80,7 @@ const signed_transaction& database::get_recent_transaction(const transaction_id_ * * @return true if we switched forks as a result of this push. */ -bool database::push_block( const signed_block& new_block, uint32_t skip ) +bool database::push_block(const signed_block& new_block, uint32_t skip) { bool result; with_skip_flags( skip, [&]() @@ -90,29 +90,20 @@ bool database::push_block( const signed_block& new_block, uint32_t skip ) return result; } -bool database::_push_block( const signed_block& new_block ) +bool database::_push_block(const signed_block& new_block) { try { uint32_t skip = get_node_properties().skip_flags; if( !(skip&skip_fork_db) ) { - auto new_head = _fork_db.push_block( new_block ); + auto new_head = _fork_db.push_block(new_block); //If the head block from the longest chain does not build off of the current head, we need to switch forks. if( new_head->data.previous != head_block_id() ) { - //edump((new_head->data.previous)); //If the newly pushed block is the same height as head, we get head back in new_head //Only switch forks if new_head is actually higher than head if( new_head->data.block_num() > head_block_num() ) { - auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous ); - for( auto item : branches.first ) - { - // wdump( ("new")(item->id)(item->data.previous) ); - } - for( auto item : branches.second ) - { - // wdump( ("old")(item->id)(item->data.previous) ); - } + auto branches = _fork_db.fetch_branch_from(new_head->data.id(), _pending_block.previous); // pop blocks until we hit the forked block while( head_block_id() != branches.second.back()->data.previous ) @@ -131,9 +122,6 @@ bool database::_push_block( const signed_block& new_block ) catch ( const fc::exception& e ) { except = e; } if( except ) { - //wdump((except->to_detail_string())); - // elog( "Encountered error when switching to a longer fork at id ${id}. Going back.", - // ("id", (*ritr)->id) ); // remove the rest of branches.first from the fork_db, those blocks are invalid while( ritr != branches.first.rend() ) { @@ -170,8 +158,8 @@ bool database::_push_block( const signed_block& new_block ) try { auto session = _undo_db.start_undo_session(); - apply_block( new_block, skip ); - _block_id_to_block.store( new_block.id(), new_block ); + apply_block(new_block, skip); + _block_id_to_block.store(new_block.id(), new_block); session.commit(); } catch ( const fc::exception& e ) { elog("Failed to push new block:\n${e}", ("e", e.to_detail_string())); @@ -204,7 +192,6 @@ processed_transaction database::push_transaction( const signed_transaction& trx, processed_transaction database::_push_transaction( const signed_transaction& trx ) { uint32_t skip = get_node_properties().skip_flags; - //wdump((trx.digest())(trx.id())); // If this is the first transaction pushed after applying a block, start a new undo session. // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives. if( !_pending_block_session ) _pending_block_session = _undo_db.start_undo_session(); @@ -239,9 +226,6 @@ processed_transaction database::push_proposal(const proposal_object& proposal) return std::make_pair(id, authority::owner); }); - //ilog("Attempting to push proposal ${prop}", ("prop", proposal)); - //idump((eval_state.approved_by)); - eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size()); processed_transaction ptrx(proposal.proposed_transaction); eval_state._trx = &ptrx; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 0f95fd1d..882234ea 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -73,6 +74,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); @@ -103,8 +105,8 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index> >(); - add_index< primary_index> >(); - add_index< primary_index> >(); + add_index< primary_index >(); + add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); @@ -116,12 +118,12 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); - add_index< primary_index> >(); - add_index< primary_index> >(); - add_index< primary_index> >(); - add_index< primary_index> >(); - add_index< primary_index> >(); - add_index< primary_index< simple_index< witness_schedule_object > > >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); } void database::init_genesis(const genesis_state_type& genesis_state) @@ -354,6 +356,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) assert( wso.id == witness_schedule_id_type() ); _undo_db.enable(); -} FC_LOG_AND_RETHROW() } +} FC_CAPTURE_AND_RETHROW((genesis_state)) } } } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 92a2e6a1..11bc6770 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -31,18 +31,19 @@ namespace graphene { namespace chain { -template -vector> database::sort_votable_objects(size_t count) const +template +vector> database::sort_votable_objects(size_t count) const { - const auto& all_objects = dynamic_cast&>(get_index()); + using ObjectType = typename Index::object_type; + const auto& all_objects = get_index_type().indices(); count = std::min(count, all_objects.size()); vector> refs; refs.reserve(all_objects.size()); std::transform(all_objects.begin(), all_objects.end(), std::back_inserter(refs), [](const ObjectType& o) { return std::cref(o); }); - std::partial_sort( refs.begin(), refs.begin() + count, refs.end(), - [this]( const ObjectType& a, const ObjectType& b )->bool { + std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), + [this](const ObjectType& a, const ObjectType& b)->bool { return _vote_tally_buffer[a.vote_id] > _vote_tally_buffer[b.vote_id]; }); @@ -105,7 +106,7 @@ void database::update_active_witnesses() && (stake_tally <= stake_target) ) stake_tally += _witness_count_histogram_buffer[++witness_count]; - auto wits = sort_votable_objects(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); + auto wits = sort_votable_objects(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); const global_property_object& gpo = get_global_properties(); // Update witness authority @@ -171,12 +172,12 @@ void database::update_active_delegates() && (stake_tally <= stake_target) ) stake_tally += _committee_count_histogram_buffer[++delegate_count]; - auto delegates = sort_votable_objects(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); + auto delegates = sort_votable_objects(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); // Update genesis authorities if( !delegates.empty() ) { - modify( get(GRAPHENE_COMMITTEE_ACCOUNT), [&]( account_object& a ) { + modify(get(GRAPHENE_COMMITTEE_ACCOUNT), [&](account_object& a) { uint64_t total_votes = 0; map weights; a.active.weight_threshold = 0; @@ -202,11 +203,11 @@ void database::update_active_delegates() a.active.weight_threshold /= 2; a.active.weight_threshold += 1; }); - modify( get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&](account_object& a) { + modify(get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&](account_object& a) { a.active = get(GRAPHENE_COMMITTEE_ACCOUNT).active; }); } - modify( get_global_properties(), [&]( global_property_object& gp ) { + modify(get_global_properties(), [&](global_property_object& gp) { gp.active_delegates.clear(); std::transform(delegates.begin(), delegates.end(), std::inserter(gp.active_delegates, gp.active_delegates.begin()), diff --git a/libraries/chain/db_reflect_cmp.tmpl b/libraries/chain/db_reflect_cmp.tmpl new file mode 100644 index 00000000..c4522b10 --- /dev/null +++ b/libraries/chain/db_reflect_cmp.tmpl @@ -0,0 +1,43 @@ +/* + * 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. + */ + +${generated_file_banner} + +/* +object_descriptor = ${object_descriptor} +*/ + +#include +#include +#include + +#include + +namespace graphene { namespace chain { namespace impl { + +bool cmp_attr_impl( + const object& obj, + uint16_t field_num, + const vector& lit, + uint8_t opc + ) +{ +${cmp_attr_impl_body} +} + +} } } // graphene::chain::detail diff --git a/libraries/chain/field_reflector.cpp b/libraries/chain/field_reflector.cpp new file mode 100644 index 00000000..ead68f4e --- /dev/null +++ b/libraries/chain/field_reflector.cpp @@ -0,0 +1,239 @@ +/* + * 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. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace graphene::chain; + +fc::mutable_variant_object g_vo_object_types; +std::vector< fc::mutable_variant_object > g_vo_fields; + +struct serialize_object_type_member_visitor +{ + public: + template + void operator()( const char* name )const + { + fc::mutable_variant_object vo; + vo["name"] = name; + vo["type"] = fc::get_typename::name(); + vo["id"] = g_vo_fields.size(); + g_vo_fields.push_back( vo ); + } +}; + +struct serialize_object_type_visitor +{ + typedef void result_type; + + int t = 0; + serialize_object_type_visitor(int _t ):t(_t){} + + template + result_type operator()( const Type& op )const + { + fc::mutable_variant_object vo; + vo["space_id"] = Type::space_id; + vo["type_id"] = Type::type_id; + g_vo_fields.clear(); + // visit all members + fc::reflector::visit( serialize_object_type_member_visitor() ); + + vo["fields"] = g_vo_fields; + g_vo_object_types[ fc::get_typename::name() ] = vo; + } +}; + +struct getattr_switch_table_entry +{ + uint32_t _switch_val; // (space << 24) | (type << 16) | fieldnum + string _object_typename; + string _field_typename; + string _field_name; +}; + +vector< getattr_switch_table_entry > build_switch_table() +{ + vector< getattr_switch_table_entry > result; + for( const auto& item : g_vo_object_types ) + { + const variant_object& vo = item.value().get_object(); + uint32_t top = (vo["space_id"].as_uint64() << 24) | (vo["type_id"].as_uint64() << 16); + for( const auto& field : vo["fields"].get_array() ) + { + getattr_switch_table_entry e; + e._switch_val = top | field["id"].as_uint64(); + e._object_typename = item.key(); + e._field_typename = field["type"].get_string(); + e._field_name = field["name"].get_string(); + result.push_back( e ); + } + } + + std::sort( result.begin(), result.end(), + []( const getattr_switch_table_entry& a, + const getattr_switch_table_entry& b ) + { + return a._switch_val < b._switch_val; + } ); + + return result; +} + +std::string generate_cmp_attr_impl( const vector< getattr_switch_table_entry >& switch_table ) +{ + std::ostringstream out; + + // switch( space ) + // switch( type ) + // switch( fieldnum ) + // switch( opc ) + + std::map< uint8_t, + std::map< uint8_t, + std::map< uint16_t, + const getattr_switch_table_entry* > > > index; + + for( const getattr_switch_table_entry& e : switch_table ) + { + uint8_t sp = (e._switch_val >> 24) & 0xFF; + uint8_t ty = (e._switch_val >> 16) & 0xFF; + uint16_t fn = (e._switch_val ) & 0xFFFF; + auto& i0 = index; + if( i0.find( sp ) == i0.end() ) + i0[sp] = std::map< uint8_t, std::map< uint16_t, const getattr_switch_table_entry* > >(); + auto& i1 = i0[sp]; + if( i1.find( ty ) == i1.end() ) + i1[ty] = std::map< uint16_t, const getattr_switch_table_entry* >(); + auto& i2 = i1[ty]; + i2[fn] = &e; + } + out << " switch( obj.id.space() )\n" + " {\n"; + for( const auto& e0 : index ) + { + out << " case " << int( e0.first ) << ":\n" + " switch( obj.id.type() )\n" + " {\n"; + for( const auto& e1 : e0.second ) + { + out << " case " << int( e1.first ) << ":\n" + " switch( field_num )\n" + " {\n"; + for( const auto& e2 : e1.second ) + { + const std::string& ft = e2.second->_field_typename; + const std::string& ot = e2.second->_object_typename; + const std::string& fn = e2.second->_field_name; + out << " case " << int( e2.first ) << ":\n" + " {\n" + " // " << ft + << " " << ot + << "." << fn + << "\n" + " const " << ft << "& dbval = object_database::cast< " << ot << " >( obj )." << fn << ";\n" + " return _cmp< " << ft << " >( dbval, lit, opc );\n" + " }\n"; + } + out << " default:\n" + " FC_ASSERT( false, \"unrecognized field_num\" );\n" + " }\n"; + } + out << " default:\n" + " FC_ASSERT( false, \"unrecognized object type\" );\n" + " }\n"; + } + out << " default:\n" + " FC_ASSERT( false, \"unrecognized object space\" );\n" + " }\n"; + + return out.str(); +} + +static const char generated_file_banner[] = +"// _ _ __ _ _ //\n" +"// | | | | / _(_) | //\n" +"// __ _ ___ _ __ ___ _ __ __ _| |_ ___ __| | | |_ _| | ___ //\n" +"// / _` |/ _ \\ '_ \\ / _ \\ '__/ _` | __/ _ \\/ _` | | _| | |/ _ \\ //\n" +"// | (_| | __/ | | | __/ | | (_| | || __/ (_| | | | | | | __/ //\n" +"// \\__, |\\___|_| |_|\\___|_| \\__,_|\\__\\___|\\__,_| |_| |_|_|\\___| //\n" +"// __/ | //\n" +"// |___/ //\n" +"// //\n" +"// Generated by: programs/field_reflector/main.cpp //\n" +"// //\n" +"// Warning: This is a generated file, any changes made here will be //\n" +"// overwritten by the build process. If you need to change what //\n" +"// is generated here, you should either modify the reflected //\n" +"// types, or modify the code generator itself. //\n" +"// //\n" +; + +int main( int argc, char** argv ) +{ + try + { + if( argc != 3 ) + { + std::cout << "syntax: " << argv[0] << " \n"; + return 1; + } + + graphene::chain::impl::wild_object wo; + + for( int32_t i = 0; i < wo.count(); ++i ) + { + wo.set_which(i); + wo.visit( serialize_object_type_visitor(i) ); + } + + vector< getattr_switch_table_entry > switch_table = build_switch_table(); + + fc::mutable_variant_object tmpl_params; + + tmpl_params["generated_file_banner"] = generated_file_banner; + tmpl_params["object_descriptor"] = fc::json::to_string( g_vo_object_types ); + tmpl_params["cmp_attr_impl_body"] = generate_cmp_attr_impl( switch_table ); + + std::ifstream template_file( argv[1] ); + if (!template_file) + FC_THROW("Error opening template file ${template_file}", ("template_file", argv[1])); + std::stringstream ss; + ss << template_file.rdbuf(); + std::string result = fc::format_string( ss.str(), tmpl_params ); + std::ofstream result_file( argv[2] ); + result_file << result; + } + catch ( const fc::exception& e ) + { + edump((e.to_detail_string())); + return 1; + } + return 0; +} diff --git a/libraries/chain/include/graphene/chain/assert_evaluator.hpp b/libraries/chain/include/graphene/chain/assert_evaluator.hpp new file mode 100644 index 00000000..37ff998b --- /dev/null +++ b/libraries/chain/include/graphene/chain/assert_evaluator.hpp @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include + +namespace graphene { namespace chain { + + class assert_evaluator : public evaluator + { + public: + typedef assert_operation operation_type; + + void_result do_evaluate( const assert_operation& o ); + void_result do_apply( const assert_operation& o ); + }; + +} } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 7cb2db1c..e594a7f5 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -83,6 +83,7 @@ #define GRAPHENE_DEFAULT_CASHBACK_VESTING_THRESHOLD (GRAPHENE_BLOCKCHAIN_PRECISION*int64_t(100)) #define GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT) #define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000) +#define GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE 1 #define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL // counter initialization values used to derive near and far future seeds for shuffling witnesses diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index caa909b2..c26b44a6 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -109,7 +109,7 @@ namespace graphene { namespace chain { { skip_nothing = 0x00, skip_delegate_signature = 0x01, ///< used while reindexing - skip_transaction_signatures = 0x02, ///< used by non delegate nodes + skip_transaction_signatures = 0x02, ///< used by non-witness nodes skip_undo_block = 0x04, ///< used while reindexing skip_undo_transaction = 0x08, ///< used while applying block skip_transaction_dupe_check = 0x10, ///< used while reindexing @@ -117,7 +117,9 @@ namespace graphene { namespace chain { skip_block_size_check = 0x40, ///< used when applying locally generated transactions skip_tapos_check = 0x80, ///< used while reindexing -- note this skips expiration check as well skip_authority_check = 0x100, ///< used while reindexing -- disables any checking of authority on transactions - skip_merkle_check = 0x200 ///< used while reindexing + skip_merkle_check = 0x200, ///< used while reindexing + skip_assert_evaluation = 0x400, ///< used while reindexing + skip_unknown_predicate = 0x800 ///< used by non-witness nodes to allow unknown predicates }; void open(const fc::path& data_dir, const genesis_state_type& initial_allocation = genesis_state_type()); @@ -397,8 +399,8 @@ namespace graphene { namespace chain { optional _pending_block_session; vector< unique_ptr > _operation_evaluators; - template - vector> sort_votable_objects(size_t count)const; + template + vector> sort_votable_objects(size_t count)const; //////////////////// db_block.cpp //////////////////// diff --git a/libraries/chain/include/graphene/chain/db_reflect_cmp.hpp b/libraries/chain/include/graphene/chain/db_reflect_cmp.hpp new file mode 100644 index 00000000..b18f49c3 --- /dev/null +++ b/libraries/chain/include/graphene/chain/db_reflect_cmp.hpp @@ -0,0 +1,60 @@ +/* + * 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 + +#include + +namespace graphene { namespace chain { + +enum comparison_opcode +{ + opc_equal_to, + opc_not_equal_to, + opc_greater, + opc_less, + opc_greater_equal, + opc_less_equal +}; + +namespace impl { + +/** + * Compare the given field of the given object to the literal string. + * The comparison opcode is specified by opc, which should be one + * of comparison_opcode. + * + * The default behavior is to only allow opc_equal_to or + * opc_not_equal_to, and implement these based on comparing the + * serialized field to the given bytes. + * + * To override the default behavior, provide a template override + * for _cmp() in db_reflect_cmp_impl.hpp. Beware adding such an + * override will create a witness-only hardfork! + */ +bool cmp_attr_impl( + const graphene::db::object& obj, + uint16_t field_num, + const std::vector& lit, + uint8_t opc + ); +} + +} } diff --git a/libraries/chain/include/graphene/chain/db_reflect_cmp_impl.hpp b/libraries/chain/include/graphene/chain/db_reflect_cmp_impl.hpp new file mode 100644 index 00000000..68450e25 --- /dev/null +++ b/libraries/chain/include/graphene/chain/db_reflect_cmp_impl.hpp @@ -0,0 +1,115 @@ +/* + * 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 + +#include +#include + +// +// This file implements the comparison used by the assert op. +// The entry point for comparison is _cmp(), it can be specialized for +// different types. The default implementation defers to _ser_eq_cmp() +// which only allows equality comparisons, and asserts +// + +namespace graphene { namespace chain { namespace impl { + +// useful for types which have all comparison ops implemented +template< typename T > +static bool _full_cmp( const T& a, const T& b, uint8_t opc ) +{ + switch( opc ) + { + case opc_equal_to: + return (a == b); + case opc_not_equal_to: + return (a != b); + case opc_greater: + return (a > b); + case opc_less: + return (a < b); + case opc_greater_equal: + return (a >= b); + case opc_less_equal: + return (a <= b); + default: + FC_ASSERT( false, "unknown comparison operator" ); + } +} + +// useful for types which have operator== implemented +template< typename T > +static bool _eq_cmp( const T& a, const T& b, uint8_t opc ) +{ + switch( opc ) + { + case opc_equal_to: + return (a == b); + case opc_not_equal_to: + return !(a == b); + default: + FC_ASSERT( false, "unknown comparison operator" ); + } +} + +// works for every serializable type +template< typename T > +static bool _ser_eq_cmp( const T& a, const std::vector& b, uint8_t opc ) +{ + std::vector< char > _a = fc::raw::pack( a ); + return _eq_cmp( _a, b, opc ); +} + +/* +static bool _cmp( const fc::sha224& a, const fc::sha224& b, uint8_t opc ) +{ + assert( a.data_size() == b.data_size() ); + int result = memcmp( a.data(), b.data(), a.data_size() ); + switch( opc ) + { + case opc_equal_to: + return (result == 0); + case opc_not_equal_to: + return (result != 0); + case opc_greater: + return (result > 0); + case opc_less: + return (result < 0); + case opc_greater_equal: + return (result >= 0); + case opc_less_equal: + return (result <= 0); + default: + FC_ASSERT( false, "unknown comparison operator" ); + } +} +*/ + +// _cmp needs to be specialized for types which don't have overloads +// for all comparison operators + +template< typename T > +static bool _cmp( const T& a, const std::vector& b, uint8_t opc ) +{ + return _ser_eq_cmp( a, b, opc ); +} + +} } } // graphene::chain::detail diff --git a/libraries/chain/include/graphene/chain/delegate_object.hpp b/libraries/chain/include/graphene/chain/delegate_object.hpp index 29dcbfd5..9807beef 100644 --- a/libraries/chain/include/graphene/chain/delegate_object.hpp +++ b/libraries/chain/include/graphene/chain/delegate_object.hpp @@ -18,6 +18,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -33,7 +34,7 @@ namespace graphene { namespace chain { * active delegates has control. * * Delegates were separated into a separate object to make iterating over - * the set of delegate easy. + * the set of delegate easy. */ class delegate_object : public abstract_object { @@ -45,6 +46,19 @@ namespace graphene { namespace chain { vote_id_type vote_id; }; + struct by_account; + using delegate_multi_index_type = multi_index_container< + delegate_object, + indexed_by< + ordered_unique< tag, + member + >, + hashed_unique< tag, + member + > + > + >; + using delegate_index = generic_index; } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object), diff --git a/libraries/chain/include/graphene/chain/key_object.hpp b/libraries/chain/include/graphene/chain/key_object.hpp index 3a9d07da..7daaa5ab 100644 --- a/libraries/chain/include/graphene/chain/key_object.hpp +++ b/libraries/chain/include/graphene/chain/key_object.hpp @@ -22,6 +22,8 @@ #include namespace graphene { namespace chain { + typedef static_variant address_or_key; + /** * @class key_object * @brief maps an ID to a public key or address @@ -38,8 +40,9 @@ namespace graphene { namespace chain { address key_address()const; const public_key_type& key()const { return key_data.get(); } - static_variant key_data; + address_or_key key_data; }; } } +FC_REFLECT_TYPENAME( graphene::chain::address_or_key ) FC_REFLECT_DERIVED( graphene::chain::key_object, (graphene::db::object), (key_data) ) diff --git a/libraries/chain/include/graphene/chain/operation_history_object.hpp b/libraries/chain/include/graphene/chain/operation_history_object.hpp index 78c8f16a..9f5d6e9e 100644 --- a/libraries/chain/include/graphene/chain/operation_history_object.hpp +++ b/libraries/chain/include/graphene/chain/operation_history_object.hpp @@ -17,6 +17,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/operations.hpp b/libraries/chain/include/graphene/chain/operations.hpp index 6e9744ac..f34af396 100644 --- a/libraries/chain/include/graphene/chain/operations.hpp +++ b/libraries/chain/include/graphene/chain/operations.hpp @@ -102,6 +102,25 @@ namespace graphene { namespace chain { * @{ */ + /** + * @brief assert that some conditions are true. + * @ingroup operations + */ + struct assert_operation + { + asset fee; + account_id_type fee_paying_account; + vector< vector< char > > predicates; + flat_set required_auths; + + account_id_type fee_payer()const { return fee_paying_account; } + void get_required_auth(flat_set& active_auth_set, flat_set&)const; + share_type calculate_fee( const fee_schedule_type& k )const{ return k.assert_op_fee; } + void validate()const; + + void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const { acc.adjust( fee_payer(), -fee ); } + }; + /** * @brief reserves a new ID to refer to a particular key or address. * @ingroup operations @@ -1339,7 +1358,8 @@ namespace graphene { namespace chain { vesting_balance_create_operation, vesting_balance_withdraw_operation, worker_create_operation, - custom_operation + custom_operation, + assert_operation > operation; /// @} // operations group @@ -1568,7 +1588,10 @@ FC_REFLECT( graphene::chain::worker_create_operation, (fee)(owner)(work_begin_date)(work_end_date)(daily_pay)(initializer) ) FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(data) ) +FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths) ) + FC_REFLECT( graphene::chain::void_result, ) FC_REFLECT_TYPENAME( graphene::chain::operation ) +FC_REFLECT_TYPENAME( graphene::chain::operation_result ) FC_REFLECT_TYPENAME( fc::flat_set ) diff --git a/libraries/chain/include/graphene/chain/predicate.hpp b/libraries/chain/include/graphene/chain/predicate.hpp new file mode 100644 index 00000000..5980d090 --- /dev/null +++ b/libraries/chain/include/graphene/chain/predicate.hpp @@ -0,0 +1,60 @@ +/* + * 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 + +#include + +namespace graphene { namespace chain { + +class database; + +class pred_field_lit_cmp +{ +public: + pred_field_lit_cmp( + object_id_type obj_id, + uint16_t field_num, + const vector& lit, + uint8_t opc + ) : + _obj_id( obj_id ), + _field_num( field_num ), + _lit( lit ), + _opc( opc ) + {} + pred_field_lit_cmp() {} // necessary for instantiating static_variant + ~pred_field_lit_cmp() {} + + bool check_predicate( const database& db )const; + + object_id_type _obj_id; + uint16_t _field_num; + vector _lit; + uint8_t _opc; +}; + +typedef static_variant< + pred_field_lit_cmp + > predicate; + +} } + +FC_REFLECT( graphene::chain::pred_field_lit_cmp, (_obj_id)(_field_num)(_lit)(_opc) ); diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index a4d2b089..c99e8ca9 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -375,6 +375,7 @@ namespace graphene { namespace chain { uint32_t global_settle_fee; uint32_t worker_create_fee; ///< the cost to create a new worker uint32_t worker_delete_fee; ///< the cost to delete a worker + uint32_t assert_op_fee; ///< fee per assert operation }; @@ -429,6 +430,7 @@ namespace graphene { namespace chain { bool allow_non_member_whitelists = false; ///< true if non-member accounts may set whitelists and blacklists; false otherwise share_type witness_pay_per_block = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block) share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day) + uint16_t max_predicate_opcode = GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE; ///< predicate_opcode must be less than this number void validate()const { @@ -548,6 +550,7 @@ FC_REFLECT( graphene::chain::fee_schedule_type, (global_settle_fee) (worker_create_fee) (worker_delete_fee) + (assert_op_fee) ) FC_REFLECT( graphene::chain::chain_parameters, @@ -574,8 +577,11 @@ FC_REFLECT( graphene::chain::chain_parameters, (allow_non_member_whitelists) (witness_pay_per_block) (worker_budget_per_day) + (max_predicate_opcode) ) +FC_REFLECT_TYPENAME( graphene::chain::share_type ) + FC_REFLECT_TYPENAME( graphene::chain::key_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_id_type ) FC_REFLECT_TYPENAME( graphene::chain::asset_id_type ) diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index 3d6ff6fb..22c10b67 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -149,6 +149,8 @@ FC_REFLECT(graphene::chain::cdd_vesting_policy, (coin_seconds_earned_last_update) ) +FC_REFLECT_TYPENAME( graphene::chain::vesting_policy ) + FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::object), (owner) (balance) diff --git a/libraries/chain/include/graphene/chain/wild_object.hpp b/libraries/chain/include/graphene/chain/wild_object.hpp new file mode 100644 index 00000000..5b302dac --- /dev/null +++ b/libraries/chain/include/graphene/chain/wild_object.hpp @@ -0,0 +1,61 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace graphene { namespace chain { namespace impl { + +/** + * A static_variant of all object types. + * + * Used by field_reflector, this ultimately determines the object + * types which may be inspected by pred_field_lit_cmp. + */ +typedef fc::static_variant< + //null_object, + //base_object, + key_object, + account_object, + asset_object, + force_settlement_object, + delegate_object, + witness_object, + limit_order_object, + call_order_object, + //custom_object, + proposal_object, + operation_history_object, + withdraw_permission_object, + vesting_balance_object, + worker_object + > wild_object; + +} } } diff --git a/libraries/chain/include/graphene/chain/witness_object.hpp b/libraries/chain/include/graphene/chain/witness_object.hpp index 5d5ba882..82677d66 100644 --- a/libraries/chain/include/graphene/chain/witness_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_object.hpp @@ -18,6 +18,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -40,6 +41,19 @@ namespace graphene { namespace chain { witness_object() : vote_id(vote_id_type::witness) {} }; + struct by_account; + using witness_multi_index_type = multi_index_container< + witness_object, + indexed_by< + hashed_unique< tag, + member + >, + hashed_unique< tag, + member + > + > + >; + using witness_index = generic_index; } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), @@ -49,4 +63,3 @@ FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), (last_secret) (accumulated_income) (vote_id) ) - diff --git a/libraries/chain/include/graphene/chain/worker_object.hpp b/libraries/chain/include/graphene/chain/worker_object.hpp index 5306d41d..fe9fe842 100644 --- a/libraries/chain/include/graphene/chain/worker_object.hpp +++ b/libraries/chain/include/graphene/chain/worker_object.hpp @@ -188,6 +188,8 @@ FC_REFLECT( graphene::chain::refund_worker_type, (total_burned) ) FC_REFLECT( graphene::chain::refund_worker_type::initializer, ) FC_REFLECT( graphene::chain::vesting_balance_worker_type, (balance) ) FC_REFLECT( graphene::chain::vesting_balance_worker_type::initializer, (pay_vesting_period_days) ) +FC_REFLECT_TYPENAME( graphene::chain::worker_type ) +FC_REFLECT_TYPENAME( graphene::chain::worker_initializer ) FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object), (worker_account) (work_begin_date) diff --git a/libraries/chain/key_object.cpp b/libraries/chain/key_object.cpp index a0a79fe8..d19eabba 100644 --- a/libraries/chain/key_object.cpp +++ b/libraries/chain/key_object.cpp @@ -21,8 +21,6 @@ namespace graphene { namespace chain { address key_object::key_address()const { - typedef static_variant address_or_key; - switch( key_data.which() ) { case address_or_key::tag
::value: diff --git a/libraries/chain/operations.cpp b/libraries/chain/operations.cpp index 73540f23..6fb26b4a 100644 --- a/libraries/chain/operations.cpp +++ b/libraries/chain/operations.cpp @@ -813,4 +813,14 @@ share_type account_upgrade_operation::calculate_fee(const fee_schedule_type& k) return k.membership_annual_fee; } +void assert_operation::validate()const +{ + FC_ASSERT( fee.amount >= 0 ); +} +void assert_operation::get_required_auth(flat_set& active_auth_set, flat_set&)const +{ + active_auth_set.insert(fee_paying_account); + active_auth_set.insert(required_auths.begin(), required_auths.end()); +} + } } // namespace graphene::chain diff --git a/libraries/chain/predicate.cpp b/libraries/chain/predicate.cpp new file mode 100644 index 00000000..cedd6fdf --- /dev/null +++ b/libraries/chain/predicate.cpp @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include +#include + +namespace graphene { namespace chain { + +bool pred_field_lit_cmp::check_predicate( const database& db )const +{ + return graphene::chain::impl::cmp_attr_impl( db.get_object( _obj_id ), _field_num, _lit, _opc ); +} + +} } // graphene::chain diff --git a/libraries/chain/type_id.cpp b/libraries/chain/type_id.cpp new file mode 100644 index 00000000..7e1ee245 --- /dev/null +++ b/libraries/chain/type_id.cpp @@ -0,0 +1,81 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace graphene { namespace chain { + +// C++ requires that static class variables declared and initialized +// in headers must also have a definition in a single source file, +// else linker errors will occur [1]. +// +// The purpose of this source file is to collect such definitions in +// a single place. +// +// [1] http://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char + +const uint8_t account_object::space_id; +const uint8_t account_object::type_id; + +const uint8_t asset_object::space_id; +const uint8_t asset_object::type_id; + +const uint8_t block_summary_object::space_id; +const uint8_t block_summary_object::type_id; + +const uint8_t call_order_object::space_id; +const uint8_t call_order_object::type_id; + +const uint8_t delegate_object::space_id; +const uint8_t delegate_object::type_id; + +const uint8_t force_settlement_object::space_id; +const uint8_t force_settlement_object::type_id; + +const uint8_t global_property_object::space_id; +const uint8_t global_property_object::type_id; + +const uint8_t key_object::space_id; +const uint8_t key_object::type_id; + +const uint8_t limit_order_object::space_id; +const uint8_t limit_order_object::type_id; + +const uint8_t operation_history_object::space_id; +const uint8_t operation_history_object::type_id; + +const uint8_t proposal_object::space_id; +const uint8_t proposal_object::type_id; + +const uint8_t transaction_object::space_id; +const uint8_t transaction_object::type_id; + +const uint8_t vesting_balance_object::space_id; +const uint8_t vesting_balance_object::type_id; + +const uint8_t withdraw_permission_object::space_id; +const uint8_t withdraw_permission_object::type_id; + +const uint8_t witness_object::space_id; +const uint8_t witness_object::type_id; + +const uint8_t witness_schedule_object::space_id; +const uint8_t witness_schedule_object::type_id; + +const uint8_t worker_object::space_id; +const uint8_t worker_object::type_id; + +} } diff --git a/libraries/db/include/graphene/db/object.hpp b/libraries/db/include/graphene/db/object.hpp index 81458477..16ff3fba 100644 --- a/libraries/db/include/graphene/db/object.hpp +++ b/libraries/db/include/graphene/db/object.hpp @@ -93,6 +93,8 @@ namespace graphene { namespace db { virtual vector pack()const { return fc::raw::pack( static_cast(*this) ); } }; + typedef flat_map annotation_map; + /** * @class annotated_object * @brief An object that is easily extended by providing pointers to other objects, one for each space. @@ -117,12 +119,11 @@ namespace graphene { namespace db { * Annotations should be accessed via get_annotation and set_annotation so * that they can be maintained in sorted order. */ - flat_map annotations; + annotation_map annotations; }; } } // graphene::db +FC_REFLECT_TYPENAME( graphene::db::annotation_map ) FC_REFLECT( graphene::db::object, (id) ) FC_REFLECT_DERIVED_TEMPLATE( (typename Derived), graphene::db::annotated_object, (graphene::db::object), (annotations) ) - - diff --git a/libraries/db/include/graphene/db/object_database.hpp b/libraries/db/include/graphene/db/object_database.hpp index e070125e..ff4cc52d 100644 --- a/libraries/db/include/graphene/db/object_database.hpp +++ b/libraries/db/include/graphene/db/object_database.hpp @@ -87,6 +87,19 @@ namespace graphene { namespace db { ///@} + template + static const T& cast( const object& obj ) + { + assert( nullptr != dynamic_cast(&obj) ); + return static_cast(obj); + } + template + static T& cast( object& obj ) + { + assert( nullptr != dynamic_cast(&obj) ); + return static_cast(obj); + } + template const T& get( object_id_type id )const { diff --git a/libraries/fc b/libraries/fc index dde8ed9d..a8b85f6d 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit dde8ed9d7ab49807f2556488c0815f3741b11e00 +Subproject commit a8b85f6dcc4558b7a9913b59ef5dc19f3b5e62ca diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index 9c3d2ad1..13f28ee6 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -243,6 +243,9 @@ struct operation_get_impacted_accounts void operator()( const worker_create_operation& )const {} + + void operator()( const assert_operation& )const + {} }; account_create_observer::~account_create_observer() diff --git a/programs/field_reflector/CMakeLists.txt b/programs/field_reflector/CMakeLists.txt new file mode 100644 index 00000000..129ae28d --- /dev/null +++ b/programs/field_reflector/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable( field_reflector main.cpp ) +if( UNIX AND NOT APPLE ) + set(rt_library rt ) +endif() +#find_package( Gperftools QUIET ) +#if( GPERFTOOLS_FOUND ) +# message( STATUS "Found gperftools; compiling client with TCMalloc") +# list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) +#endif() + +target_link_libraries( field_reflector + PRIVATE graphene_app graphene_net graphene_chain graphene_utilities graphene_wallet fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index e74a34b3..02685c58 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -155,7 +155,7 @@ void database_fixture::verify_asset_supplies( )const total_balances[bad.options.short_backing_asset] += bad.settlement_fund; } } - for( const witness_object& witness_obj : db.get_index_type>() ) + for( const witness_object& witness_obj : db.get_index_type().indices() ) { total_balances[asset_id_type()] += witness_obj.accumulated_income; } diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 2bb9a464..cab95933 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -41,14 +41,14 @@ genesis_state_type make_genesis() { secret_hash_type::encoder enc; fc::raw::pack(enc, delegate_priv_key); fc::raw::pack(enc, secret_hash_type()); + auto secret = secret_hash_type::hash(enc.result()); for( int i = 0; i < 10; ++i ) { - genesis_state.allocation_targets.emplace_back("init"+fc::to_string(i), delegate_priv_key.get_public_key(), 0, true); - genesis_state.initial_committee.push_back({"init"+fc::to_string(i)}); + auto name = "init"+fc::to_string(i); + genesis_state.allocation_targets.emplace_back(name, delegate_priv_key.get_public_key(), 0, true); + genesis_state.initial_committee.push_back({name}); + genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret}); } - genesis_state.initial_witnesses = vector(10, {"committee-account", - delegate_priv_key.get_public_key(), - secret_hash_type::hash(enc.result())}); return genesis_state; } @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE( block_database_test ) for( uint32_t i = 0; i < 5; ++i ) { if( i > 0 ) b.previous = b.id(); - b.witness = witness_id_type(i+1); + b.witness = witness_id_type(i+1); bdb.store( b.id(), b ); auto fetch = bdb.fetch_by_number( b.block_num() ); diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 5e35977d..e61c052b 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -29,6 +29,9 @@ #include #include +#include +#include + #include #include "../common/database_fixture.hpp" @@ -797,6 +800,47 @@ BOOST_AUTO_TEST_CASE( unimp_force_settlement_unavailable ) */ } +BOOST_AUTO_TEST_CASE( assert_op_test ) +{ + try { + // create some objects + auto nathan_private_key = generate_private_key("nathan"); + auto dan_private_key = generate_private_key("dan"); + public_key_type nathan_public_key = nathan_private_key.get_public_key(); + public_key_type dan_public_key = dan_private_key.get_public_key(); + key_id_type nathan_key_id = register_key(nathan_public_key).id; + key_id_type dan_key_id = register_key(dan_public_key).id; + account_id_type nathan_id = create_account("nathan", nathan_key_id).id; + + assert_operation op; + decltype( key_object::key_data ) lit_key = nathan_public_key; + + // nathan checks that his public key is equal to the given value. + op.fee_paying_account = nathan_id; + op.predicates = vector< vector< char > >(); + op.predicates.push_back( + fc::raw::pack( + predicate( + pred_field_lit_cmp( nathan_key_id, 1, fc::raw::pack( lit_key ), opc_equal_to ) + ) + ) ); + trx.operations.push_back(op); + trx.sign( nathan_key_id, nathan_private_key ); + PUSH_TX( db, trx ); + + // nathan checks that his public key is not equal to the given value (fail) + op.predicates.back() = + fc::raw::pack( + predicate( + pred_field_lit_cmp( nathan_key_id, 1, fc::raw::pack( lit_key ), opc_not_equal_to ) + ) + ); + trx.operations.back() = op; + trx.sign( nathan_key_id, nathan_private_key ); + BOOST_CHECK_THROW( PUSH_TX( db, trx ), fc::exception ); + } FC_LOG_AND_RETHROW() +} + // TODO: Write linear VBO tests BOOST_AUTO_TEST_SUITE_END()