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

set immutable chain_id during construction of controller #7962

Merged
merged 2 commits into from
Sep 21, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
55 changes: 36 additions & 19 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ struct controller_impl {
authorization_manager authorization;
protocol_feature_manager protocol_features;
controller::config conf;
chain_id_type chain_id; // read by thread_pool threads, value will not be changed after initialization/snapshot
const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
optional<fc::time_point> replay_head_time;
db_read_mode read_mode = db_read_mode::SPECULATIVE;
bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
Expand Down Expand Up @@ -281,7 +281,7 @@ struct controller_impl {
apply_handlers[receiver][make_pair(contract,action)] = v;
}

controller_impl( const controller::config& cfg, controller& s, protocol_feature_set&& pfs )
controller_impl( const controller::config& cfg, controller& s, protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id )
:self(s),
db( cfg.state_dir,
cfg.read_only ? database::read_only : database::read_write,
Expand All @@ -296,9 +296,21 @@ struct controller_impl {
authorization( s, db ),
protocol_features( std::move(pfs) ),
conf( cfg ),
chain_id( (db.revision() >= 1) ? db.get<global_property_object>().chain_id
: ( expected_chain_id ? *expected_chain_id
: genesis_state().compute_chain_id() ) ),
read_mode( cfg.read_mode ),
thread_pool( "chain", cfg.thread_pool_size )
{
if( expected_chain_id && db.revision() >= 1 ) {
const auto& actual_chain_id = db.get<global_property_object>().chain_id;
EOS_ASSERT( *expected_chain_id == actual_chain_id,
database_exception,
"Unexpected chain ID in state. Expected: ${expected}. Actual: ${actual}.",
("expected", *expected_chain_id)("actual", actual_chain_id)
);
}

fork_db.open( [this]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
const vector<digest_type>& new_features )
Expand Down Expand Up @@ -546,6 +558,11 @@ struct controller_impl {

void startup(std::function<bool()> shutdown, const genesis_state& genesis) {
EOS_ASSERT( db.revision() < 1, database_exception, "This version of controller::startup only works with a fresh state database." );
const auto& genesis_chain_id = genesis.compute_chain_id();
EOS_ASSERT( genesis_chain_id == chain_id, chain_id_type_exception,
"genesis state provided to startup corresponds to a chain ID (${genesis_chain_id}) that does not match the chain ID that controller was constructed with (${controller_chain_id})",
("genesis_chain_id", genesis_chain_id)("controller_chain_id", chain_id)
arhag marked this conversation as resolved.
Show resolved Hide resolved
);

if( fork_db.head() ) {
if( read_mode == db_read_mode::IRREVERSIBLE && fork_db.head()->id != fork_db.root()->id ) {
Expand Down Expand Up @@ -575,13 +592,12 @@ struct controller_impl {
EOS_ASSERT( db.revision() >= 1, database_exception, "This version of controller::startup does not work with a fresh state database." );
EOS_ASSERT( fork_db.head(), fork_database_exception, "No existing fork database despite existing chain state. Replay required." );

chain_id = db.get<global_property_object>().chain_id;
uint32_t lib_num = fork_db.root()->block_num;
auto first_block_num = blog.first_block_num();
if( blog.head() ) {
EOS_ASSERT( first_block_num <= lib_num && lib_num <= blog.head()->block_num(),
block_log_exception,
"block log does not contain last irreversible block",
"block log (ranging from ${block_log_first_num} to ${block_log_last_num}) does not contain the last irreversible block (${fork_db_lib})",
("block_log_first_num", first_block_num)
("block_log_last_num", blog.head()->block_num())
("fork_db_lib", lib_num)
Expand Down Expand Up @@ -624,7 +640,7 @@ struct controller_impl {
// Also, even though blog.head() may still be nullptr, blog.first_block_num() is guaranteed to be lib_num + 1.

EOS_ASSERT( db.revision() >= head->block_num, fork_database_exception,
"fork database head is inconsistent with state",
"fork database head (${head}) is inconsistent with state (${db})",
("db",db.revision())("head",head->block_num) );

if( db.revision() > head->block_num ) {
Expand Down Expand Up @@ -655,7 +671,7 @@ struct controller_impl {
reversible_blocks.remove( *itr );

EOS_ASSERT( itr == rbi.end() || itr->blocknum == lib_num + 1, reversible_blocks_exception,
"gap exists between last irreversible block and first reversible block",
"gap exists between last irreversible block (${lib}) and first reversible block (${first_reversible_block_num})",
("lib", lib_num)("first_reversible_block_num", itr->blocknum)
);

Expand Down Expand Up @@ -836,13 +852,13 @@ struct controller_impl {
resource_limits.add_to_snapshot(snapshot);
}

static fc::optional<genesis_state> extract_legacy_genesis_state( const snapshot_reader_ptr& snapshot, uint32_t version ) {
static fc::optional<genesis_state> extract_legacy_genesis_state( snapshot_reader& snapshot, uint32_t version ) {
fc::optional<genesis_state> genesis;
using v2 = legacy::snapshot_global_property_object_v2;

if (std::clamp(version, v2::minimum_version, v2::maximum_version) == version ) {
genesis.emplace();
snapshot->read_section<genesis_state>([&genesis=*genesis]( auto &section ){
snapshot.read_section<genesis_state>([&genesis=*genesis]( auto &section ){
section.read_row(genesis);
});
}
Expand Down Expand Up @@ -905,7 +921,7 @@ struct controller_impl {
using v2 = legacy::snapshot_global_property_object_v2;

if (std::clamp(header.version, v2::minimum_version, v2::maximum_version) == header.version ) {
fc::optional<genesis_state> genesis = extract_legacy_genesis_state(snapshot, header.version);
fc::optional<genesis_state> genesis = extract_legacy_genesis_state(*snapshot, header.version);
EOS_ASSERT( genesis, snapshot_exception,
"Snapshot indicates chain_snapshot_header version 2, but does not contain a genesis_state. "
"It must be corrupted.");
Expand Down Expand Up @@ -942,8 +958,10 @@ struct controller_impl {
});

const auto& gpo = db.get<global_property_object>();
// ensure chain_id is populated from global_property_object's chain_id
chain_id = gpo.chain_id;
EOS_ASSERT( gpo.chain_id == chain_id, chain_id_type_exception,
"chain ID in snapshot (${snapshot_chain_id}) does not match the chain ID that controller was constructed with (${controller_chain_id})",
("snapshot_chain_id", gpo.chain_id)("controller_chain_id", chain_id)
);
}

sha256 calculate_integrity_hash() const {
Expand Down Expand Up @@ -1004,7 +1022,6 @@ struct controller_impl {
});

genesis.initial_configuration.validate();
chain_id = genesis.compute_chain_id();
db.create<global_property_object>([&genesis,&chain_id=this->chain_id](auto& gpo ){
gpo.configuration = genesis.initial_configuration;
gpo.chain_id = chain_id;
Expand Down Expand Up @@ -2348,13 +2365,13 @@ const protocol_feature_manager& controller::get_protocol_feature_manager()const
return my->protocol_features;
}

controller::controller( const controller::config& cfg )
:my( new controller_impl( cfg, *this, protocol_feature_set{} ) )
controller::controller( const controller::config& cfg, const fc::optional<chain_id_type>& expected_chain_id )
:my( new controller_impl( cfg, *this, protocol_feature_set{}, expected_chain_id ) )
{
}

controller::controller( const config& cfg, protocol_feature_set&& pfs )
:my( new controller_impl( cfg, *this, std::move(pfs) ) )
controller::controller( const config& cfg, protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id )
:my( new controller_impl( cfg, *this, std::move(pfs), expected_chain_id ) )
{
}

Expand Down Expand Up @@ -3149,9 +3166,9 @@ fc::optional<uint64_t> controller::convert_exception_to_error_code( const fc::ex
return e_ptr->error_code;
}

chain_id_type controller::extract_chain_id(const snapshot_reader_ptr& snapshot) {
chain_id_type controller::extract_chain_id(snapshot_reader& snapshot) {
chain_snapshot_header header;
snapshot->read_section<chain_snapshot_header>([&header]( auto &section ){
snapshot.read_section<chain_snapshot_header>([&header]( auto &section ){
section.read_row(header);
header.validate();
});
Expand All @@ -3163,7 +3180,7 @@ chain_id_type controller::extract_chain_id(const snapshot_reader_ptr& snapshot)
}

chain_id_type chain_id;
snapshot->read_section<global_property_object>([&chain_id]( auto &section ){
snapshot.read_section<global_property_object>([&chain_id]( auto &section ){
snapshot_global_property_object global_properties;
section.read_row(global_properties);
chain_id = global_properties.chain_id;
Expand Down
6 changes: 3 additions & 3 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ namespace eosio { namespace chain {
incomplete = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node)
};

explicit controller( const config& cfg );
controller( const config& cfg, protocol_feature_set&& pfs );
controller( const config& cfg, const fc::optional<chain_id_type>& expected_chain_id );
controller( const config& cfg, protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id );
~controller();

void add_indices();
Expand Down Expand Up @@ -328,7 +328,7 @@ namespace eosio { namespace chain {
return pretty_output;
}

static chain_id_type extract_chain_id(const snapshot_reader_ptr& snapshot);
static chain_id_type extract_chain_id(snapshot_reader& snapshot);

private:
friend class apply_context;
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/include/eosio/chain/snapshot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ namespace eosio { namespace chain {

virtual void validate() const = 0;

virtual void return_to_header() = 0;

virtual ~snapshot_reader(){};

protected:
Expand Down Expand Up @@ -316,6 +318,7 @@ namespace eosio { namespace chain {
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
bool empty ( ) override;
void clear_section() override;
void return_to_header() override;

private:
const fc::variant& snapshot;
Expand Down Expand Up @@ -352,6 +355,7 @@ namespace eosio { namespace chain {
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
bool empty ( ) override;
void clear_section() override;
void return_to_header() override;

private:
bool validate_section() const;
Expand Down
12 changes: 11 additions & 1 deletion libraries/chain/snapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void variant_snapshot_writer::finalize() {

variant_snapshot_reader::variant_snapshot_reader(const fc::variant& snapshot)
:snapshot(snapshot)
,cur_section(nullptr)
,cur_row(0)
{
}
Expand Down Expand Up @@ -114,6 +115,10 @@ void variant_snapshot_reader::clear_section() {
cur_row = 0;
}

void variant_snapshot_reader::return_to_header() {
clear_section();
}

ostream_snapshot_writer::ostream_snapshot_writer(std::ostream& snapshot)
:snapshot(snapshot)
,header_pos(snapshot.tellp())
Expand Down Expand Up @@ -336,6 +341,11 @@ void istream_snapshot_reader::clear_section() {
cur_row = 0;
}

void istream_snapshot_reader::return_to_header() {
snapshot.seekg( header_pos );
clear_section();
}

integrity_hash_snapshot_writer::integrity_hash_snapshot_writer(fc::sha256::encoder& enc)
:enc(enc)
{
Expand All @@ -358,4 +368,4 @@ void integrity_hash_snapshot_writer::finalize() {
// no-op for structural details
}

}}
}}
24 changes: 13 additions & 11 deletions libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@ namespace eosio { namespace testing {

void close();
template <typename Lambda>
void open( protocol_feature_set&& pfs, Lambda lambda );
void open( protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id, Lambda lambda );
void open( protocol_feature_set&& pfs, const snapshot_reader_ptr& snapshot );
void open( protocol_feature_set&& pfs, const genesis_state& genesis );
void open( protocol_feature_set&& pfs );
void open( protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id = {} );
void open( const snapshot_reader_ptr& snapshot );
void open( const genesis_state& genesis );
void open();
void open( const fc::optional<chain_id_type>& expected_chain_id = {} );
bool is_same_chain( base_tester& other );

virtual signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms) ) = 0;
Expand Down Expand Up @@ -380,6 +380,13 @@ namespace eosio { namespace testing {
void preactivate_protocol_features(const vector<digest_type> feature_digests);
void preactivate_all_builtin_protocol_features();

static genesis_state default_genesis() {
genesis_state genesis;
genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000");
genesis.initial_key = get_public_key( config::system_account_name, "active" );

return genesis;
}

static std::pair<controller::config, genesis_state> default_config(const fc::temp_directory& tempdir) {
controller::config cfg;
Expand All @@ -391,17 +398,13 @@ namespace eosio { namespace testing {
cfg.reversible_guard_size = 0;
cfg.contracts_console = true;

genesis_state genesis;
genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000");
genesis.initial_key = get_public_key( config::system_account_name, "active" );

for(int i = 0; i < boost::unit_test::framework::master_test_suite().argc; ++i) {
if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wavm"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wavm;
else if(boost::unit_test::framework::master_test_suite().argv[i] == std::string("--wabt"))
cfg.wasm_runtime = chain::wasm_interface::vm_type::wabt;
}
return {cfg, genesis};
return {cfg, default_genesis()};
}

protected:
Expand All @@ -418,7 +421,6 @@ namespace eosio { namespace testing {
std::map<chain::public_key_type, chain::private_key_type> block_signing_private_keys;
protected:
controller::config cfg;
fc::optional<genesis_state> genesis;
map<transaction_id_type, transaction_receipt> chain_transactions;
map<account_name, block_id_type> last_produced_block;
unapplied_transaction_queue unapplied_transactions;
Expand Down Expand Up @@ -529,7 +531,7 @@ namespace eosio { namespace testing {
}

static unique_ptr<controller> create_validating_node(controller::config vcfg, const genesis_state& genesis, bool use_genesis) {
unique_ptr<controller> validating_node = std::make_unique<controller>(vcfg, make_protocol_feature_set());
unique_ptr<controller> validating_node = std::make_unique<controller>(vcfg, make_protocol_feature_set(), genesis.compute_chain_id());
validating_node->add_indices();
if (use_genesis) {
validating_node->startup( []() { return false; }, genesis );
Expand Down Expand Up @@ -613,7 +615,7 @@ namespace eosio { namespace testing {
hbh.producer == vn_hbh.producer;

validating_node.reset();
validating_node = std::make_unique<controller>(vcfg, make_protocol_feature_set());
validating_node = std::make_unique<controller>(vcfg, make_protocol_feature_set(), control->get_chain_id());
validating_node->add_indices();
validating_node->startup( []() { return false; } );

Expand Down
22 changes: 12 additions & 10 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ namespace eosio { namespace testing {

void base_tester::init(controller::config config) {
cfg = config;
open();
open(default_genesis().compute_chain_id());
}

void base_tester::init(controller::config config, protocol_feature_set&& pfs, const snapshot_reader_ptr& snapshot) {
Expand All @@ -185,7 +185,7 @@ namespace eosio { namespace testing {

void base_tester::init(controller::config config, protocol_feature_set&& pfs) {
cfg = config;
open(std::move(pfs));
open(std::move(pfs), default_genesis().compute_chain_id());
}

void base_tester::execute_setup_policy(const setup_policy policy) {
Expand Down Expand Up @@ -241,13 +241,13 @@ namespace eosio { namespace testing {
open( make_protocol_feature_set(), genesis );
}

void base_tester::open() {
open( make_protocol_feature_set() );
void base_tester::open( const fc::optional<chain_id_type>& expected_chain_id ) {
open( make_protocol_feature_set(), expected_chain_id );
}

template <typename Lambda>
void base_tester::open( protocol_feature_set&& pfs, Lambda lambda ) {
control.reset( new controller(cfg, std::move(pfs)) );
void base_tester::open( protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id, Lambda lambda ) {
control.reset( new controller(cfg, std::move(pfs), expected_chain_id) );
control->add_indices();
lambda();
chain_transactions.clear();
Expand All @@ -266,19 +266,21 @@ namespace eosio { namespace testing {
}

void base_tester::open( protocol_feature_set&& pfs, const snapshot_reader_ptr& snapshot ) {
open(std::move(pfs), [&snapshot,&control=this->control]() {
const auto& snapshot_chain_id = controller::extract_chain_id( *snapshot );
snapshot->return_to_header();
open(std::move(pfs), snapshot_chain_id, [&snapshot,&control=this->control]() {
control->startup([]() { return false; }, snapshot );
});
}

void base_tester::open( protocol_feature_set&& pfs, const genesis_state& genesis ) {
open(std::move(pfs), [&genesis,&control=this->control]() {
open(std::move(pfs), genesis.compute_chain_id(), [&genesis,&control=this->control]() {
control->startup( []() { return false; }, genesis );
});
}

void base_tester::open( protocol_feature_set&& pfs ) {
open(std::move(pfs), [&control=this->control]() {
void base_tester::open( protocol_feature_set&& pfs, const fc::optional<chain_id_type>& expected_chain_id ) {
open(std::move(pfs), expected_chain_id, [&control=this->control]() {
control->startup( []() { return false; } );
});
}
Expand Down
Loading