diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 9625ca299d53349ff847fea4e38f8d4a431a36d2..107fa621a332adfabb60de8a63851ed22dfb3747 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -738,6 +738,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.name = "sys"; }); register_message_type("sys", "Transfer"); + register_message_type("sys", "CreateAccount"); // Create initial accounts for (const auto& acct : genesis_state.initial_accounts) { diff --git a/libraries/chain/include/eos/chain/account_object.hpp b/libraries/chain/include/eos/chain/account_object.hpp index cbeb1fafa8875708abc7e96980eb21613daf15e4..55bd9b6a050e04ed00cb67a9b2a76d63d74703d9 100644 --- a/libraries/chain/include/eos/chain/account_object.hpp +++ b/libraries/chain/include/eos/chain/account_object.hpp @@ -29,11 +29,28 @@ namespace eos { namespace chain { - class shared_authority { + struct shared_authority { shared_authority( chainbase::allocator alloc ) :accounts(alloc),keys(alloc) {} + shared_authority& operator=(const Authority& a) { + threshold = a.threshold; + accounts = decltype(accounts)(a.accounts.begin(), a.accounts.end(), accounts.get_allocator()); + keys = decltype(keys)(a.keys.begin(), a.keys.end(), keys.get_allocator()); + return *this; + } + shared_authority& operator=(Authority&& a) { + threshold = a.threshold; + accounts.reserve(a.accounts.size()); + for (auto& p : a.accounts) + accounts.emplace_back(std::move(p)); + keys.reserve(a.keys.size()); + for (auto& p : a.keys) + keys.emplace_back(std::move(p)); + return *this; + } + uint32_t threshold = 0; shared_vector accounts; shared_vector keys; @@ -41,10 +58,10 @@ namespace eos { namespace chain { class account_object : public chainbase::object { - OBJECT_CTOR(account_object, (name)) + OBJECT_CTOR(account_object) id_type id; - shared_string name; + account_name name; uint64_t balance = 0; uint64_t votes = 0; uint64_t converting_votes = 0; @@ -56,8 +73,7 @@ namespace eos { namespace chain { account_object, indexed_by< ordered_unique, member>, - ordered_unique, member, - chainbase::strcmp_less> + ordered_unique, member> > >; diff --git a/libraries/chain/include/eos/chain/authority.hpp b/libraries/chain/include/eos/chain/authority.hpp index b16507fd3b0d96238aa2245b8b1b81d226c3e811..f5defd0239ec2b646f223671690015c5e8692495 100644 --- a/libraries/chain/include/eos/chain/authority.hpp +++ b/libraries/chain/include/eos/chain/authority.hpp @@ -19,8 +19,27 @@ namespace eos { namespace chain { uint32_t threshold = 0; vector accounts; vector keys; + + bool validate() const { + if (threshold == 0) + return false; + uint32_t score = 0; + for (const auto& p : accounts) + score += p.weight; + for (const auto& p : keys) + score += p.weight; + return score >= threshold; + } + set referenced_accounts() const { + set results; + std::transform(accounts.begin(), accounts.end(), std::inserter(results, results.begin()), + [](const PermissionLevel& p) { return p.account; }); + return results; + } }; } } // eos::chain -FC_REFLECT( eos::chain::Authority, (threshold)(accounts)(keys) ) +FC_REFLECT(eos::chain::PermissionLevel, (account)(level)(weight)) +FC_REFLECT(eos::chain::KeyPermission, (key)(weight)) +FC_REFLECT(eos::chain::Authority, (threshold)(accounts)(keys)) 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 d82b8dce5be02614738036da8f4c80045eb29110..1c81af570e1dbf858091cbefa71f5a7fb1f4d950 100644 --- a/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp +++ b/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp @@ -14,7 +14,7 @@ void Transfer_validate_preconditions(chain::precondition_validate_context& conte const auto& db = context.db; auto transfer = context.msg.as(); const auto& from = db.get_account(context.msg.sender); - EOS_ASSERT(from.balance > transfer.amount, message_precondition_exception, "Insufficient Funds", + EOS_ASSERT(from.balance >= transfer.amount, message_precondition_exception, "Insufficient Funds", ("from.balance",from.balance)("transfer.amount",transfer.amount)); } void Transfer_apply(chain::apply_context& context) { @@ -30,6 +30,52 @@ void Transfer_apply(chain::apply_context& context) { }); } +void CreateAccount_validate(chain::message_validate_context& context) { + auto create = context.msg.as(); + EOS_ASSERT(create.owner.validate(), message_validate_exception, "Invalid owner authority"); + EOS_ASSERT(create.active.validate(), message_validate_exception, "Invalid active authority"); +} +void CreateAccount_validate_preconditions(chain::precondition_validate_context& context) { + const auto& db = context.db; + auto create = context.msg.as(); + + auto existing_account = db.find(create.new_account); + EOS_ASSERT(existing_account == nullptr, message_precondition_exception, + "Cannot create account named ${name}, as that name is already taken", + ("name", create.new_account)); + + const auto& creator = db.get_account(context.msg.sender); + EOS_ASSERT(creator.balance >= create.initial_balance, message_precondition_exception, "Insufficient Funds"); + + for (const auto& account : create.owner.referenced_accounts()) + db.get_account(account); + for (const auto& account : create.active.referenced_accounts()) + db.get_account(account); +} +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.initial_balance; + }); + const auto& new_account = db.create([&create](account_object& a) { + a.name = create.new_account; + a.balance = create.initial_balance; + }); + 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); + }); +} + class native_system_contract_plugin_impl { public: native_system_contract_plugin_impl(database& db) @@ -61,5 +107,6 @@ void native_system_contract_plugin::install(database& db) { db.set_apply_handler("sys", "sys", #name, &name ## _apply) SET_HANDLERS(Transfer); + SET_HANDLERS(CreateAccount); } }