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

Commit

Permalink
Merge pull request #5198 from EOSIO/read-only
Browse files Browse the repository at this point in the history
Read only mode
  • Loading branch information
heifner committed Aug 14, 2018
2 parents a4e6449 + 52171a9 commit 03ee499
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 7 deletions.
1 change: 1 addition & 0 deletions libraries/chain/controller.cpp
Expand Up @@ -1423,6 +1423,7 @@ void controller::push_confirmation( const header_confirmation& c ) {

transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
validate_db_available_size();
EOS_ASSERT( get_read_mode() != chain::db_read_mode::READ_ONLY, transaction_type_exception, "push transaction not allowed in read-only mode" );
EOS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
return my->push_transaction(trx, deadline, billed_cpu_time_us, billed_cpu_time_us > 0 );
}
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Expand Up @@ -36,6 +36,7 @@ namespace eosio { namespace chain {
enum class db_read_mode {
SPECULATIVE,
HEAD,
READ_ONLY,
IRREVERSIBLE
};

Expand Down
7 changes: 7 additions & 0 deletions plugins/bnet_plugin/bnet_plugin.cpp
Expand Up @@ -1038,6 +1038,8 @@ namespace eosio {
peer_elog(this, "bad packed_transaction_ptr : null pointer");
EOS_THROW(transaction_exception, "bad transaction");
}
if( app().get_plugin<chain_plugin>().chain().get_read_mode() == chain::db_read_mode::READ_ONLY )
return;

auto id = p->id();
// ilog( "recv trx ${n}", ("n", id) );
Expand Down Expand Up @@ -1368,6 +1370,11 @@ namespace eosio {
});


if( app().get_plugin<chain_plugin>().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) {
my->_request_trx = false;
ilog( "setting bnet-no-trx to true since in read-only mode" );
}

const auto address = boost::asio::ip::make_address( my->_bnet_endpoint_address );
my->_ioc.reset( new boost::asio::io_context{my->_num_threads} );

Expand Down
6 changes: 3 additions & 3 deletions plugins/chain_api_plugin/chain_api_plugin.cpp
Expand Up @@ -49,7 +49,7 @@ struct async_result_visitor : public fc::visitor<std::string> {

#define CALL_ASYNC(api_name, api_handle, api_namespace, call_name, call_result, http_response_code) \
{std::string("/v1/" #api_name "/" #call_name), \
[this, api_handle](string, string body, url_response_callback cb) mutable { \
[this](string, string body, url_response_callback cb) mutable { \
if (body.empty()) body = "{}"; \
api_handle.call_name(fc::json::from_string(body).as<api_namespace::call_name ## _params>(),\
[cb, body](const fc::static_variant<fc::exception_ptr, call_result>& result){\
Expand All @@ -66,16 +66,16 @@ struct async_result_visitor : public fc::visitor<std::string> {
}\
}

#define CHAIN_RW_API app().get_plugin<chain_plugin>().get_read_write_api()
#define CHAIN_RO_CALL(call_name, http_response_code) CALL(chain, ro_api, chain_apis::read_only, call_name, http_response_code)
#define CHAIN_RW_CALL(call_name, http_response_code) CALL(chain, rw_api, chain_apis::read_write, call_name, http_response_code)
#define CHAIN_RO_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, ro_api, chain_apis::read_only, call_name, call_result, http_response_code)
#define CHAIN_RW_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, rw_api, chain_apis::read_write, call_name, call_result, http_response_code)
#define CHAIN_RW_CALL_ASYNC(call_name, call_result, http_response_code) CALL_ASYNC(chain, (CHAIN_RW_API), chain_apis::read_write, call_name, call_result, http_response_code)

void chain_api_plugin::plugin_startup() {
ilog( "starting chain_api_plugin" );
my.reset(new chain_api_plugin_impl(app().get_plugin<chain_plugin>().chain()));
auto ro_api = app().get_plugin<chain_plugin>().get_read_only_api();
auto rw_api = app().get_plugin<chain_plugin>().get_read_write_api();

app().get_plugin<http_plugin>().add_api({
CHAIN_RO_CALL(get_info, 200l),
Expand Down
11 changes: 11 additions & 0 deletions plugins/chain_plugin/chain_plugin.cpp
Expand Up @@ -39,6 +39,8 @@ std::ostream& operator<<(std::ostream& osm, eosio::chain::db_read_mode m) {
osm << "speculative";
} else if ( m == eosio::chain::db_read_mode::HEAD ) {
osm << "head";
} else if ( m == eosio::chain::db_read_mode::READ_ONLY ) {
osm << "read-only";
} else if ( m == eosio::chain::db_read_mode::IRREVERSIBLE ) {
osm << "irreversible";
}
Expand All @@ -64,6 +66,8 @@ void validate(boost::any& v,
v = boost::any(eosio::chain::db_read_mode::SPECULATIVE);
} else if ( s == "head" ) {
v = boost::any(eosio::chain::db_read_mode::HEAD);
} else if ( s == "read-only" ) {
v = boost::any(eosio::chain::db_read_mode::READ_ONLY);
} else if ( s == "irreversible" ) {
v = boost::any(eosio::chain::db_read_mode::IRREVERSIBLE);
} else {
Expand Down Expand Up @@ -656,6 +660,13 @@ void chain_plugin::plugin_shutdown() {
my->chain.reset();
}

chain_apis::read_write::read_write(controller& db, const fc::microseconds& abi_serializer_max_time)
: db(db)
, abi_serializer_max_time(abi_serializer_max_time)
{
EOS_ASSERT( db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, "Not allowed, node in read-only mode" );
}

chain_apis::read_write chain_plugin::get_read_write_api() {
return chain_apis::read_write(chain(), get_abi_serializer_max_time());
}
Expand Down
Expand Up @@ -473,8 +473,7 @@ class read_write {
controller& db;
const fc::microseconds abi_serializer_max_time;
public:
read_write(controller& db, const fc::microseconds& abi_serializer_max_time)
: db(db), abi_serializer_max_time(abi_serializer_max_time) {}
read_write(controller& db, const fc::microseconds& abi_serializer_max_time);

using push_block_params = chain::signed_block;
using push_block_results = empty;
Expand Down
13 changes: 11 additions & 2 deletions plugins/net_plugin/net_plugin.cpp
Expand Up @@ -2496,6 +2496,11 @@ namespace eosio {
void net_plugin_impl::handle_message( connection_ptr c, const packed_transaction &msg) {
fc_dlog(logger, "got a packed transaction, cancel wait");
peer_ilog(c, "received packed_transaction");
controller& cc = my_impl->chain_plug->chain();
if( cc.get_read_mode() == eosio::db_read_mode::READ_ONLY ) {
fc_dlog(logger, "got a txn in read-only mode - dropping");
return;
}
if( sync_master->is_active(c) ) {
fc_dlog(logger, "got a txn during sync - dropping");
return;
Expand All @@ -2507,7 +2512,6 @@ namespace eosio {
return;
}
dispatcher->recv_transaction(c, tid);
uint64_t code = 0;
chain_plug->accept_transaction(msg, [=](const static_variant<fc::exception_ptr, transaction_trace_ptr>& result) {
if (result.contains<fc::exception_ptr>()) {
auto e_ptr = result.get<fc::exception_ptr>();
Expand Down Expand Up @@ -3033,8 +3037,8 @@ namespace eosio {
ilog("starting listener, max clients is ${mc}",("mc",my->max_client_count));
my->start_listen_loop();
}
chain::controller&cc = my->chain_plug->chain();
{
chain::controller&cc = my->chain_plug->chain();
cc.accepted_block_header.connect( boost::bind(&net_plugin_impl::accepted_block_header, my.get(), _1));
cc.accepted_block.connect( boost::bind(&net_plugin_impl::accepted_block, my.get(), _1));
cc.irreversible_block.connect( boost::bind(&net_plugin_impl::irreversible_block, my.get(), _1));
Expand All @@ -3045,6 +3049,11 @@ namespace eosio {

my->incoming_transaction_ack_subscription = app().get_channel<channels::transaction_ack>().subscribe(boost::bind(&net_plugin_impl::transaction_ack, my.get(), _1));

if( cc.get_read_mode() == chain::db_read_mode::READ_ONLY ) {
my->max_nodes_per_host = 0;
ilog( "node in read-only mode setting max_nodes_per_host to 0 to prevent connections" );
}

my->start_monitors();

for( auto seed_node : my->supplied_peers ) {
Expand Down
4 changes: 4 additions & 0 deletions plugins/producer_plugin/producer_plugin.cpp
Expand Up @@ -877,6 +877,10 @@ fc::time_point producer_plugin_impl::calculate_pending_block_time() const {

producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool &last_block) {
chain::controller& chain = app().get_plugin<chain_plugin>().chain();

if( chain.get_read_mode() == chain::db_read_mode::READ_ONLY )
return start_block_result::waiting;

const auto& hbs = chain.head_block_state();

//Schedule for the next second's tick regardless of chain state
Expand Down
5 changes: 5 additions & 0 deletions unittests/forked_tests.cpp
Expand Up @@ -453,6 +453,11 @@ BOOST_AUTO_TEST_CASE( read_modes ) try {
BOOST_REQUIRE_EQUAL(head_block_num, head.control->fork_db_head_block_num());
BOOST_REQUIRE_EQUAL(head_block_num, head.control->head_block_num());

tester read_only(false, db_read_mode::READ_ONLY);
push_blocks(c, read_only);
BOOST_REQUIRE_EQUAL(head_block_num, read_only.control->fork_db_head_block_num());
BOOST_REQUIRE_EQUAL(head_block_num, read_only.control->head_block_num());

tester irreversible(true, db_read_mode::IRREVERSIBLE);
push_blocks(c, irreversible);
BOOST_REQUIRE_EQUAL(head_block_num, irreversible.control->fork_db_head_block_num());
Expand Down

0 comments on commit 03ee499

Please sign in to comment.