diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 435dbc8f6b7..89044359816 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1144,7 +1144,12 @@ void database::set_apply_handler( const AccountName& contract, const AccountName const account_object& database::get_account( const AccountName& name )const { try { - return get(name); -} FC_CAPTURE_AND_RETHROW( (name) ) } + return get(name); +} FC_CAPTURE_AND_RETHROW((name)) } + +const producer_object&database::get_producer(const types::AccountName& name) const { +try { + return get(get_account(name).id); +} FC_CAPTURE_AND_RETHROW((name)) } } } diff --git a/libraries/chain/include/eos/chain/database.hpp b/libraries/chain/include/eos/chain/database.hpp index e501389164f..c4591616f95 100644 --- a/libraries/chain/include/eos/chain/database.hpp +++ b/libraries/chain/include/eos/chain/database.hpp @@ -193,7 +193,8 @@ namespace eos { namespace chain { const signed_transaction& get_recent_transaction( const transaction_id_type& trx_id )const; std::vector get_block_ids_on_fork(block_id_type head_of_fork) const; - const account_object& get_account( const AccountName& name )const; + const account_object& get_account(const AccountName& name)const; + const producer_object& get_producer(const AccountName& name)const; /** * Calculate the percent of block production slots that were missed in the diff --git a/libraries/chain/include/eos/chain/types.hpp b/libraries/chain/include/eos/chain/types.hpp index 981f3f1740c..0a3a3b8e0d6 100644 --- a/libraries/chain/include/eos/chain/types.hpp +++ b/libraries/chain/include/eos/chain/types.hpp @@ -65,7 +65,8 @@ { c(*this); } #define OBJECT_CTOR(...) BOOST_PP_OVERLOAD(OBJECT_CTOR, __VA_ARGS__)(__VA_ARGS__) -#define EOS_SYSTEM_CONTRACT_FUNCTIONS (Transfer)(CreateAccount)(CreateProducer)(DefineStruct)(SetMessageHandler) +#define EOS_SYSTEM_CONTRACT_FUNCTIONS (Transfer)(CreateAccount)(CreateProducer)(UpdateProducer) \ + (DefineStruct)(SetMessageHandler) namespace eos { namespace chain { using std::map; 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 010dc66210a..2fcde1aab7b 100644 --- a/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp +++ b/plugins/native_system_contract_plugin/native_system_contract_plugin.cpp @@ -34,29 +34,6 @@ void native_system_contract_plugin::plugin_startup() { void native_system_contract_plugin::plugin_shutdown() { } -void CreateProducer_validate(chain::message_validate_context& context) { - auto create = context.msg.as(); - EOS_ASSERT(create.name.size() > 0, message_validate_exception, "Producer owner name cannot be empty"); - EOS_ASSERT(create.key != PublicKey(), message_validate_exception, "Producer signing key cannot be null"); -} -void CreateProducer_validate_preconditions(chain::precondition_validate_context& context) { - auto create = context.msg.as(); - const auto& db = context.db; - const auto& owner = db.get_account(create.name); - auto producer = db.find(owner.id); - EOS_ASSERT(producer == nullptr, message_precondition_exception, - "Account ${name} already has a block producer", ("name", create.name)); -} -void CreateProducer_apply(chain::apply_context& context) { - auto create = context.msg.as(); - auto& db = context.mutable_db; - const auto& owner = db.get_account(create.name); - db.create([&create, &owner](producer_object& p) { - p.owner = owner.id; - p.signing_key = create.key; - }); -} - #include "system_contract_impl.hpp" void native_system_contract_plugin::install(database& db) { #define SET_HANDLERS(name) \ diff --git a/plugins/native_system_contract_plugin/system_contract_impl.hpp b/plugins/native_system_contract_plugin/system_contract_impl.hpp index 02d3d5e62b2..a8a0e5362b9 100644 --- a/plugins/native_system_contract_plugin/system_contract_impl.hpp +++ b/plugins/native_system_contract_plugin/system_contract_impl.hpp @@ -66,12 +66,6 @@ void DefineStruct_apply(chain::apply_context& context) { }); } - -void validate_type_name(const TypeName& name) { - // TODO: starts with capital letter and is alphanumeric -} - - /************************************************************ * * SetMessageHandler @@ -115,8 +109,6 @@ void SetMessageHandler_apply(chain::apply_context& context) { * ***********************************************************/ ///@{ - - void Authority_validate_preconditions(const Authority& auth, chain::precondition_validate_context& context) { for(const auto& a : auth.accounts) context.db.get(a.permission.account); @@ -175,3 +167,52 @@ void CreateAccount_apply(chain::apply_context& context) { }); } ///@} Create Account Handlers + +/************************************************************ + * + * Create/Update Producer Handlers + * + ***********************************************************/ +///@{ +void CreateProducer_validate(chain::message_validate_context& context) { + auto create = context.msg.as(); + EOS_ASSERT(create.name.size() > 0, message_validate_exception, "Producer owner name cannot be empty"); +} +void CreateProducer_validate_preconditions(chain::precondition_validate_context& context) { + auto create = context.msg.as(); + const auto& db = context.db; + const auto& owner = db.get_account(create.name); + auto producer = db.find(owner.id); + EOS_ASSERT(producer == nullptr, message_precondition_exception, + "Account ${name} already has a block producer", ("name", create.name)); +} +void CreateProducer_apply(chain::apply_context& context) { + auto create = context.msg.as(); + auto& db = context.mutable_db; + const auto& owner = db.get_account(create.name); + db.create([&create, &owner](producer_object& p) { + p.owner = owner.id; + p.signing_key = create.key; + }); +} + +void UpdateProducer_validate(chain::message_validate_context& context) { + auto update = context.msg.as(); + EOS_ASSERT(update.name.size() > 0, message_validate_exception, "Producer owner name cannot be empty"); +} +void UpdateProducer_validate_preconditions(chain::precondition_validate_context& context) { + const auto& db = context.db; + auto update = context.msg.as(); + const auto& producer = db.get_producer(update.name); + EOS_ASSERT(producer.signing_key != update.newKey, message_validate_exception, + "Producer's new key may not be identical to old key"); +} +void UpdateProducer_apply(chain::apply_context& context) { + auto& db = context.mutable_db; + auto update = context.msg.as(); + const auto& producer = db.get_producer(update.name); + db.modify(producer, [&update](producer_object& p) { + p.signing_key = update.newKey; + }); +} +///@} Create/Update Producer Handlers diff --git a/tests/tests/system_contract_tests.cpp b/tests/tests/system_contract_tests.cpp index 3f5b4c0f49e..2cbe86e0ff4 100644 --- a/tests/tests/system_contract_tests.cpp +++ b/tests/tests/system_contract_tests.cpp @@ -82,7 +82,7 @@ BOOST_FIXTURE_TEST_CASE(create_account, testing_fixture) } } FC_LOG_AND_RETHROW() } -// Simple test of creating a new block producer +// Simple test of creating/updating a new block producer BOOST_FIXTURE_TEST_CASE(producer_creation, testing_fixture) { try { MKDB(db) @@ -100,24 +100,30 @@ BOOST_FIXTURE_TEST_CASE(producer_creation, testing_fixture) CreateAccount ca{"init0", "producer", producer_authority, producer_authority, {}, Asset(100)}; trx.messages.emplace_back("init0", "sys", vector{}, "CreateAccount", ca); db.push_transaction(trx); - trx.messages.clear(); + trx.clear(); CreateProducer cp{"producer", producer_pub_key}; trx.messages.emplace_back("producer", "sys", vector{}, "CreateProducer", cp); db.push_transaction(trx); while (db.head_block_num() < 3) { - auto producer_account = db.find("producer"); - BOOST_REQUIRE(producer_account != nullptr); - auto producer = db.find(producer_account->id); - BOOST_REQUIRE(producer != nullptr); - BOOST_CHECK_EQUAL(producer->owner, producer_account->id); - BOOST_CHECK_EQUAL(producer->signing_key, producer_pub_key); - BOOST_CHECK_EQUAL(producer->last_aslot, 0); - BOOST_CHECK_EQUAL(producer->total_missed, 0); - BOOST_CHECK_EQUAL(producer->last_confirmed_block_num, 0); + auto& producer = db.get_producer("producer"); + BOOST_CHECK_EQUAL(db.get(producer.owner).name, "producer"); + BOOST_CHECK_EQUAL(producer.signing_key, producer_pub_key); + BOOST_CHECK_EQUAL(producer.last_aslot, 0); + BOOST_CHECK_EQUAL(producer.total_missed, 0); + BOOST_CHECK_EQUAL(producer.last_confirmed_block_num, 0); db.produce_blocks(); } + + auto signing_key = private_key_type::regenerate(fc::digest("producer signing key")); + PublicKey signing_public_key = signing_key.get_public_key(); + trx.clear(); + trx.messages.emplace_back("producer", "sys", vector{}, "UpdateProducer", + UpdateProducer{"producer", signing_key.get_public_key()}); + db.push_transaction(trx); + auto& producer = db.get_producer("producer"); + BOOST_CHECK_EQUAL(producer.signing_key, signing_public_key); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END()