Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Create special accounts #79

Merged
merged 7 commits into from
Jul 17, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion libraries/chain/chain_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,8 @@ void chain_controller::create_block_summary(const signed_block& next_block) {
}

void chain_controller::update_global_properties(const signed_block& b) {
// If we're at the end of a round, update the BlockchainConfiguration and producer schedule
// If we're at the end of a round, update the BlockchainConfiguration, producer schedule
// and "producers" special account authority
if (b.block_num() % config::BlocksPerRound == 0) {
auto schedule = calculate_next_round(b);
auto config = _admin->get_blockchain_configuration(_db, schedule);
Expand All @@ -717,6 +718,16 @@ void chain_controller::update_global_properties(const signed_block& b) {
gpo.active_producers = std::move(schedule);
gpo.configuration = std::move(config);
});

auto active_producers_authority = types::Authority(uint32_t(gpo.active_producers.size()*config::ProducersAuthorityThreshold), {}, {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This like will break once you replace the double constant with a constant number of producers threshold.

The active producers size should always be 21.

for(auto& name : gpo.active_producers) {
active_producers_authority.accounts.push_back({{name, config::ActiveName}, 1});
}

auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::ProducersAccountName, config::ActiveName) );
_db.modify(po,[active_producers_authority] (permission_object& po) {
po.auth = active_producers_authority;
});
}
}

Expand Down
19 changes: 14 additions & 5 deletions libraries/chain/include/eos/chain/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,29 @@
* THE SOFTWARE.
*/
#pragma once
#include <eos/types/native.hpp>
#include <eos/types/Asset.hpp>
#include <eos/types/types.hpp>

namespace eos { namespace config {
using types::UInt32;
using types::UInt64;
using types::UInt128;
using types::ShareType;
using types::Asset;
using types::AccountName;
using types::PermissionName;

const static char KeyPrefix[] = "EOS";

const static char SystemContractName[] = "system";
const static char EosContractName[] = "eos";
const static char StakedBalanceContractName[] = "staked";
const static AccountName SystemContractName = N(system);
const static AccountName EosContractName = N(eos);
const static AccountName StakedBalanceContractName = N(staked);

const static AccountName NobodyAccountName = N(nobody);
const static AccountName AnybodyAccountName = N(anybody);
const static AccountName ProducersAccountName = N(producers);

const static PermissionName ActiveName = N(active);
const static PermissionName OwnerName = N(owner);

const static ShareType InitialTokenSupply = Asset::fromString("90000000.00000000 EOS").amount;

Expand All @@ -53,6 +61,7 @@ const static ShareType DefaultElectedPay = Asset(100).amount;
const static ShareType DefaultRunnerUpPay = Asset(75).amount;
const static ShareType DefaultMinEosBalance = Asset(100).amount;
const static UInt32 DefaultMaxTrxLifetime = 60*60;
const static double ProducersAuthorityThreshold = 2.0/3.0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should never use double's in our code, especially any logic that is run as part of consensus.


const static int BlocksPerRound = 21;
const static int VotedProducersPerRound = 20;
Expand Down
31 changes: 31 additions & 0 deletions libraries/native_contract/native_contract_chain_initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <eos/native_contract/system_contract.hpp>

#include <eos/chain/producer_object.hpp>
#include <eos/chain/permission_object.hpp>

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
Expand Down Expand Up @@ -143,6 +144,36 @@ std::vector<chain::Message> native_contract_chain_initializer::prepare_database(
});
boost::copy(genesis.initial_producers | CreateProducer, std::back_inserter(messages_to_process));

// Create special accounts
auto create_special_account = [this, &db](Name name, const auto& owner, const auto& active) {
db.create<account_object>([this, &name](account_object& a) {
a.name = name;
a.creation_date = genesis.initial_timestamp;
});
const auto& owner_permission = db.create<permission_object>([&owner, &name](permission_object& p) {
p.name = config::OwnerName;
p.parent = 0;
p.owner = name;
p.auth = std::move(owner);
});
db.create<permission_object>([&active, &owner_permission](permission_object& p) {
p.name = config::ActiveName;
p.parent = owner_permission.id;
p.owner = owner_permission.owner;
p.auth = std::move(active);
});
};

auto empty_authority = types::Authority(0, {}, {});
auto active_producers_authority = types::Authority(uint32_t(genesis.initial_producers.size()*config::ProducersAuthorityThreshold), {}, {});
for(auto& p : genesis.initial_producers) {
active_producers_authority.accounts.push_back({{p.owner_name, config::ActiveName}, 1});
}

//CreateNativeAccount(config::AnybodyAccountName, 0);
create_special_account(config::NobodyAccountName, empty_authority, empty_authority);
create_special_account(config::ProducersAccountName, empty_authority, active_producers_authority);

return messages_to_process;
}

Expand Down
38 changes: 28 additions & 10 deletions libraries/types/include/eos/types/native.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include <fc/reflect/reflect.hpp>

#define N(X) eos::types::string_to_name(#X)

namespace eos { namespace types {
using namespace boost::multiprecision;

Expand Down Expand Up @@ -55,7 +57,33 @@ namespace eos { namespace types {
using Int128 = boost::multiprecision::int128_t;
using Int256 = boost::multiprecision::int256_t;
using uint128_t = unsigned __int128; /// native clang/gcc 128 intrinisic

static constexpr char char_to_symbol( char c ) {
if( c >= 'a' && c <= 'z' )
return (c - 'a') + 1;
if( c >= '1' && c <= '5' )
return (c - '1') + 26;
return 0;
}

static constexpr uint64_t string_to_name( const char* str ) {
uint32_t len = 0;
while( str[len] ) ++len;

uint64_t value = 0;

for( uint32_t i = 0; i <= 12 && i < len; ++i ) {
value <<= 5;
value |= char_to_symbol( str[ len -1 - i ] );
}

if( len == 13 ) {
value <<= 4;
value |= 0x0f & char_to_symbol( str[ 12 ] );
}
return value;
}

struct Name {
uint64_t value = 0;
bool valid()const { return 0 == (value >> 60); }
Expand All @@ -80,16 +108,6 @@ namespace eos { namespace types {
}
}FC_CAPTURE_AND_RETHROW( (str) ) }


char char_to_symbol( char c ) const {
if( c >= 'a' && c <= 'z' )
return (c - 'a') + 1;
if( c >= '1' && c <= '5' )
return (c - '1') + 27;
//FC_ASSERT( c == '.', "invalid character '${c}' (${i}) in Name string", ("c", String(&c,1))("i",int(c)) );
return 0;
}

Name( uint64_t v = 0 ):value(v){
// FC_ASSERT( !(v>>(5*12)), "invalid name id" );
}
Expand Down
143 changes: 143 additions & 0 deletions tests/tests/special_accounts_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include <algorithm>
#include <vector>
#include <iterator>
#include <boost/test/unit_test.hpp>

#include <eos/chain/chain_controller.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/permission_object.hpp>
#include <eos/chain/key_value_object.hpp>

#include <eos/native_contract/producer_objects.hpp>

#include <eos/utilities/tempdir.hpp>

#include <fc/crypto/digest.hpp>

#include <boost/test/unit_test.hpp>
#include <boost/range/algorithm/find.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/range/algorithm/permutation.hpp>

#include "../common/database_fixture.hpp"

using namespace eos;
using namespace chain;

BOOST_AUTO_TEST_SUITE(special_account_tests)

//Check special accounts exits in genesis
BOOST_FIXTURE_TEST_CASE(accounts_exists, testing_fixture)
{ try {

Make_Blockchain(chain);

auto nobody = chain_db.find<account_object, by_name>(config::NobodyAccountName);
BOOST_CHECK(nobody != nullptr);
const auto& nobody_active_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::NobodyAccountName, config::ActiveName));
BOOST_CHECK_EQUAL(nobody_active_authority.auth.threshold, 0);
BOOST_CHECK_EQUAL(nobody_active_authority.auth.accounts.size(), 0);
BOOST_CHECK_EQUAL(nobody_active_authority.auth.keys.size(), 0);

const auto& nobody_owner_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::NobodyAccountName, config::OwnerName));
BOOST_CHECK_EQUAL(nobody_owner_authority.auth.threshold, 0);
BOOST_CHECK_EQUAL(nobody_owner_authority.auth.accounts.size(), 0);
BOOST_CHECK_EQUAL(nobody_owner_authority.auth.keys.size(), 0);

// TODO: check for anybody account
//auto anybody = chain_db.find<account_object, by_name>(config::AnybodyAccountName);
//BOOST_CHECK(anybody == nullptr);

auto producers = chain_db.find<account_object, by_name>(config::ProducersAccountName);
BOOST_CHECK(producers != nullptr);

auto& gpo = chain_db.get<global_property_object>();
auto threshold = uint32_t(gpo.active_producers.size()*config::ProducersAuthorityThreshold);

const auto& producers_active_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::ProducersAccountName, config::ActiveName));
BOOST_CHECK_EQUAL(producers_active_authority.auth.threshold, threshold);
BOOST_CHECK_EQUAL(producers_active_authority.auth.accounts.size(), gpo.active_producers.size());
BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0);

std::vector<AccountName> active_auth;
for(auto& apw : producers_active_authority.auth.accounts) {
active_auth.emplace_back(apw.permission.account);
}

std::vector<AccountName> diff;
std::set_difference(
active_auth.begin(),
active_auth.end(),
gpo.active_producers.begin(),
gpo.active_producers.end(),
std::inserter(diff, diff.begin())
);

BOOST_CHECK_EQUAL(diff.size(), 0);

const auto& producers_owner_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::ProducersAccountName, config::OwnerName));
BOOST_CHECK_EQUAL(producers_owner_authority.auth.threshold, 0);
BOOST_CHECK_EQUAL(producers_owner_authority.auth.accounts.size(), 0);
BOOST_CHECK_EQUAL(producers_owner_authority.auth.keys.size(), 0);

} FC_LOG_AND_RETHROW() }

//Check correct authority when new set of producers are elected
BOOST_FIXTURE_TEST_CASE(producers_authority, testing_fixture)
{ try {

Make_Blockchain(chain)
chain.produce_blocks();

Make_Account(chain, alice);
Make_Account(chain, bob);
Make_Account(chain, charlie);

Make_Account(chain, newproducer1); Make_Producer(chain, newproducer1);
Make_Account(chain, newproducer2); Make_Producer(chain, newproducer2);
Make_Account(chain, newproducer3); Make_Producer(chain, newproducer3);

Approve_Producer(chain, alice, newproducer1, true);
Approve_Producer(chain, bob, newproducer2, true);
Approve_Producer(chain, charlie, newproducer3, true);

chain.produce_blocks(config::BlocksPerRound - chain.head_block_num() );

auto& gpo = chain_db.get<global_property_object>();

BOOST_REQUIRE(boost::find(gpo.active_producers, "newproducer1") != gpo.active_producers.end());
BOOST_REQUIRE(boost::find(gpo.active_producers, "newproducer2") != gpo.active_producers.end());
BOOST_REQUIRE(boost::find(gpo.active_producers, "newproducer3") != gpo.active_producers.end());

auto threshold = uint32_t(gpo.active_producers.size()*config::ProducersAuthorityThreshold);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line will also break when constant changed.


const auto& producers_active_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::ProducersAccountName, config::ActiveName));
BOOST_CHECK_EQUAL(producers_active_authority.auth.threshold, threshold);
BOOST_CHECK_EQUAL(producers_active_authority.auth.accounts.size(), gpo.active_producers.size());
BOOST_CHECK_EQUAL(producers_active_authority.auth.keys.size(), 0);

std::vector<AccountName> active_auth;
for(auto& apw : producers_active_authority.auth.accounts) {
active_auth.emplace_back(apw.permission.account);
}

std::vector<AccountName> diff;
std::set_difference(
active_auth.begin(),
active_auth.end(),
gpo.active_producers.begin(),
gpo.active_producers.end(),
std::inserter(diff, diff.begin())
);

BOOST_CHECK_EQUAL(diff.size(), 0);

const auto& producers_owner_authority = chain_db.get<permission_object, by_owner>(boost::make_tuple(config::ProducersAccountName, config::OwnerName));
BOOST_CHECK_EQUAL(producers_owner_authority.auth.threshold, 0);
BOOST_CHECK_EQUAL(producers_owner_authority.auth.accounts.size(), 0);
BOOST_CHECK_EQUAL(producers_owner_authority.auth.keys.size(), 0);

} FC_LOG_AND_RETHROW() }


BOOST_AUTO_TEST_SUITE_END()