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

Commit

Permalink
more work on #6429
Browse files Browse the repository at this point in the history
  • Loading branch information
arhag committed Feb 16, 2019
1 parent 5799292 commit 1d2e24b
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 83 deletions.
12 changes: 9 additions & 3 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ struct controller_impl {
apply_handlers[receiver][make_pair(contract,action)] = v;
}

controller_impl( const controller::config& cfg, controller& s )
controller_impl( const controller::config& cfg, controller& s, protocol_feature_manager&& pfm )
:self(s),
db( cfg.state_dir,
cfg.read_only ? database::read_only : database::read_write,
Expand All @@ -287,6 +287,7 @@ struct controller_impl {
wasmif( cfg.wasm_runtime ),
resource_limits( db ),
authorization( s, db ),
protocol_features( std::move(pfm) ),
conf( cfg ),
chain_id( cfg.genesis.compute_chain_id() ),
read_mode( cfg.read_mode ),
Expand Down Expand Up @@ -2043,7 +2044,12 @@ authorization_manager& controller::get_mutable_authorization_manager()
}

controller::controller( const controller::config& cfg )
:my( new controller_impl( cfg, *this ) )
:my( new controller_impl( cfg, *this, protocol_feature_manager{} ) )
{
}

controller::controller( const config& cfg, protocol_feature_manager&& pfm )
:my( new controller_impl( cfg, *this, std::move(pfm) ) )
{
}

Expand Down Expand Up @@ -2707,7 +2713,7 @@ bool controller::is_builtin_activated( builtin_protocol_feature_t f )const {
++current_block_num;
}

my->protocol_features.is_builtin_activated( f, current_block_num );
return my->protocol_features.is_builtin_activated( f, current_block_num );
}

bool controller::is_known_unexpired_transaction( const transaction_id_type& id) const {
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ namespace eosio { namespace chain {
};

explicit controller( const config& cfg );
controller( const config& cfg, protocol_feature_manager&& pfm );
~controller();

void add_indices();
Expand Down
29 changes: 26 additions & 3 deletions libraries/chain/include/eosio/chain/protocol_feature_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,36 @@ enum class builtin_protocol_feature_t : uint32_t {

struct protocol_feature_subjective_restrictions {
time_point earliest_allowed_activation_time;
bool preactivation_required = false;
bool enabled = false;
bool preactivation_required = true;
bool enabled = true;
};

struct builtin_protocol_feature_spec {
const char* codename = nullptr;
digest_type description_digest;
flat_set<builtin_protocol_feature_t> builtin_dependencies;
protocol_feature_subjective_restrictions subjective_restrictions;
};

const char* builtin_protocol_feature_codename( builtin_protocol_feature_t );

class protocol_feature_base {
public:
protocol_feature_base() = default;

protocol_feature_base( protocol_feature_t feature_type,
const digest_type& description_digest,
flat_set<digest_type>&& dependencies,
const protocol_feature_subjective_restrictions& restrictions );

void reflector_init();

protocol_feature_t get_type() { return _type; }

public:
std::string protocol_feature_type;
flat_set<digest_type> dependencies;
digest_type description_digest;
flat_set<digest_type> dependencies;
protocol_feature_subjective_restrictions subjective_restrictions;
protected:
protocol_feature_t _type;
Expand All @@ -47,12 +60,16 @@ class builtin_protocol_feature : public protocol_feature_base {
builtin_protocol_feature() = default;

builtin_protocol_feature( builtin_protocol_feature_t codename,
const digest_type& description_digest,
flat_set<digest_type>&& dependencies,
const protocol_feature_subjective_restrictions& restrictions );

void reflector_init();

digest_type digest()const;

builtin_protocol_feature_t get_codename() { return _codename; }

friend class protocol_feature_manager;

public:
Expand All @@ -61,6 +78,8 @@ class builtin_protocol_feature : public protocol_feature_base {
builtin_protocol_feature_t _codename;
};

extern const std::unordered_map<builtin_protocol_feature_t, builtin_protocol_feature_spec> builtin_protocol_feature_codenames;

class protocol_feature_manager {
public:

Expand Down Expand Up @@ -101,9 +120,13 @@ class protocol_feature_manager {

bool is_builtin_activated( builtin_protocol_feature_t feature_codename, uint32_t current_block_num )const;

optional<digest_type> get_builtin_digest( builtin_protocol_feature_t feature_codename )const;

bool validate_dependencies( const digest_type& feature_digest,
const std::function<bool(const digest_type&)>& validator )const;

builtin_protocol_feature make_default_builtin_protocol_feature( builtin_protocol_feature_t codename )const;

void add_feature( const builtin_protocol_feature& f );

void activate_feature( const digest_type& feature_digest, uint32_t current_block_num );
Expand Down
28 changes: 28 additions & 0 deletions libraries/chain/include/eosio/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,34 @@ namespace eosio { namespace chain {
typedef vector<std::pair<uint16_t,vector<char>>> extensions_type;


template<typename Container>
class end_insert_iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
{
protected:
Container* container;

public:
using container_type = Container;

explicit end_insert_iterator( Container& c )
:container(&c)
{}

end_insert_iterator& operator=( typename Container::const_reference value ) {
container->insert( container->cend(), value );
return *this;
}

end_insert_iterator& operator*() { return *this; }
end_insert_iterator& operator++() { return *this; }
end_insert_iterator operator++(int) { return *this; }
};

template<typename Container>
inline end_insert_iterator<Container> end_inserter( Container& c ) {
return end_insert_iterator<Container>( c );
}

} } // eosio::chain

FC_REFLECT( eosio::chain::void_t, )
28 changes: 0 additions & 28 deletions libraries/chain/protocol_feature_activation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,6 @@ namespace eosio { namespace chain {
}
}

template<typename Container>
class end_insert_iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
{
protected:
Container* container;

public:
using container_type = Container;

explicit end_insert_iterator( Container& c )
:container(&c)
{}

end_insert_iterator& operator=( typename Container::const_reference value ) {
container->insert( container->cend(), value );
return *this;
}

end_insert_iterator& operator*() { return *this; }
end_insert_iterator& operator++() { return *this; }
end_insert_iterator operator++(int) { return *this; }
};

template<typename Container>
inline end_insert_iterator<Container> end_inserter( Container& c ) {
return end_insert_iterator<Container>( c );
}

protocol_feature_activation_set::protocol_feature_activation_set(
const protocol_feature_activation_set& orig_pfa_set,
vector<digest_type> additional_features,
Expand Down
141 changes: 131 additions & 10 deletions libraries/chain/protocol_feature_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,34 @@

namespace eosio { namespace chain {

const std::unordered_map<builtin_protocol_feature_t, const char*> builtin_codenames = boost::assign::map_list_of
(builtin_protocol_feature_t::preactivate_feature, "PREACTIVATE_FEATURE");
const std::unordered_map<builtin_protocol_feature_t, builtin_protocol_feature_spec>
builtin_protocol_feature_codenames =
boost::assign::map_list_of<builtin_protocol_feature_t, builtin_protocol_feature_spec>
( builtin_protocol_feature_t::preactivate_feature, {
"PREACTIVATE_FEATURE",
digest_type{},
{},
{time_point{}, false, true} // enabled without preactivation and ready to go at any time
} )
;


const char* builtin_protocol_feature_codename( builtin_protocol_feature_t codename ) {
auto itr = builtin_protocol_feature_codenames.find( codename );
EOS_ASSERT( itr != builtin_protocol_feature_codenames.end(), protocol_feature_validation_exception,
"Unsupported builtin_protocol_feature_t passed to builtin_protocol_feature_codename: ${codename}",
("codename", static_cast<uint32_t>(codename)) );

return itr->second.codename;
}

protocol_feature_base::protocol_feature_base( protocol_feature_t feature_type,
const digest_type& description_digest,
flat_set<digest_type>&& dependencies,
const protocol_feature_subjective_restrictions& restrictions )
:subjective_restrictions( restrictions )
:description_digest( description_digest )
,dependencies( std::move(dependencies) )
,subjective_restrictions( restrictions )
,_type( feature_type )
{
switch( feature_type ) {
Expand Down Expand Up @@ -46,23 +68,32 @@ namespace eosio { namespace chain {
}

builtin_protocol_feature::builtin_protocol_feature( builtin_protocol_feature_t codename,
const digest_type& description_digest,
flat_set<digest_type>&& dependencies,
const protocol_feature_subjective_restrictions& restrictions )
:protocol_feature_base( protocol_feature_t::builtin, restrictions )
:protocol_feature_base( protocol_feature_t::builtin, description_digest, std::move(dependencies), restrictions )
,_codename(codename)
{
auto itr = builtin_codenames.find( codename );
EOS_ASSERT( itr != builtin_codenames.end(), protocol_feature_validation_exception,
auto itr = builtin_protocol_feature_codenames.find( codename );
EOS_ASSERT( itr != builtin_protocol_feature_codenames.end(), protocol_feature_validation_exception,
"Unsupported builtin_protocol_feature_t passed to constructor: ${codename}",
("codename", static_cast<uint32_t>(codename)) );

builtin_feature_codename = itr->second;
builtin_feature_codename = itr->second.codename;
}

void builtin_protocol_feature::reflector_init() {
protocol_feature_base::reflector_init();

for( const auto& p : builtin_codenames ) {
if( builtin_feature_codename.compare( p.second ) == 0 ) {
auto codename = get_codename();
for( const auto& p : builtin_protocol_feature_codenames ) {
if( p.first == codename ) {
EOS_ASSERT( builtin_feature_codename == p.second.codename,
protocol_feature_validation_exception,
"Deserialized protocol feature has invalid codename. Expected: ${expected}. Actual: ${actual}.",
("expected", p.second.codename)
("actual", protocol_feature_type)
);
_codename = p.first;
return;
}
Expand All @@ -83,7 +114,7 @@ namespace eosio { namespace chain {
}

protocol_feature_manager::protocol_feature_manager() {
_builtin_protocol_features.reserve( builtin_codenames.size() );
_builtin_protocol_features.reserve( builtin_protocol_feature_codenames.size() );
}

protocol_feature_manager::recognized_t
Expand Down Expand Up @@ -127,6 +158,20 @@ namespace eosio { namespace chain {
return (_builtin_protocol_features[indx].activation_block_num <= current_block_num);
}

optional<digest_type>
protocol_feature_manager::get_builtin_digest( builtin_protocol_feature_t feature_codename )const
{
uint32_t indx = static_cast<uint32_t>( feature_codename );

if( indx >= _builtin_protocol_features.size() )
return {};

if( _builtin_protocol_features[indx].iterator_to_protocol_feature == _recognized_protocol_features.end() )
return {};

return _builtin_protocol_features[indx].iterator_to_protocol_feature->feature_digest;
}

bool protocol_feature_manager::validate_dependencies(
const digest_type& feature_digest,
const std::function<bool(const digest_type&)>& validator
Expand All @@ -142,11 +187,41 @@ namespace eosio { namespace chain {
return true;
}

builtin_protocol_feature
protocol_feature_manager::make_default_builtin_protocol_feature( builtin_protocol_feature_t codename )const
{
auto itr = builtin_protocol_feature_codenames.find( codename );

EOS_ASSERT( itr != builtin_protocol_feature_codenames.end(), protocol_feature_validation_exception,
"Unsupported builtin_protocol_feature_t: ${codename}",
("codename", static_cast<uint32_t>(codename)) );

flat_set<digest_type> dependencies;
dependencies.reserve( itr->second.builtin_dependencies.size() );

for( const auto& d : itr->second.builtin_dependencies ) {
auto dependency_digest = get_builtin_digest( d );
EOS_ASSERT( dependency_digest, protocol_feature_exception,
"cannot make default builtin protocol feature with codename '${codename}' since it has a dependency that has not been added yet: ${dependency_codename}",
("codename", static_cast<uint32_t>(itr->first))
("dependency_codename", static_cast<uint32_t>(d))
);
dependencies.insert( *dependency_digest );
}

return {itr->first, itr->second.description_digest, std::move(dependencies), itr->second.subjective_restrictions};
}

void protocol_feature_manager::add_feature( const builtin_protocol_feature& f ) {
EOS_ASSERT( _head_of_builtin_activation_list == builtin_protocol_feature_entry::no_previous,
protocol_feature_exception,
"new builtin protocol features cannot be added after a protocol feature has already been activated" );

auto builtin_itr = builtin_protocol_feature_codenames.find( f._codename );
EOS_ASSERT( builtin_itr != builtin_protocol_feature_codenames.end(), protocol_feature_validation_exception,
"Builtin protocol feature has unsupported builtin_protocol_feature_t: ${codename}",
("codename", static_cast<uint32_t>( f._codename )) );

uint32_t indx = static_cast<uint32_t>( f._codename );

if( indx < _builtin_protocol_features.size() ) {
Expand All @@ -158,6 +233,52 @@ namespace eosio { namespace chain {

auto feature_digest = f.digest();

const auto& expected_builtin_dependencies = builtin_itr->second.builtin_dependencies;
flat_set<builtin_protocol_feature_t> satisfied_builtin_dependencies;
satisfied_builtin_dependencies.reserve( expected_builtin_dependencies.size() );

for( const auto& d : f.dependencies ) {
auto itr = _recognized_protocol_features.find( d );
EOS_ASSERT( itr != _recognized_protocol_features.end(), protocol_feature_exception,
"builtin protocol feature with codename '${codename}' and digest of ${digest} has a dependency on a protocol feature with digest ${dependency_digest} that is not recognized",
("codename", f.builtin_feature_codename)
("digest", feature_digest)
("dependency_digest", d )
);

if( itr->builtin_feature
&& expected_builtin_dependencies.find( *itr->builtin_feature )
!= expected_builtin_dependencies.end() )
{
satisfied_builtin_dependencies.insert( *itr->builtin_feature );
}
}

if( expected_builtin_dependencies.size() > satisfied_builtin_dependencies.size() ) {
flat_set<builtin_protocol_feature_t> missing_builtins;
missing_builtins.reserve( expected_builtin_dependencies.size() - satisfied_builtin_dependencies.size() );
std::set_difference( expected_builtin_dependencies.begin(), expected_builtin_dependencies.end(),
satisfied_builtin_dependencies.begin(), satisfied_builtin_dependencies.end(),
end_inserter( missing_builtins )
);

vector<string> missing_builtins_with_names;
missing_builtins_with_names.reserve( missing_builtins.size() );
for( const auto& builtin_codename : missing_builtins ) {
auto itr = builtin_protocol_feature_codenames.find( builtin_codename );
EOS_ASSERT( itr != builtin_protocol_feature_codenames.end(),
protocol_feature_exception,
"Unexpected error"
);
missing_builtins_with_names.emplace_back( itr->second.codename );
}

EOS_THROW( protocol_feature_validation_exception,
"Not all the builtin dependencies of the builtin protocol feature with codename '${codename}' and digest of ${digest} were satisfied.",
("missing_dependencies", missing_builtins_with_names)
);
}

auto res = _recognized_protocol_features.insert( protocol_feature{
feature_digest,
f.dependencies,
Expand Down
Loading

0 comments on commit 1d2e24b

Please sign in to comment.