提交 5599ace3 编写于 作者: N Nathan Hourt

Cleanup/fixes

Break up files, fix a typo here and there... no interesting behavior
changes.
上级 36ae434b
......@@ -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
......
......@@ -28,7 +28,8 @@
#include <eos/chain/block_summary_object.hpp>
#include <eos/chain/chain_property_object.hpp>
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/account_object.hpp>
#include <eos/chain/key_value_object.hpp>
#include <eos/chain/action_objects.hpp>
#include <eos/chain/transaction_object.hpp>
#include <eos/chain/producer_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<action_code_object_type, action_code_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<tag<by_id>, member<action_code_object, action_code_object::id_type, &action_code_object::id>>,
ordered_unique<tag<by_processor_recipient_type>,
composite_key< action_code_object,
member<action_code_object, account_id_type, &action_code_object::processor>,
member<action_code_object, account_id_type, &action_code_object::recipient>,
member<action_code_object, TypeName, &action_code_object::type>
>
>
>
>;
/**
* 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<action_permission_object_type, action_permission_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<tag<by_id>, member<action_permission_object, action_permission_object::id_type, &action_permission_object::id>>,
ordered_unique<tag<by_owner_scope>,
composite_key< action_permission_object,
member<action_permission_object, account_id_type, &action_permission_object::owner>,
member<action_permission_object, permission_object::id_type, &action_permission_object::scope_permission>
>
>
>
>;
struct type_object : public chainbase::object<type_object_type, type_object> {
OBJECT_CTOR(type_object, (fields))
id_type id;
account_name scope;
TypeName name;
account_name base_scope;
TypeName base;
shared_vector<Field> fields;
};
struct by_scope_name;
using type_index = chainbase::shared_multi_index_container<
type_object,
indexed_by<
ordered_unique<tag<by_id>, member<type_object, type_object::id_type, &type_object::id>>,
ordered_unique<tag<by_scope_name>,
composite_key< type_object,
member<type_object, account_name, &type_object::scope>,
member<type_object, message_type, &type_object::name>
>
>
>
>;
struct key_value_object : public chainbase::object<key_value_object_type, key_value_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<tag<by_id>, member<key_value_object, key_value_object::id_type, &key_value_object::id>>,
ordered_unique<tag<by_scope_key>,
composite_key< key_value_object,
member<key_value_object, account_name, &key_value_object::scope>,
member<key_value_object, shared_string, &key_value_object::key>
>,
composite_key_compare< std::less<account_name>, 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) )
/*
* 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 <eos/chain/types.hpp>
#include <eos/chain/account_object.hpp>
#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<action_code_object_type, action_code_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<tag<by_id>, member<action_code_object, action_code_object::id_type, &action_code_object::id>>,
ordered_unique<tag<by_processor_recipient_type>,
composite_key< action_code_object,
member<action_code_object, account_id_type, &action_code_object::processor>,
member<action_code_object, account_id_type, &action_code_object::recipient>,
member<action_code_object, TypeName, &action_code_object::type>
>
>
>
>;
/**
* 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<action_permission_object_type, action_permission_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<tag<by_id>, member<action_permission_object, action_permission_object::id_type, &action_permission_object::id>>,
ordered_unique<tag<by_owner_scope>,
composite_key< action_permission_object,
member<action_permission_object, account_id_type, &action_permission_object::owner>,
member<action_permission_object, permission_object::id_type, &action_permission_object::scope_permission>
>
>
>
>;
} } // 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) )
......@@ -24,6 +24,7 @@
#pragma once
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/account_object.hpp>
#include <eos/chain/type_object.hpp>
#include <eos/chain/node_property_object.hpp>
#include <eos/chain/fork_database.hpp>
#include <eos/chain/genesis_state.hpp>
......@@ -112,8 +113,8 @@ namespace eos { namespace chain {
create<type_object>([&](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 );
......
/*
* 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 <eos/chain/types.hpp>
#include "multi_index_includes.hpp"
namespace eos { namespace chain {
struct key_value_object : public chainbase::object<key_value_object_type, key_value_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<tag<by_id>, member<key_value_object, key_value_object::id_type, &key_value_object::id>>,
ordered_unique<tag<by_scope_key>,
composite_key< key_value_object,
member<key_value_object, account_name, &key_value_object::scope>,
member<key_value_object, shared_string, &key_value_object::key>
>,
composite_key_compare< std::less<account_name>, 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) )
/*
* 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 <eos/chain/types.hpp>
#include "multi_index_includes.hpp"
namespace eos { namespace chain {
struct type_object : public chainbase::object<type_object_type, type_object> {
OBJECT_CTOR(type_object, (fields))
id_type id;
account_name scope;
TypeName name;
account_name base_scope;
TypeName base;
shared_vector<Field> fields;
};
struct by_scope_name;
using type_index = chainbase::shared_multi_index_container<
type_object,
indexed_by<
ordered_unique<tag<by_id>, member<type_object, type_object::id_type, &type_object::id>>,
ordered_unique<tag<by_scope_name>,
composite_key< type_object,
member<type_object, account_name, &type_object::scope>,
member<type_object, message_type, &type_object::name>
>
>
>
>;
} } // 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) )
......@@ -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 )
......
......@@ -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 );
......
......@@ -74,7 +74,7 @@ namespace eos {
static const Struct& type() {
static Struct result = { "Field ", "", {
{"name", "FieldName"},
{"type", "TypeNmae"}
{"type", "TypeName"}
}
};
return result;
......
......@@ -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();
......
#include <eos/native_system_contract_plugin/native_system_contract_plugin.hpp>
#include <eos/chain/account_object.hpp>
#include <eos/chain/action_objects.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/types/native.hpp>
#include <eos/types/generated.hpp>
......@@ -8,184 +8,6 @@
namespace eos {
using namespace chain;
/************************************************************
*
* Transfer Handlers
*
***********************************************************/
void Transfer_validate(chain::message_validate_context& context) {
auto transfer = context.msg.as<Transfer>();
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<Transfer>();
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<Transfer>();
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<DefineStruct>();
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<DefineStruct>();
db.get<account_object,by_name>( msg.scope );
#warning TODO: db.get<account_object>(msg.base_scope )
}
void DefineStruct_apply( chain::apply_context& context ) {
auto& db = context.mutable_db;
auto msg = context.msg.as<DefineStruct>();
db.create<type_object>( [&]( 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<SetMessageHandler>();
}
void SetMessageHandler_validate_preconditions( chain::precondition_validate_context& context )
{ try {
auto& db = context.db;
auto msg = context.msg.as<SetMessageHandler>();
idump((msg.recipient)(msg.processor)(msg.type));
// db.get<type_object,by_scope_name>( 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<SetMessageHandler>();
const auto& processor_acnt = db.get<account_object,by_name>( msg.processor );
const auto& recipient_acnt = db.get<account_object,by_name>( msg.recipient );
db.create<action_code_object>( [&]( 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<account_object,by_name>( a.permission.account );
}
void CreateAccount_validate(chain::message_validate_context& context) {
auto create = context.msg.as<CreateAccount>();
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<CreateAccount>();
db.get_account(create.creator); ///< make sure it exists
auto existing_account = db.find<account_object, by_name>(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<CreateAccount>();
db.modify(db.get_account(context.msg.sender), [&create](account_object& a) {
a.balance -= create.deposit;
});
const auto& new_account = db.create<account_object>([&create](account_object& a) {
a.name = create.name;
a.balance = create.deposit;
});
const auto& owner_permission = db.create<permission_object>([&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<permission_object>([&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<chain_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); \
......
/************************************************************
*
* Transfer Handlers
*
***********************************************************/
void Transfer_validate(chain::message_validate_context& context) {
auto transfer = context.msg.as<Transfer>();
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<Transfer>();
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<Transfer>();
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<DefineStruct>();
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<DefineStruct>();
db.get<account_object,by_name>( msg.scope );
#warning TODO: db.get<account_object>(msg.base_scope )
}
void DefineStruct_apply(chain::apply_context& context) {
auto& db = context.mutable_db;
auto msg = context.msg.as<DefineStruct>();
db.create<type_object>( [&]( 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<SetMessageHandler>();
}
void SetMessageHandler_validate_preconditions(chain::precondition_validate_context& context)
{ try {
auto& db = context.db;
auto msg = context.msg.as<SetMessageHandler>();
idump((msg.recipient)(msg.processor)(msg.type));
// db.get<type_object,by_scope_name>( 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<SetMessageHandler>();
const auto& processor_acnt = db.get<account_object,by_name>( msg.processor );
const auto& recipient_acnt = db.get<account_object,by_name>( msg.recipient );
db.create<action_code_object>( [&]( 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<account_object,by_name>( a.permission.account );
}
void CreateAccount_validate(chain::message_validate_context& context) {
auto create = context.msg.as<CreateAccount>();
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<CreateAccount>();
db.get_account(create.creator); ///< make sure it exists
auto existing_account = db.find<account_object, by_name>(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<CreateAccount>();
db.modify(db.get_account(context.msg.sender), [&create](account_object& a) {
a.balance -= create.deposit;
});
const auto& new_account = db.create<account_object>([&create](account_object& a) {
a.name = create.name;
a.balance = create.deposit;
});
const auto& owner_permission = db.create<permission_object>([&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<permission_object>([&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
......@@ -27,6 +27,7 @@
#include <eos/chain/database.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/account_object.hpp>
#include <eos/chain/key_value_object.hpp>
#include <eos/native_system_contract_plugin/native_system_contract_plugin.hpp>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册