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

Commit

Permalink
Exodus of Genesis
Browse files Browse the repository at this point in the history
OK, so this turned out to be a **massive** refactor that I thought I'd
never finish, and no, I don't remember everything that changed here, but
I think it all worked out to be better than before, and almost all of it
was fairly necessary/the best of available options. Whew. I am SO glad
this is finally done.

High level goal: Continue refining the native contracts (ref #15),
specifically
walling off their state into their own contract DBs rather than globally
shared (read: stuff that race conditions are made of) general blockchain
state.

The first real change I made in this commit, which precipitated the
avalanche of changes that followed before the project became consistent
again, was to move the account balance out of account_object (globally
shared) to an object known only to the Eos Contract, thus eliminating
the possibility of race conditions/nondeterministic behavior.

The trouble is, balances are set at genesis. Genesis is processed by
chain_controller. chain_controller cannot know about balances, since
those are an abstraction defined on top of the Eos contract, which is an
abstraction defined on top of chain_controller. So all of genesis had to
be reimagined, and quite a lot of architectural changes had to be made
in order to create a logically consistent solution.

Changes (probably incomplete):
 - Fix up notifications within the native contract to support
precondition validation as well as application

 - Add notify handlers for CreateAccount to Eos and Staked Balance
contracts

 - Move account's liquid balance of EOS from account_object to
BalanceObject

 - Replace {producer,account}_object::id_type with AccountName most
everywhere except block_header, which still contains a
producer_object::id_type (potentially in violation of protocol
standards, but I want to confirm that before fixing it)
   - Reason: The name is not significantly slower, as it's fixed length so
no heap allocs, and it simplifies the code in quite a few places by
allowing us to look up objects directly rather than indirectly by
looking up an ID to get an intermediate object to get a handle for the
object we really wanted

 - Replace native_system_contract_plugin with native_contract library
   - Reason: The plugin was getting in the way. The native system
contract C++ implementation is simply too fundamental unless/until we
have a scripted implementation that works until the native
implementation gets installed

 - Completely reimagine genesis initialization, taking it largely out of
the hands of chain_controller and putting it in the hands of
native_contract
   - Reason: chain_controller understands relatively little about
genesis. It understands global_property_object and producer_object, but
not BalanceObject or StakedBalanceObject, etc... It also doesn't
understand the native_contract, and things like installing the native
contract, setting up accounts/balances, etc. all need to be handled by
something... native_contract is the most logical place to put it.

Sorry for the enormous commit... alas, this was the first time I got it
all building again and passing tests in days.
  • Loading branch information
nathanielhourt committed Jun 9, 2017
1 parent 0c2140a commit 55a8470
Show file tree
Hide file tree
Showing 45 changed files with 645 additions and 640 deletions.
1 change: 1 addition & 0 deletions libraries/CMakeLists.txt
Expand Up @@ -7,3 +7,4 @@ add_subdirectory( chain )
add_subdirectory( egenesis )
add_subdirectory( utilities )
add_subdirectory( appbase )
add_subdirectory( native_contract )
1 change: 0 additions & 1 deletion libraries/chain/CMakeLists.txt
Expand Up @@ -13,7 +13,6 @@ add_library( eos_chain

block_log.cpp
BlockchainConfiguration.cpp
chain_model.cpp

${HEADERS}
)
Expand Down
201 changes: 78 additions & 123 deletions libraries/chain/chain_controller.cpp

Large diffs are not rendered by default.

15 changes: 0 additions & 15 deletions libraries/chain/chain_model.cpp

This file was deleted.

38 changes: 22 additions & 16 deletions libraries/chain/include/eos/chain/account_object.hpp
Expand Up @@ -55,15 +55,15 @@ namespace eos { namespace chain {
shared_vector<types::AccountPermissionWeight> accounts;
shared_vector<types::KeyPermissionWeight> keys;
};

class account_object : public chainbase::object<account_object_type, account_object>
{

class account_object : public chainbase::object<account_object_type, account_object> {
OBJECT_CTOR(account_object)

id_type id;
AccountName name;
Asset balance;
Time creation_date;
};
using account_id_type = account_object::id_type;

struct by_name;
using account_index = chainbase::shared_multi_index_container<
Expand All @@ -74,39 +74,41 @@ namespace eos { namespace chain {
>
>;

class permission_object : public chainbase::object<permission_object_type, permission_object>
{
class permission_object : public chainbase::object<permission_object_type, permission_object> {
OBJECT_CTOR(permission_object, (auth) )

id_type id;
account_id_type owner; ///< the account this permission belongs to
AccountName owner; ///< the account this permission belongs to
id_type parent; ///< parent permission
PermissionName name;
shared_authority auth; ///< TODO
};



struct by_parent;
struct by_owner;
using permission_index = chainbase::shared_multi_index_container<
permission_object,
indexed_by<
ordered_unique<tag<by_id>, member<permission_object, permission_object::id_type, &permission_object::id>>,
ordered_unique<tag<by_parent>,
composite_key< permission_object,
ordered_unique<tag<by_parent>,
composite_key<permission_object,
member<permission_object, permission_object::id_type, &permission_object::parent>,
member<permission_object, permission_object::id_type, &permission_object::id>
>
>,
ordered_unique<tag<by_owner>,
composite_key< permission_object,
member<permission_object, account_object::id_type, &permission_object::owner>,
ordered_unique<tag<by_owner>,
composite_key<permission_object,
member<permission_object, AccountName, &permission_object::owner>,
member<permission_object, PermissionName, &permission_object::name>,
member<permission_object, permission_object::id_type, &permission_object::id>
>
>,
ordered_unique<tag<by_name>, member<permission_object, PermissionName, &permission_object::name> >
ordered_unique<tag<by_name>,
composite_key<permission_object,
member<permission_object, PermissionName, &permission_object::name>,
member<permission_object, permission_object::id_type, &permission_object::id>
>
>
>
>;

Expand All @@ -115,5 +117,9 @@ namespace eos { namespace 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)

FC_REFLECT(eos::chain::account_object, (id)(name)(balance))
FC_REFLECT(chainbase::oid<eos::chain::permission_object>, (_id))
FC_REFLECT(chainbase::oid<eos::chain::account_object>, (_id))

FC_REFLECT(eos::chain::account_object, (id)(name)(creation_date))
// TODO: Reflect permission_object::auth
FC_REFLECT(eos::chain::permission_object, (id)(owner)(parent)(name))
61 changes: 48 additions & 13 deletions libraries/chain/include/eos/chain/chain_controller.hpp
Expand Up @@ -29,7 +29,6 @@
#include <eos/chain/fork_database.hpp>
#include <eos/chain/genesis_state.hpp>
#include <eos/chain/block_log.hpp>
#include <eos/chain/chain_model.hpp>

#include <chainbase/chainbase.hpp>
#include <fc/scoped_exit.hpp>
Expand All @@ -49,15 +48,47 @@ namespace eos { namespace chain {
using database = chainbase::database;
using boost::signals2::signal;

/**
* @brief This class defines an interface allowing
*/
class chain_initializer {
public:
virtual ~chain_initializer();
/**
* @brief Prepare the database, creating objects and defining state which should exist before the first block
* @param chain A reference to the @ref chain_controller
* @param db A reference to the @ref chainbase::database
* @param A list of @ref Message "Messages" to be applied before the first block
*
* This method creates the @ref account_object "account_objects" and @ref producer_object "producer_objects" for
* at least the initial block producers.
*
* This method also provides an opportunity to create objects and setup the database to the state it should be in
* prior to the first block. This method should only initialize state that the @ref chain_controller itself does
* not understand. The other methods will be called to retrieve the data necessary to initialize chain state the
* controller does understand.
*
* Finally, this method may perform any necessary initializations on the chain and/or database, such as
* installing indexes and message handlers that should be defined before the first block is processed. This may
* be necessary in order for the returned list of messages to be processed successfully.
*/
virtual vector<Message> prepare_database(chain_controller& chain, database& db) = 0;
/// Retrieve the timestamp to use as the blockchain start time
virtual types::Time get_chain_start_time() = 0;
/// Retrieve the BlockchainConfiguration to use at blockchain start
virtual BlockchainConfiguration get_chain_start_configuration() = 0;
/// Retrieve the first round of block producers
virtual std::array<AccountName, config::ProducerCount> get_chain_start_producers() = 0;
};

/**
* @class database
* @brief tracks the blockchain state in an extensible manner
*/
class chain_controller
{
public:
chain_controller(database& database, fork_database& fork_db, block_log& blocklog,
std::function<genesis_state_type()> genesis_loader);
chain_controller(database& database, fork_database& fork_db, block_log& blocklog, chain_initializer& starter);
chain_controller(chain_controller&&) = default;
~chain_controller();

Expand Down Expand Up @@ -130,8 +161,6 @@ namespace eos { namespace chain {
const SignedTransaction& get_recent_transaction( const transaction_id_type& trx_id )const;
std::vector<block_id_type> get_block_ids_on_fork(block_id_type head_of_fork) const;

chain_model get_model()const;

/**
* Calculate the percent of block production slots that were missed in the
* past 128 blocks, not including the current block.
Expand All @@ -148,14 +177,14 @@ namespace eos { namespace chain {
void _push_transaction( const SignedTransaction& trx );

signed_block generate_block(
const fc::time_point_sec when,
producer_id_type producer,
fc::time_point_sec when,
const AccountName& producer,
const fc::ecc::private_key& block_signing_private_key,
uint32_t skip
);
signed_block _generate_block(
const fc::time_point_sec when,
producer_id_type producer,
fc::time_point_sec when,
const AccountName& producer,
const fc::ecc::private_key& block_signing_private_key
);

Expand Down Expand Up @@ -215,7 +244,7 @@ namespace eos { namespace chain {
*
* Passing slot_num == 0 returns EOS_NULL_PRODUCER
*/
producer_id_type get_scheduled_producer(uint32_t slot_num)const;
AccountName get_scheduled_producer(uint32_t slot_num)const;

/**
* Get the time at which the given slot occurs.
Expand All @@ -239,15 +268,15 @@ namespace eos { namespace chain {

void update_producer_schedule();

const chain_id_type& get_chain_id()const;
const global_property_object& get_global_properties()const;
const dynamic_global_property_object& get_dynamic_global_properties()const;
const node_property_object& get_node_properties()const;
const producer_object& get_producer(const AccountName& ownerName)const;

time_point_sec head_block_time()const;
uint32_t head_block_num()const;
block_id_type head_block_id()const;
producer_id_type head_block_producer()const;
AccountName head_block_producer()const;

uint32_t block_interval()const { return config::BlockIntervalSeconds; }

Expand All @@ -262,17 +291,22 @@ namespace eos { namespace chain {
// these were formerly private, but they have a fairly well-defined API, so let's make them public
void apply_block(const signed_block& next_block, uint32_t skip = skip_nothing);
void apply_transaction(const SignedTransaction& trx, uint32_t skip = skip_nothing);

protected:
const chainbase::database& get_database() const { return _db; }

private:
/// Reset the object graph in-memory
void initialize_indexes();
void initialize_genesis(std::function<genesis_state_type()> genesis_loader);
void initialize_chain(chain_initializer& starter);

void replay();

void _apply_block(const signed_block& next_block);
void _apply_transaction(const SignedTransaction& trx);

void require_account(const AccountName& name) const;

/**
* This method validates transactions without adding it to the pending state.
* @return true if the transaction would validate
Expand All @@ -287,6 +321,7 @@ namespace eos { namespace chain {
/// @}

void validate_message_precondition(precondition_validate_context& c)const;
void process_message(Message message);
void apply_message(apply_context& c);

bool should_check_for_duplicate_transactions()const { return !(_skip_flags&skip_transaction_dupe_check); }
Expand Down
51 changes: 0 additions & 51 deletions libraries/chain/include/eos/chain/chain_model.hpp

This file was deleted.

56 changes: 0 additions & 56 deletions libraries/chain/include/eos/chain/chain_property_object.hpp

This file was deleted.

2 changes: 2 additions & 0 deletions libraries/chain/include/eos/chain/config.hpp
Expand Up @@ -38,6 +38,8 @@ const static char SystemContractName[] = "sys";
const static char EosContractName[] = "eos";
const static char StakedBalanceContractName[] = "sbc";

const static ShareType InitialTokenSupply = Asset(90'000'000).amount;

const static int BlockIntervalSeconds = 3;

/** Percentages are fixed point with a denominator of 10,000 */
Expand Down

0 comments on commit 55a8470

Please sign in to comment.