From 5599ace331adb1b56abda73d9192d9efe32edc64 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 2 May 2017 10:14:01 -0500 Subject: [PATCH] Cleanup/fixes Break up files, fix a typo here and there... no interesting behavior changes. --- .gitignore | 2 + libraries/chain/database.cpp | 3 +- .../include/eos/chain/account_object.hpp | 147 -------------- .../include/eos/chain/action_objects.hpp | 125 ++++++++++++ .../chain/include/eos/chain/database.hpp | 3 +- .../include/eos/chain/key_value_object.hpp | 59 ++++++ .../chain/include/eos/chain/type_object.hpp | 60 ++++++ libraries/types/CMakeLists.txt | 1 + .../types/include/eos/types/TypeParser.hpp | 4 +- libraries/types/include/eos/types/native.hpp | 2 +- .../native_system_contract_plugin.hpp | 2 +- .../native_system_contract_plugin.cpp | 185 +----------------- .../system_contract_impl.hpp | 177 +++++++++++++++++ tests/tests/block_tests.cpp | 1 + 14 files changed, 436 insertions(+), 335 deletions(-) create mode 100644 libraries/chain/include/eos/chain/action_objects.hpp create mode 100644 libraries/chain/include/eos/chain/key_value_object.hpp create mode 100644 libraries/chain/include/eos/chain/type_object.hpp create mode 100644 plugins/native_system_contract_plugin/system_contract_impl.hpp diff --git a/.gitignore b/.gitignore index b7f662e1d..7bd3bbd56 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ hardfork.hpp libraries/utilities/git_revision.cpp +libraries/types/include/eos/types/generated.hpp + libraries/wallet/Doxyfile libraries/wallet/api_documentation.cpp libraries/wallet/doxygen diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 7d91554d4..2b3a4b259 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/libraries/chain/include/eos/chain/account_object.hpp b/libraries/chain/include/eos/chain/account_object.hpp index b2b754b02..a2e4a963c 100644 --- a/libraries/chain/include/eos/chain/account_object.hpp +++ b/libraries/chain/include/eos/chain/account_object.hpp @@ -113,157 +113,10 @@ namespace eos { namespace chain { > >; - - /** - * This table defines all of the event handlers for every contract. Every message is - * delivered TO a particular contract and also processed in parallel by several other contracts. - * - * Each account can define a custom handler based upon the tuple { processor, recipient, type } where - * processor is the account that is processing the message, recipient is the account specified by - * message::recipient and type is messagse::type. - * - * - */ - class action_code_object : public chainbase::object - { - OBJECT_CTOR(action_code_object, (validate_action)(validate_precondition)(apply) ) - - id_type id; - account_id_type recipient; - account_id_type processor; - TypeName type; ///< the name of the action (defines serialization) - - shared_string validate_action; ///< read only access to action - shared_string validate_precondition; ///< read only access to state - shared_string apply; ///< the code that executes the state transition - }; - - struct by_parent; - struct by_processor_recipient_type; - using action_code_index = chainbase::shared_multi_index_container< - action_code_object, - indexed_by< - ordered_unique, member>, - ordered_unique, - composite_key< action_code_object, - member, - member, - member - > - > - > - >; - - - /** - * Maps the permission level on the code to the permission level specififed by owner, when specifying a contract the - * contract will specify 1 permission_object per action, and by default the parent of that permission object will be - * the active permission of the contract; however, the contract owner could group their actions any way they like. - * - * When it comes time to evaluate whether User can call Action on Contract with UserPermissionLevel the algorithm - * operates as follows: - * - * let scope_permission = action_code.permission - * while( ! mapping for (scope_permission / owner ) - * scope_permission = scope_permission.parent - * if( !scope_permission ) - * user permission => active - * break; - * - * Now that we know the required user permission... - * - * while( ! transaction.has( user_permission ) ) - * user_permission = user_permission.parent - * if( !user_permission ) - * throw invalid permission - * pass - */ - class action_permission_object : public chainbase::object - { - OBJECT_CTOR(action_permission_object) - - id_type id; - account_id_type owner; ///< the account whose permission we seek - permission_object::id_type scope_permission; ///< the scope permission defined by the contract for the action - permission_object::id_type owner_permission; ///< the owner permission that is required - }; - - struct by_owner_scope; - using action_permission_index = chainbase::shared_multi_index_container< - action_permission_object, - indexed_by< - ordered_unique, member>, - ordered_unique, - composite_key< action_permission_object, - member, - member - > - > - > - >; - - struct type_object : public chainbase::object { - OBJECT_CTOR(type_object, (fields)) - - id_type id; - account_name scope; - TypeName name; - account_name base_scope; - TypeName base; - shared_vector fields; - }; - - struct by_scope_name; - using type_index = chainbase::shared_multi_index_container< - type_object, - indexed_by< - ordered_unique, member>, - ordered_unique, - composite_key< type_object, - member, - member - > - > - > - >; - - struct key_value_object : public chainbase::object { - OBJECT_CTOR(key_value_object, (key)(value)) - - id_type id; - account_name scope; - shared_string key; - shared_string value; - }; - - struct by_scope_key; - using key_value_index = chainbase::shared_multi_index_container< - key_value_object, - indexed_by< - ordered_unique, member>, - ordered_unique, - composite_key< key_value_object, - member, - member - >, - composite_key_compare< std::less, chainbase::strcmp_less > - > - > - >; - - } } // eos::chain CHAINBASE_SET_INDEX_TYPE(eos::chain::account_object, eos::chain::account_index) CHAINBASE_SET_INDEX_TYPE(eos::chain::permission_object, eos::chain::permission_index) -CHAINBASE_SET_INDEX_TYPE(eos::chain::action_code_object, eos::chain::action_code_index) -CHAINBASE_SET_INDEX_TYPE(eos::chain::action_permission_object, eos::chain::action_permission_index) -CHAINBASE_SET_INDEX_TYPE(eos::chain::type_object, eos::chain::type_index) -CHAINBASE_SET_INDEX_TYPE(eos::chain::key_value_object, eos::chain::key_value_index) FC_REFLECT(eos::chain::account_object, (id)(name)(balance)(votes)(converting_votes)(last_vote_conversion) ) FC_REFLECT(eos::chain::permission_object, (id)(owner)(parent)(name) ) -FC_REFLECT(eos::chain::action_code_object, (id)(recipient)(processor)(type)(validate_action)(validate_precondition)(apply) ) -FC_REFLECT(eos::chain::action_permission_object, (id)(owner)(owner_permission)(scope_permission) ) -FC_REFLECT(eos::chain::type_object, (id)(scope)(name)(base_scope)(base)(fields) ) -FC_REFLECT(eos::chain::key_value_object, (id)(scope)(key)(value) ) diff --git a/libraries/chain/include/eos/chain/action_objects.hpp b/libraries/chain/include/eos/chain/action_objects.hpp new file mode 100644 index 000000000..2997debed --- /dev/null +++ b/libraries/chain/include/eos/chain/action_objects.hpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, Respective Authors. + * + * 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. + */ +#pragma once +#include +#include + +#include "multi_index_includes.hpp" + +namespace eos { namespace chain { + + /** + * This table defines all of the event handlers for every contract. Every message is + * delivered TO a particular contract and also processed in parallel by several other contracts. + * + * Each account can define a custom handler based upon the tuple { processor, recipient, type } where + * processor is the account that is processing the message, recipient is the account specified by + * message::recipient and type is messagse::type. + * + * + */ + class action_code_object : public chainbase::object + { + OBJECT_CTOR(action_code_object, (validate_action)(validate_precondition)(apply) ) + + id_type id; + account_id_type recipient; + account_id_type processor; + TypeName type; ///< the name of the action (defines serialization) + + shared_string validate_action; ///< read only access to action + shared_string validate_precondition; ///< read only access to state + shared_string apply; ///< the code that executes the state transition + }; + + struct by_parent; + struct by_processor_recipient_type; + using action_code_index = chainbase::shared_multi_index_container< + action_code_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< action_code_object, + member, + member, + member + > + > + > + >; + + /** + * Maps the permission level on the code to the permission level specififed by owner, when specifying a contract the + * contract will specify 1 permission_object per action, and by default the parent of that permission object will be + * the active permission of the contract; however, the contract owner could group their actions any way they like. + * + * When it comes time to evaluate whether User can call Action on Contract with UserPermissionLevel the algorithm + * operates as follows: + * + * let scope_permission = action_code.permission + * while( ! mapping for (scope_permission / owner ) + * scope_permission = scope_permission.parent + * if( !scope_permission ) + * user permission => active + * break; + * + * Now that we know the required user permission... + * + * while( ! transaction.has( user_permission ) ) + * user_permission = user_permission.parent + * if( !user_permission ) + * throw invalid permission + * pass + */ + class action_permission_object : public chainbase::object + { + OBJECT_CTOR(action_permission_object) + + id_type id; + account_id_type owner; ///< the account whose permission we seek + permission_object::id_type scope_permission; ///< the scope permission defined by the contract for the action + permission_object::id_type owner_permission; ///< the owner permission that is required + }; + + struct by_owner_scope; + using action_permission_index = chainbase::shared_multi_index_container< + action_permission_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< action_permission_object, + member, + member + > + > + > + >; + +} } // eos::chain + +CHAINBASE_SET_INDEX_TYPE(eos::chain::action_code_object, eos::chain::action_code_index) +CHAINBASE_SET_INDEX_TYPE(eos::chain::action_permission_object, eos::chain::action_permission_index) + +FC_REFLECT(eos::chain::action_code_object, (id)(recipient)(processor)(type)(validate_action)(validate_precondition)(apply) ) +FC_REFLECT(eos::chain::action_permission_object, (id)(owner)(owner_permission)(scope_permission) ) diff --git a/libraries/chain/include/eos/chain/database.hpp b/libraries/chain/include/eos/chain/database.hpp index 22c3870fe..d9642ff98 100644 --- a/libraries/chain/include/eos/chain/database.hpp +++ b/libraries/chain/include/eos/chain/database.hpp @@ -24,6 +24,7 @@ #pragma once #include #include +#include #include #include #include @@ -112,8 +113,8 @@ namespace eos { namespace chain { create([&](type_object& o) { o.scope = scope; o.name = stru.name; - o.scope = scope; o.base = stru.base; +#warning QUESTION Should we be setting o.base_scope here? o.fields.reserve(stru.fields.size()); for( const auto& f : stru.fields ) o.fields.push_back( f ); diff --git a/libraries/chain/include/eos/chain/key_value_object.hpp b/libraries/chain/include/eos/chain/key_value_object.hpp new file mode 100644 index 000000000..a2b3d7f85 --- /dev/null +++ b/libraries/chain/include/eos/chain/key_value_object.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, Respective Authors. + * + * 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. + */ +#pragma once +#include + +#include "multi_index_includes.hpp" + +namespace eos { namespace chain { + + struct key_value_object : public chainbase::object { + OBJECT_CTOR(key_value_object, (key)(value)) + + id_type id; + account_name scope; + shared_string key; + shared_string value; + }; + + struct by_scope_key; + using key_value_index = chainbase::shared_multi_index_container< + key_value_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< key_value_object, + member, + member + >, + composite_key_compare< std::less, chainbase::strcmp_less > + > + > + >; + +} } // eos::chain + +CHAINBASE_SET_INDEX_TYPE(eos::chain::key_value_object, eos::chain::key_value_index) + +FC_REFLECT(eos::chain::key_value_object, (id)(scope)(key)(value) ) diff --git a/libraries/chain/include/eos/chain/type_object.hpp b/libraries/chain/include/eos/chain/type_object.hpp new file mode 100644 index 000000000..845710abf --- /dev/null +++ b/libraries/chain/include/eos/chain/type_object.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Respective Authors. + * + * 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. + */ +#pragma once +#include + +#include "multi_index_includes.hpp" + +namespace eos { namespace chain { + + struct type_object : public chainbase::object { + OBJECT_CTOR(type_object, (fields)) + + id_type id; + account_name scope; + TypeName name; + account_name base_scope; + TypeName base; + shared_vector fields; + }; + + struct by_scope_name; + using type_index = chainbase::shared_multi_index_container< + type_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key< type_object, + member, + member + > + > + > + >; + +} } // eos::chain + +CHAINBASE_SET_INDEX_TYPE(eos::chain::type_object, eos::chain::type_index) + +FC_REFLECT(eos::chain::type_object, (id)(scope)(name)(base_scope)(base)(fields) ) diff --git a/libraries/types/CMakeLists.txt b/libraries/types/CMakeLists.txt index d1c969d5b..8b48c1bec 100644 --- a/libraries/types/CMakeLists.txt +++ b/libraries/types/CMakeLists.txt @@ -5,6 +5,7 @@ add_library( eos_types PublicKey.cpp TypeParser.cpp native.cpp + ${HEADERS} ) target_include_directories( eos_types PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) target_link_libraries( eos_types fc ) diff --git a/libraries/types/include/eos/types/TypeParser.hpp b/libraries/types/include/eos/types/TypeParser.hpp index 3092407b1..f26d72dae 100644 --- a/libraries/types/include/eos/types/TypeParser.hpp +++ b/libraries/types/include/eos/types/TypeParser.hpp @@ -85,8 +85,8 @@ namespace eos { return itr->second; if( known.find(name) != known.end() ) - FC_ASSERT( !"type is a built in type" ); - FC_ASSERT( !"unknown type", "", ("n", name) ); + FC_ASSERT( false, "type is a built in type" ); + FC_ASSERT( false, "unknown type: ${n}", ("n", name) ); } virtual TypeName resolveTypedef( TypeName name )const override { auto tdef = typedefs.find( name ); diff --git a/libraries/types/include/eos/types/native.hpp b/libraries/types/include/eos/types/native.hpp index f6f8f0464..eeadb5848 100644 --- a/libraries/types/include/eos/types/native.hpp +++ b/libraries/types/include/eos/types/native.hpp @@ -74,7 +74,7 @@ namespace eos { static const Struct& type() { static Struct result = { "Field ", "", { {"name", "FieldName"}, - {"type", "TypeNmae"} + {"type", "TypeName"} } }; return result; diff --git a/plugins/native_system_contract_plugin/include/eos/native_system_contract_plugin/native_system_contract_plugin.hpp b/plugins/native_system_contract_plugin/include/eos/native_system_contract_plugin/native_system_contract_plugin.hpp index 3d1ec02f1..1e41b743a 100644 --- a/plugins/native_system_contract_plugin/include/eos/native_system_contract_plugin/native_system_contract_plugin.hpp +++ b/plugins/native_system_contract_plugin/include/eos/native_system_contract_plugin/native_system_contract_plugin.hpp @@ -20,7 +20,7 @@ public: APPBASE_PLUGIN_REQUIRES((chain_plugin)) virtual void set_program_options(options_description&, options_description&) override {} - void plugin_initialize(const variables_map& options); + void plugin_initialize(const variables_map&); void plugin_startup(); void plugin_shutdown(); diff --git a/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp b/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp index 19b25b12c..74cdf5092 100644 --- a/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp +++ b/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -8,184 +8,6 @@ namespace eos { using namespace chain; -/************************************************************ - * - * Transfer Handlers - * - ***********************************************************/ -void Transfer_validate(chain::message_validate_context& context) { - auto transfer = context.msg.as(); - try { - EOS_ASSERT(transfer.amount > Asset(0), message_validate_exception, "Must transfer a positive amount"); - EOS_ASSERT(context.msg.has_notify(transfer.to), message_validate_exception, "Must notify recipient of transfer"); - } FC_CAPTURE_AND_RETHROW( (transfer) ) -} - -void Transfer_validate_preconditions(chain::precondition_validate_context& context) { - const auto& db = context.db; - auto transfer = context.msg.as(); - - db.get_account(transfer.to); ///< make sure this exists - const auto& from = db.get_account(transfer.from); - EOS_ASSERT(from.balance >= transfer.amount.amount, message_precondition_exception, "Insufficient Funds", - ("from.balance",from.balance)("transfer.amount",transfer.amount)); -} -void Transfer_apply(chain::apply_context& context) { - auto& db = context.mutable_db; - auto transfer = context.msg.as(); - const auto& from = db.get_account(transfer.from); - const auto& to = db.get_account(transfer.to); - db.modify(from, [&](account_object& a) { - a.balance -= transfer.amount; - }); - db.modify(to, [&](account_object& a) { - a.balance += transfer.amount; - }); -} - -/************************************************************ - * - * DefineStruct - * - ***********************************************************/ -void DefineStruct_validate( chain::message_validate_context& context ) { - auto msg = context.msg.as(); - FC_ASSERT( msg.definition.name != TypeName(), "must define a type name" ); -// TODO: validate_type_name( msg.definition.name ); -// validate_type_name( msg.definition.base ); -} -void DefineStruct_validate_preconditions( chain::precondition_validate_context& context ) { - auto& db = context.db; - auto msg = context.msg.as(); - db.get( msg.scope ); -#warning TODO: db.get(msg.base_scope ) -} -void DefineStruct_apply( chain::apply_context& context ) { - auto& db = context.mutable_db; - auto msg = context.msg.as(); - - db.create( [&]( auto& type ) { - type.scope = msg.scope; - type.name = msg.definition.name; - type.fields.reserve( msg.definition.fields.size() ); -#warning TODO: type.base_scope = - type.base = msg.definition.base; - for( const auto& f : msg.definition.fields ) { - type.fields.push_back(f); - } - }); -} - - -void validate_type_name( const TypeName& name ) { - // TODO: starts with capital letter and is alphanumeric -} - - -/************************************************************ - * - * SetMessageHandler - * - ***********************************************************/ -void SetMessageHandler_validate( chain::message_validate_context& context ) { - auto msg = context.msg.as(); -} -void SetMessageHandler_validate_preconditions( chain::precondition_validate_context& context ) -{ try { - auto& db = context.db; - auto msg = context.msg.as(); - idump((msg.recipient)(msg.processor)(msg.type)); - // db.get( boost::make_tuple(msg.account, msg.type) ); - - // TODO: verify code compiles -} FC_CAPTURE_AND_RETHROW() } - -void SetMessageHandler_apply( chain::apply_context& context ) { - auto& db = context.mutable_db; - auto msg = context.msg.as(); - const auto& processor_acnt = db.get( msg.processor ); - const auto& recipient_acnt = db.get( msg.recipient ); - db.create( [&]( auto& action ){ - action.processor = processor_acnt.id; - action.recipient = recipient_acnt.id; - action.type = msg.type; - action.validate_action = msg.validate.c_str(); - action.validate_precondition = msg.precondition.c_str(); - action.apply = msg.apply.c_str(); - }); - idump((msg.apply)); -} - - - - -/************************************************************ - * - * Create Account Handlers - * - ***********************************************************/ -///@{ - - -void Authority_validate_preconditions( const Authority& auth, chain::precondition_validate_context& context ) { - for( const auto& a : auth.accounts ) - context.db.get( a.permission.account ); -} - -void CreateAccount_validate(chain::message_validate_context& context) { - auto create = context.msg.as(); - - EOS_ASSERT( validate(create.owner), message_validate_exception, "Invalid owner authority"); - EOS_ASSERT( validate(create.active), message_validate_exception, "Invalid active authority"); - EOS_ASSERT( validate(create.recovery), message_validate_exception, "Invalid recovery authority"); -} - -void CreateAccount_validate_preconditions(chain::precondition_validate_context& context) { - const auto& db = context.db; - auto create = context.msg.as(); - - db.get_account(create.creator); ///< make sure it exists - - auto existing_account = db.find(create.name); - EOS_ASSERT(existing_account == nullptr, message_precondition_exception, - "Cannot create account named ${name}, as that name is already taken", - ("name", create.name)); - - const auto& creator = db.get_account(context.msg.sender); - EOS_ASSERT(creator.balance >= create.deposit, message_precondition_exception, "Insufficient Funds"); - -#warning TODO: make sure creation deposit is greater than min account balance - - Authority_validate_preconditions( create.owner, context ); - Authority_validate_preconditions( create.active, context ); - Authority_validate_preconditions( create.recovery, context ); -} - -void CreateAccount_apply(chain::apply_context& context) { - auto& db = context.mutable_db; - auto create = context.msg.as(); - db.modify(db.get_account(context.msg.sender), [&create](account_object& a) { - a.balance -= create.deposit; - }); - const auto& new_account = db.create([&create](account_object& a) { - a.name = create.name; - a.balance = create.deposit; - }); - const auto& owner_permission = db.create([&create, &new_account](permission_object& p) { - p.name = "owner"; - p.parent = 0; - p.owner = new_account.id; - p.auth = std::move(create.owner); - }); - db.create([&create, &owner_permission](permission_object& p) { - p.name = "active"; - p.parent = owner_permission.id; - p.owner = owner_permission.owner; - p.auth = std::move(create.active); - }); -} -///@} Create Account Handlers - class native_system_contract_plugin_impl { public: native_system_contract_plugin_impl(database& db) @@ -198,18 +20,17 @@ native_system_contract_plugin::native_system_contract_plugin() : my(new native_system_contract_plugin_impl(app().get_plugin().db())){} native_system_contract_plugin::~native_system_contract_plugin(){} -void native_system_contract_plugin::plugin_initialize(const variables_map& options) { +void native_system_contract_plugin::plugin_initialize(const variables_map&) { install(my->db); } void native_system_contract_plugin::plugin_startup() { - // Make the magic happen } void native_system_contract_plugin::plugin_shutdown() { - // OK, that's enough magic } +#include "system_contract_impl.hpp" void native_system_contract_plugin::install(database& db) { #define SET_HANDLERS(name) \ db.set_validate_handler("sys", "sys", #name, &name ## _validate); \ diff --git a/plugins/native_system_contract_plugin/system_contract_impl.hpp b/plugins/native_system_contract_plugin/system_contract_impl.hpp new file mode 100644 index 000000000..8d28db754 --- /dev/null +++ b/plugins/native_system_contract_plugin/system_contract_impl.hpp @@ -0,0 +1,177 @@ +/************************************************************ + * + * Transfer Handlers + * + ***********************************************************/ +void Transfer_validate(chain::message_validate_context& context) { + auto transfer = context.msg.as(); + try { + EOS_ASSERT(transfer.amount > Asset(0), message_validate_exception, "Must transfer a positive amount"); + EOS_ASSERT(context.msg.has_notify(transfer.to), message_validate_exception, "Must notify recipient of transfer"); + } FC_CAPTURE_AND_RETHROW( (transfer) ) +} + +void Transfer_validate_preconditions(chain::precondition_validate_context& context) { + const auto& db = context.db; + auto transfer = context.msg.as(); + + db.get_account(transfer.to); ///< make sure this exists + const auto& from = db.get_account(transfer.from); + EOS_ASSERT(from.balance >= transfer.amount.amount, message_precondition_exception, "Insufficient Funds", + ("from.balance",from.balance)("transfer.amount",transfer.amount)); +} +void Transfer_apply(chain::apply_context& context) { + auto& db = context.mutable_db; + auto transfer = context.msg.as(); + const auto& from = db.get_account(transfer.from); + const auto& to = db.get_account(transfer.to); + db.modify(from, [&](account_object& a) { + a.balance -= transfer.amount; + }); + db.modify(to, [&](account_object& a) { + a.balance += transfer.amount; + }); +} + +/************************************************************ + * + * DefineStruct + * + ***********************************************************/ +void DefineStruct_validate(chain::message_validate_context& context) { + auto msg = context.msg.as(); + FC_ASSERT( msg.definition.name != TypeName(), "must define a type name" ); +// TODO: validate_type_name( msg.definition.name ); +// validate_type_name( msg.definition.base ); +} +void DefineStruct_validate_preconditions(chain::precondition_validate_context& context) { + auto& db = context.db; + auto msg = context.msg.as(); + db.get( msg.scope ); +#warning TODO: db.get(msg.base_scope ) +} +void DefineStruct_apply(chain::apply_context& context) { + auto& db = context.mutable_db; + auto msg = context.msg.as(); + + db.create( [&]( auto& type ) { + type.scope = msg.scope; + type.name = msg.definition.name; + type.fields.reserve( msg.definition.fields.size() ); +#warning TODO: type.base_scope = + type.base = msg.definition.base; + for( const auto& f : msg.definition.fields ) { + type.fields.push_back(f); + } + }); +} + + +void validate_type_name(const TypeName& name) { + // TODO: starts with capital letter and is alphanumeric +} + + +/************************************************************ + * + * SetMessageHandler + * + ***********************************************************/ +void SetMessageHandler_validate(chain::message_validate_context& context) { + auto msg = context.msg.as(); +} +void SetMessageHandler_validate_preconditions(chain::precondition_validate_context& context) +{ try { + auto& db = context.db; + auto msg = context.msg.as(); + idump((msg.recipient)(msg.processor)(msg.type)); + // db.get( boost::make_tuple(msg.account, msg.type) ); + + // TODO: verify code compiles +} FC_CAPTURE_AND_RETHROW() } + +void SetMessageHandler_apply(chain::apply_context& context) { + auto& db = context.mutable_db; + auto msg = context.msg.as(); + const auto& processor_acnt = db.get( msg.processor ); + const auto& recipient_acnt = db.get( msg.recipient ); + db.create( [&]( auto& action ){ + action.processor = processor_acnt.id; + action.recipient = recipient_acnt.id; + action.type = msg.type; + action.validate_action = msg.validate.c_str(); + action.validate_precondition = msg.precondition.c_str(); + action.apply = msg.apply.c_str(); + }); + idump((msg.apply)); +} + + + + +/************************************************************ + * + * Create Account Handlers + * + ***********************************************************/ +///@{ + + +void Authority_validate_preconditions(const Authority& auth, chain::precondition_validate_context& context) { + for( const auto& a : auth.accounts ) + context.db.get( a.permission.account ); +} + +void CreateAccount_validate(chain::message_validate_context& context) { + auto create = context.msg.as(); + + EOS_ASSERT( validate(create.owner), message_validate_exception, "Invalid owner authority"); + EOS_ASSERT( validate(create.active), message_validate_exception, "Invalid active authority"); + EOS_ASSERT( validate(create.recovery), message_validate_exception, "Invalid recovery authority"); +} + +void CreateAccount_validate_preconditions(chain::precondition_validate_context& context) { + const auto& db = context.db; + auto create = context.msg.as(); + + db.get_account(create.creator); ///< make sure it exists + + auto existing_account = db.find(create.name); + EOS_ASSERT(existing_account == nullptr, message_precondition_exception, + "Cannot create account named ${name}, as that name is already taken", + ("name", create.name)); + + const auto& creator = db.get_account(context.msg.sender); + EOS_ASSERT(creator.balance >= create.deposit, message_precondition_exception, "Insufficient Funds"); + +#warning TODO: make sure creation deposit is greater than min account balance + + Authority_validate_preconditions( create.owner, context ); + Authority_validate_preconditions( create.active, context ); + Authority_validate_preconditions( create.recovery, context ); +} + +void CreateAccount_apply(chain::apply_context& context) { + auto& db = context.mutable_db; + auto create = context.msg.as(); + db.modify(db.get_account(context.msg.sender), [&create](account_object& a) { + a.balance -= create.deposit; + }); + const auto& new_account = db.create([&create](account_object& a) { + a.name = create.name; + a.balance = create.deposit; + }); + const auto& owner_permission = db.create([&create, &new_account](permission_object& p) { + p.name = "owner"; + p.parent = 0; + p.owner = new_account.id; + p.auth = std::move(create.owner); + }); + db.create([&create, &owner_permission](permission_object& p) { + p.name = "active"; + p.parent = owner_permission.id; + p.owner = owner_permission.owner; + p.auth = std::move(create.active); + }); +} +///@} Create Account Handlers diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index b3d80a8c5..059f914c5 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include -- GitLab