未验证 提交 c045881d 编写于 作者: K Kevin Heifner 提交者: GitHub

Merge branch 'slim' into feature/explicitly-remove-implicit-calls

......@@ -167,7 +167,7 @@ namespace eosiosystem {
res.storage_bytes += uint64_t(bytes_out);
});
}
set_resource_limits( res_itr->owner, res_itr->storage_bytes, uint64_t(res_itr->net_weight.amount), uint64_t(res_itr->cpu_weight.amount) );
set_resource_limits( res_itr->owner, res_itr->storage_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount );
}
......
......@@ -122,7 +122,7 @@ namespace eosiosystem {
[[noreturn]] ~system_contract();
// Actions:
void onblock( const block_id_type&, uint32_t timestamp_slot, account_name producer );
void onblock( uint32_t timestamp_slot, account_name producer );
// const block_header& header ); /// only parse first 3 fields of block header
// functions defined in delegate_bandwidth.cpp
......
......@@ -46,17 +46,18 @@ namespace eosiosystem {
};
struct block_header {
block_id_type previous;
uint32_t timestamp;
account_name producer;
uint32_t schedule_version = 0;
uint16_t confirmed = 0;
block_id_type previous;
checksum256 transaction_mroot;
checksum256 action_mroot;
uint32_t schedule_version = 0;
eosio::optional<eosio::producer_schedule> new_producers;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE(block_header, (previous)(timestamp)(producer)(schedule_version)(transaction_mroot)(action_mroot)
(new_producers))
EOSLIB_SERIALIZE(block_header, (timestamp)(producer)(confirmed)(previous)(transaction_mroot)(action_mroot)
(schedule_version)(new_producers))
};
......
......@@ -7,7 +7,7 @@ namespace eosiosystem {
static const uint32_t num_of_payed_producers = 121;
void system_contract::onblock( const block_id_type&, block_timestamp timestamp, account_name producer ) {
void system_contract::onblock( block_timestamp timestamp, account_name producer ) {
global_state_singleton gs( _self, _self );
auto parameters = gs.exists() ? gs.get() : get_default_parameters();
......
......@@ -4,6 +4,7 @@
namespace eosio { namespace chain {
/*
uint32_t block_header_state::calc_dpos_last_irreversible()const {
if( producer_to_last_produced.size() == 0 )
return 0;
......@@ -18,11 +19,13 @@ namespace eosio { namespace chain {
return irb[offset];
}
*/
bool block_header_state::is_active_producer( account_name n )const {
return producer_to_last_produced.find(n) != producer_to_last_produced.end();
}
/*
block_timestamp_type block_header_state::get_slot_time( uint32_t slot_num )const {
auto t = header.timestamp;
FC_ASSERT( std::numeric_limits<decltype(t.slot)>::max() - t.slot >= slot_num, "block timestamp overflow" );
......@@ -40,6 +43,7 @@ namespace eosio { namespace chain {
producer_key block_header_state::get_scheduled_producer( uint32_t slot_num )const {
return get_scheduled_producer( get_slot_time(slot_num) );
}
*/
producer_key block_header_state::get_scheduled_producer( block_timestamp_type t )const {
auto index = t.slot % (active_schedule.producers.size() * config::producer_repetitions);
......@@ -47,10 +51,12 @@ namespace eosio { namespace chain {
return active_schedule.producers[index];
}
/*
uint32_t block_header_state::producer_participation_rate()const
{
return static_cast<uint32_t>(config::percent_100); // Ignore participation rate for now until we construct a better metric.
}
*/
/**
......@@ -79,9 +85,7 @@ namespace eosio { namespace chain {
result.block_num = block_num + 1;
result.producer_to_last_produced = producer_to_last_produced;
result.producer_to_last_produced[prokey.producer_name] = result.block_num;
result.dpos_last_irreversible_blocknum = result.calc_dpos_last_irreversible();
result.bft_irreversible_blocknum =
std::max(bft_irreversible_blocknum,result.dpos_last_irreversible_blocknum);
// result.dpos_last_irreversible_blocknum = result.calc_dpos_last_irreversible();
result.blockroot_merkle = blockroot_merkle;
result.blockroot_merkle.append( id );
......@@ -89,6 +93,24 @@ namespace eosio { namespace chain {
result.active_schedule = active_schedule;
result.pending_schedule = pending_schedule;
result.dpos2_lib = dpos2_lib;
result.dpos_last_irreversible_blocknum = dpos2_lib;
result.bft_irreversible_blocknum =
std::max(bft_irreversible_blocknum,result.dpos_last_irreversible_blocknum);
/// grow the confirmed count
if( confirm_count.size() < 1024 ) {
result.confirm_count.reserve( confirm_count.size() + 1 );
result.confirm_count = confirm_count;
result.confirm_count.resize( confirm_count.size() + 1 );
result.confirm_count.back() = 0;
} else {
result.confirm_count.resize( confirm_count.size() );
memcpy( &result.confirm_count[0], &confirm_count[1], confirm_count.size() - 1 );
result.confirm_count.back() = 0;
}
if( result.pending_schedule.producers.size() &&
......@@ -140,6 +162,12 @@ namespace eosio { namespace chain {
FC_ASSERT( result.header.producer == h.producer, "wrong producer specified" );
FC_ASSERT( result.header.schedule_version == h.schedule_version, "schedule_version in signed block is corrupted" );
//idump((h.producer)(h.block_num()-h.confirmed)(h.block_num()));
auto itr = producer_to_last_produced.find(h.producer);
if( itr != producer_to_last_produced.end() ) {
FC_ASSERT( itr->second <= result.block_num - h.confirmed, "producer double-confirming known range" );
}
// FC_ASSERT( result.header.block_mroot == h.block_mroot, "mistmatch block merkle root" );
/// below this point is state changes that cannot be validated with headers alone, but never-the-less,
......@@ -148,9 +176,14 @@ namespace eosio { namespace chain {
result.set_new_producers( *h.new_producers );
}
result.set_confirmed( h.confirmed );
// idump( (result.confirm_count.size()) );
result.header.action_mroot = h.action_mroot;
result.header.transaction_mroot = h.transaction_mroot;
result.header.producer_signature = h.producer_signature;
//idump((result.header));
result.id = result.header.id();
FC_ASSERT( result.block_signing_key == result.signee(), "block not signed by expected key",
......@@ -159,6 +192,36 @@ namespace eosio { namespace chain {
return result;
} /// next
void block_header_state::set_confirmed( uint16_t num_prev_blocks ) {
/*
idump((num_prev_blocks)(confirm_count.size()));
for( uint32_t i = 0; i < confirm_count.size(); ++i ) {
std::cerr << "confirm_count["<<i<<"] = " << int(confirm_count[i]) << "\n";
}
*/
header.confirmed = num_prev_blocks;
int32_t i = confirm_count.size() - 2;
while( i >= 0 && num_prev_blocks ) {
++confirm_count[i];
//idump((confirm_count[i]));
if( confirm_count[i] > active_schedule.producers.size()*2/3 )
{
uint32_t block_num_for_i = block_num - (confirm_count.size() - 1 - i);
dpos2_lib = block_num_for_i;
idump((dpos2_lib)(block_num)(dpos_last_irreversible_blocknum));
memmove( &confirm_count[0], &confirm_count[i], confirm_count.size() -i );
// wdump((confirm_count.size()-i));
confirm_count.resize( confirm_count.size() - i );
return;
}
--i;
--num_prev_blocks;
}
}
digest_type block_header_state::sig_digest()const {
auto header_bmroot = digest_type::hash( std::make_pair( header.digest(), blockroot_merkle.get_root() ) );
return digest_type::hash( std::make_pair(header_bmroot, pending_schedule_hash) );
......
......@@ -348,6 +348,7 @@ struct controller_impl {
if( add_to_fork_db ) {
pending->_pending_block_state->validated = true;
auto new_bsp = fork_db.add( pending->_pending_block_state );
emit( self.accepted_block_header, pending->_pending_block_state );
head = fork_db.head();
FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" );
}
......@@ -678,6 +679,7 @@ struct controller_impl {
void apply_block( const signed_block_ptr& b ) { try {
try {
start_block( b->timestamp );
self.pending_block_state()->set_confirmed( b->confirmed );
for( const auto& receipt : b->transactions ) {
if( receipt.trx.contains<packed_transaction>() ) {
......@@ -714,7 +716,7 @@ struct controller_impl {
auto new_header_state = fork_db.add( b );
emit( self.accepted_block_header, new_header_state );
maybe_switch_forks();
} FC_LOG_AND_RETHROW()
} FC_LOG_AND_RETHROW( )
}
void push_confirmation( const header_confirmation& c ) {
......
......@@ -57,7 +57,7 @@ namespace eosio { namespace chain {
vector<transaction_receipt> transactions; /// new or generated transactions
};
typedef std::shared_ptr<signed_block> signed_block_ptr;
using signed_block_ptr = std::shared_ptr<signed_block>;
struct producer_confirmation {
block_id_type block_id;
......
......@@ -6,13 +6,25 @@ namespace eosio { namespace chain {
struct block_header
{
block_id_type previous;
block_timestamp_type timestamp;
account_name producer;
/**
* By signing this block this producer is confirming blocks [block_num() - confirmed, blocknum())
* as being the best blocks for that range and that he has not signed any other
* statements that would contradict.
*
* No producer should sign a block with overlapping ranges or it is proof of byzantine
* behavior. When producing a block a producer is always confirming at least the block he
* is building off of. A producer cannot confirm "this" block, only prior blocks.
*/
uint16_t confirmed = 1;
block_id_type previous;
checksum256_type transaction_mroot; /// mroot of cycles_summary
checksum256_type action_mroot; /// mroot of all delivered action receipts
account_name producer;
/** The producer schedule version that should validate this block, this is used to
* indicate that the prior block which included new_producers->version has been marked
......@@ -42,7 +54,8 @@ namespace eosio { namespace chain {
} } /// namespace eosio::chain
FC_REFLECT(eosio::chain::block_header, (previous)(timestamp)
FC_REFLECT(eosio::chain::block_header,
(timestamp)(producer)(confirmed)(previous)
(transaction_mroot)(action_mroot)
(producer)(schedule_version)(new_producers))
......
......@@ -20,26 +20,35 @@ struct block_header_state {
incremental_merkle blockroot_merkle;
flat_map<account_name,uint32_t> producer_to_last_produced;
public_key_type block_signing_key;
vector<uint8_t> confirm_count;
uint32_t bft_irreversible_blocknum = 0;
uint32_t dpos2_lib = 0;
block_header_state next( const signed_block_header& h )const;
block_header_state generate_next( block_timestamp_type when )const;
void set_new_producers( producer_schedule_type next_pending );
void set_confirmed( uint16_t num_prev_blocks );
void add_confirmation( const header_confirmation& c );
uint32_t bft_irreversible_blocknum = 0;
vector<header_confirmation> confirmations;
bool has_pending_producers()const { return pending_schedule.producers.size(); }
uint32_t calc_dpos_last_irreversible()const;
//uint32_t calc_dpos_last_irreversible()const;
bool is_active_producer( account_name n )const;
/*
block_timestamp_type get_slot_time( uint32_t slot_num )const;
uint32_t get_slot_at_time( block_timestamp_type t )const;
producer_key get_scheduled_producer( uint32_t slot_num )const;
producer_key get_scheduled_producer( block_timestamp_type t )const;
uint32_t producer_participation_rate()const;
*/
producer_key get_scheduled_producer( block_timestamp_type t )const;
const block_id_type& prev()const { return header.previous; }
digest_type sig_digest()const;
void sign( const std::function<signature_type(const digest_type&)>& signer );
......
......@@ -27,7 +27,7 @@ namespace eosio { namespace chain {
vector<transaction_metadata_ptr> trxs;
};
typedef std::shared_ptr<block_state> block_state_ptr;
using block_state_ptr = std::shared_ptr<block_state>;
} } /// namespace eosio::chain
......
......@@ -30,6 +30,17 @@ namespace eosio { namespace chain {
static block_timestamp maximum() { return block_timestamp( 0xffff ); }
static block_timestamp min() { return block_timestamp(0); }
block_timestamp next() const {
FC_ASSERT( std::numeric_limits<uint32_t>::max() - slot >= 1, "block timestamp overflow" );
auto result = block_timestamp(*this);
result.slot += 1;
return result;
}
fc::time_point to_time_point() const {
return (fc::time_point)(*this);
}
operator fc::time_point() const {
int64_t msec = slot * (int64_t)IntervalMs;
msec += EpochMs;
......
......@@ -37,7 +37,6 @@ namespace eosio { namespace chain {
struct runtime_limits {
fc::microseconds max_push_block_us = fc::microseconds(100000);
fc::microseconds max_push_transaction_us = fc::microseconds(1000'000);
fc::microseconds max_deferred_transactions_us = fc::microseconds(100000);
};
path block_log_dir = chain::config::default_block_log_dir;
......@@ -196,7 +195,7 @@ namespace eosio { namespace chain {
} } /// eosio::chain
FC_REFLECT( eosio::chain::controller::config::runtime_limits, (max_push_block_us)(max_push_transaction_us)(max_deferred_transactions_us) )
FC_REFLECT( eosio::chain::controller::config::runtime_limits, (max_push_block_us)(max_push_transaction_us) )
FC_REFLECT( eosio::chain::controller::config,
(block_log_dir)
(shared_memory_dir)(shared_memory_size)(read_only)
......
......@@ -31,7 +31,7 @@ namespace eosio { namespace chain {
};
struct transaction_trace;
typedef std::shared_ptr<transaction_trace> transaction_trace_ptr;
using transaction_trace_ptr = std::shared_ptr<transaction_trace>;
struct transaction_trace {
transaction_id_type id;
......@@ -55,7 +55,7 @@ namespace eosio { namespace chain {
uint64_t cpu_usage;
vector<transaction_trace_ptr> trx_traces;
};
typedef std::shared_ptr<block_trace> block_trace_ptr;
using block_trace_ptr = std::shared_ptr<block_trace>;
} } /// namespace eosio::chain
......
......@@ -137,6 +137,7 @@ namespace eosio { namespace chain {
void set_transaction(const transaction& t, const vector<bytes>& cfd, compression_type _compression = none);
};
using packed_transaction_ptr = std::shared_ptr<packed_transaction>;
/**
* When a transaction is generated it can be scheduled to occur
......
......@@ -48,6 +48,6 @@ class transaction_metadata {
uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); }
};
typedef std::shared_ptr<transaction_metadata> transaction_metadata_ptr;
using transaction_metadata_ptr = std::shared_ptr<transaction_metadata>;
} } // eosio::chain
......@@ -444,6 +444,23 @@ namespace fc
wdump( __VA_ARGS__ ); \
}
#define FC_LOG_AND_DROP( ... ) \
catch( fc::exception& er ) { \
wlog( "${details}", ("details",er.to_detail_string()) ); \
} catch( const std::exception& e ) { \
fc::exception fce( \
FC_LOG_MESSAGE( warn, "rethrow ${what}: ",FC_FORMAT_ARG_PARAMS( __VA_ARGS__ )("what",e.what()) ), \
fc::std_exception_code,\
BOOST_CORE_TYPEID(e).name(), \
e.what() ) ; \
wlog( "${details}", ("details",fce.to_detail_string()) ); \
} catch( ... ) { \
fc::unhandled_exception e( \
FC_LOG_MESSAGE( warn, "rethrow", FC_FORMAT_ARG_PARAMS( __VA_ARGS__) ), \
std::current_exception() ); \
wlog( "${details}", ("details",e.to_detail_string()) ); \
}
/**
* @def FC_RETHROW_EXCEPTIONS(LOG_LEVEL,FORMAT,...)
......
......@@ -5,7 +5,6 @@
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <fc/io/json.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/test/unit_test.hpp>
#include <iosfwd>
......@@ -181,15 +180,15 @@ namespace eosio { namespace testing {
static action_result error(const string& msg) { return msg; }
auto get_resolver() {
return [this](const account_name &name) -> optional<abi_serializer> {
return [this]( const account_name& name ) -> optional<abi_serializer> {
try {
const auto &accnt = control->db().get<account_object, by_name>(name);
const auto& accnt = control->db().get<account_object, by_name>( name );
abi_def abi;
if (abi_serializer::to_abi(accnt.abi, abi)) {
return abi_serializer(abi);
if( abi_serializer::to_abi( accnt.abi, abi )) {
return abi_serializer( abi );
}
return optional<abi_serializer>();
} FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name))
} FC_RETHROW_EXCEPTIONS( error, "Failed to find or parse ABI for ${name}", ("name", name))
};
}
......@@ -328,14 +327,10 @@ namespace eosio { namespace testing {
* Utility predicate to check whether an FC_ASSERT message ends with a given string
*/
struct assert_message_ends_with {
assert_message_ends_with(string expected)
:expected(expected)
{}
assert_message_ends_with( string expected )
: expected( expected ) {}
bool operator()( const fc::exception& ex ) {
auto message = ex.get_log().at(0).get_message();
return boost::algorithm::ends_with(message, expected);
}
bool operator()( const fc::exception& ex );
string expected;
};
......@@ -344,17 +339,76 @@ namespace eosio { namespace testing {
* Utility predicate to check whether an FC_ASSERT message contains a given string
*/
struct assert_message_contains {
assert_message_contains(string expected)
:expected(expected)
{}
assert_message_contains( string expected )
: expected( expected ) {}
bool operator()( const fc::exception& ex ) {
auto message = ex.get_log().at(0).get_message();
return boost::algorithm::contains(message, expected);
}
bool operator()( const fc::exception& ex );
string expected;
};
/**
* Utility predicate to check whether an fc::exception message starts with a given string
*/
struct fc_exception_message_starts_with {
fc_exception_message_starts_with( const string& msg )
: expected( msg ) {}
bool operator()( const fc::exception& ex );
string expected;
};
/**
* Utility predicate to check whether an fc::assert_exception message is equivalent to a given string
*/
struct fc_assert_exception_message_is {
fc_assert_exception_message_is( const string& msg )
: expected( msg ) {}
bool operator()( const fc::assert_exception& ex );
string expected;
};
/**
* Utility predicate to check whether an fc::assert_exception message starts with a given string
*/
struct fc_assert_exception_message_starts_with {
fc_assert_exception_message_starts_with( const string& msg )
: expected( msg ) {}
bool operator()( const fc::assert_exception& ex );
string expected;
};
/**
* Utility predicate to check whether an eosio_assert message is equivalent to a given string
*/
struct eosio_assert_message_is {
eosio_assert_message_is( const string& msg )
: expected( "assertion failed: " ) {
expected.append( msg );
}
bool operator()( const fc::assert_exception& ex );
string expected;
};
/**
* Utility predicate to check whether an eosio_assert message starts with a given string
*/
struct eosio_assert_message_starts_with {
eosio_assert_message_starts_with( const string& msg )
: expected( "assertion failed: " ) {
expected.append( msg );
}
bool operator()( const fc::assert_exception& ex );
string expected;
};
} } /// eosio::testing
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/chain/eosio_contract.hpp>
......@@ -118,6 +119,16 @@ namespace eosio { namespace testing {
while( control->push_next_scheduled_transaction( fc::time_point::maximum() ) );
}
auto hb = control->head_block_state();
auto pb = control->pending_block_state();
const auto& lpp_map = hb->producer_to_last_produced;
auto pitr = lpp_map.find( pb->header.producer );
if( pitr != lpp_map.end() ) {
if( pb->block_num == pitr->second ) {
wdump((pb->block_num));
}
control->pending_block_state()->set_confirmed( pb->block_num - pitr->second );
}
control->finalize_block();
control->sign_block( [&]( digest_type d ) {
return priv_key.sign(d);
......@@ -679,6 +690,81 @@ namespace eosio { namespace testing {
return tid;
}
bool assert_message_ends_with::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
return boost::algorithm::ends_with( message, expected );
}
bool assert_message_contains::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
return boost::algorithm::contains( message, expected );
}
bool fc_exception_message_starts_with::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = boost::algorithm::starts_with( message, expected );
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
bool fc_assert_exception_message_is::operator()( const fc::assert_exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = false;
auto pos = message.find( ": " );
if( pos != std::string::npos ) {
message = message.substr( pos + 2 );
match = (message == expected);
}
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
bool fc_assert_exception_message_starts_with::operator()( const fc::assert_exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = false;
auto pos = message.find( ": " );
if( pos != std::string::npos ) {
message = message.substr( pos + 2 );
match = boost::algorithm::starts_with( message, expected );
}
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
bool eosio_assert_message_is::operator()( const fc::assert_exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = false;
auto pos = message.find( ": " );
if( pos != std::string::npos ) {
message = message.substr( pos + 2 );
match = (message == expected);
}
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
bool eosio_assert_message_starts_with::operator()( const fc::assert_exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
bool match = false;
auto pos = message.find( ": " );
if( pos != std::string::npos ) {
message = message.substr( pos + 2 );
match = boost::algorithm::starts_with( message, expected );
}
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
} } /// eosio::test
std::ostream& operator<<( std::ostream& osm, const fc::variant& v ) {
......
......@@ -25,11 +25,14 @@ namespace eosio { namespace chain { namespace plugin_interface {
using accepted_transaction = channel_decl<struct accepted_transaction_tag, transaction_metadata_ptr>;
using applied_transaction = channel_decl<struct applied_transaction_tag, transaction_trace_ptr>;
using accepted_confirmation = channel_decl<struct accepted_confirmation_tag, header_confirmation>;
using incoming_block = channel_decl<struct incoming_blocks_tag, signed_block_ptr>;
using incoming_transaction = channel_decl<struct incoming_transactions_tag, packed_transaction_ptr>;
}
namespace methods {
using get_block_by_number = method_decl<chain_plugin_interface, const signed_block_ptr&(uint32_t block_num)>;
using get_block_by_id = method_decl<chain_plugin_interface, const signed_block_ptr&(const block_id_type& block_id)>;
using get_block_by_number = method_decl<chain_plugin_interface, signed_block_ptr(uint32_t block_num)>;
using get_block_by_id = method_decl<chain_plugin_interface, signed_block_ptr(const block_id_type& block_id)>;
using get_head_block_id = method_decl<chain_plugin_interface, block_id_type ()>;
using get_last_irreversible_block_number = method_decl<chain_plugin_interface, uint32_t ()>;
......
......@@ -45,6 +45,7 @@ public:
,accepted_transaction_channel(app().get_channel<channels::accepted_transaction>())
,applied_transaction_channel(app().get_channel<channels::applied_transaction>())
,accepted_confirmation_channel(app().get_channel<channels::accepted_confirmation>())
,incoming_block_channel(app().get_channel<channels::incoming_block>())
{}
bfs::path block_log_dir;
......@@ -61,7 +62,6 @@ public:
chain_id_type chain_id;
int32_t max_reversible_block_time_ms;
int32_t max_pending_transaction_time_ms;
int32_t max_deferred_transaction_time_ms;
//txn_msg_rate_limits rate_limits;
fc::optional<vm_type> wasm_runtime;
......@@ -72,6 +72,7 @@ public:
channels::accepted_transaction::channel_type& accepted_transaction_channel;
channels::applied_transaction::channel_type& applied_transaction_channel;
channels::accepted_confirmation::channel_type& accepted_confirmation_channel;
channels::incoming_block::channel_type& incoming_block_channel;
// method provider handles
methods::get_block_by_number::method_type::handle get_block_by_number_provider;
......@@ -79,6 +80,8 @@ public:
methods::get_head_block_id::method_type::handle get_head_block_id_provider;
methods::get_last_irreversible_block_number::method_type::handle get_last_irreversible_block_number_provider;
// things we subscribe to
channels::incoming_transaction::channel_type::handle incoming_transaction_subscription;
};
chain_plugin::chain_plugin()
......@@ -99,8 +102,6 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
"Limits the maximum time (in milliseconds) that a reversible block is allowed to run before being considered invalid")
("max-pending-transaction-time", bpo::value<int32_t>()->default_value(30),
"Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid")
("max-deferred-transaction-time", bpo::value<int32_t>()->default_value(20),
"Limits the maximum time (in milliseconds) that is allowed a to push deferred transactions at the start of a block")
("wasm-runtime", bpo::value<eosio::chain::wasm_interface::vm_type>()->value_name("wavm/binaryen"), "Override default WASM runtime")
("shared-memory-size-mb", bpo::value<uint64_t>()->default_value(config::default_shared_memory_size / (1024 * 1024)), "Maximum size MB of database shared memory file")
......@@ -182,7 +183,6 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->max_reversible_block_time_ms = options.at("max-reversible-block-time").as<int32_t>();
my->max_pending_transaction_time_ms = options.at("max-pending-transaction-time").as<int32_t>();
my->max_deferred_transaction_time_ms = options.at("max-deferred-transaction-time").as<int32_t>();
if(options.count("wasm-runtime"))
my->wasm_runtime = options.at("wasm-runtime").as<vm_type>();
......@@ -209,21 +209,17 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->chain_config->limits.max_push_transaction_us = fc::milliseconds(my->max_pending_transaction_time_ms);
}
if (my->max_deferred_transaction_time_ms > 0 ) {
my->chain_config->limits.max_deferred_transactions_us = fc::milliseconds(my->max_deferred_transaction_time_ms);
}
if(my->wasm_runtime)
my->chain_config->wasm_runtime = *my->wasm_runtime;
my->chain.emplace(*my->chain_config);
// set up method providers
my->get_block_by_number_provider = app().get_method<methods::get_block_by_number>().register_provider([this](uint32_t block_num) -> const signed_block_ptr& {
my->get_block_by_number_provider = app().get_method<methods::get_block_by_number>().register_provider([this](uint32_t block_num) -> signed_block_ptr {
return my->chain->fetch_block_by_number(block_num);
});
my->get_block_by_id_provider = app().get_method<methods::get_block_by_id>().register_provider([this](block_id_type id) -> const signed_block_ptr& {
my->get_block_by_id_provider = app().get_method<methods::get_block_by_id>().register_provider([this](block_id_type id) -> signed_block_ptr {
return my->chain->fetch_block_by_id(id);
});
......@@ -259,6 +255,12 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->chain->accepted_confirmation.connect([this](const header_confirmation& conf){
my->accepted_confirmation_channel.publish(conf);
});
my->incoming_transaction_subscription = app().get_channel<channels::incoming_transaction>().subscribe([this](const packed_transaction_ptr& ptrx){
try {
my->chain->push_transaction(std::make_shared<transaction_metadata>(*ptrx), get_transaction_deadline());
} FC_LOG_AND_DROP();
});
}
void chain_plugin::plugin_startup()
......@@ -286,7 +288,7 @@ chain_apis::read_write chain_plugin::get_read_write_api() {
}
void chain_plugin::accept_block(const signed_block_ptr& block ) {
chain().push_block( block );
my->incoming_block_channel.publish(block);
}
void chain_plugin::accept_transaction(const packed_transaction& trx) {
......
......@@ -239,8 +239,6 @@ struct faucet_testnet_plugin_impl {
trx.sign(_create_account_private_key, chainid);
try {
if( !cc.pending_block_state() )
cc.start_block();
cc.push_transaction( std::make_shared<transaction_metadata>(trx) );
} catch (const account_name_exists_exception& ) {
// another transaction ended up adding the account, so look for alternates
......
......@@ -7,4 +7,4 @@ add_library( producer_plugin
target_link_libraries( producer_plugin chain_plugin appbase eosio_chain eos_utilities )
target_include_directories( producer_plugin
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" )
......@@ -4,6 +4,7 @@
*/
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/plugin_interface.hpp>
#include <fc/io/json.hpp>
#include <fc/smart_ref_impl.hpp>
......@@ -24,11 +25,13 @@ namespace eosio {
static appbase::abstract_plugin& _producer_plugin = app().register_plugin<producer_plugin>();
using namespace eosio::chain;
using namespace eosio::chain::plugin_interface;
class producer_plugin_impl {
public:
producer_plugin_impl(boost::asio::io_service& io)
: _timer(io) {}
:_timer(io)
{}
void schedule_production_loop();
block_production_condition::block_production_condition_enum block_production_loop();
......@@ -43,6 +46,8 @@ class producer_plugin_impl {
std::set<chain::account_name> _producers;
boost::asio::deadline_timer _timer;
int32_t _max_deferred_transaction_time_ms;
block_production_condition::block_production_condition_enum _prev_result = block_production_condition::produced;
uint32_t _prev_result_count = 0;
......@@ -52,6 +57,8 @@ class producer_plugin_impl {
producer_plugin* _self = nullptr;
channels::incoming_block::channel_type::handle _incoming_block_subscription;
void on_block( const block_state_ptr& bsp ) {
if( bsp->header.timestamp <= _last_signed_block_time ) return;
if( bsp->header.timestamp <= _start_time ) return;
......@@ -83,6 +90,20 @@ class producer_plugin_impl {
}
} ) );
}
void on_incoming_block(const signed_block_ptr& block) {
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
// abort the pending block
chain.abort_block();
try {
// push the new block
chain.push_block(block);
} FC_LOG_AND_DROP();
// restart our production loop
schedule_production_loop();
}
};
void new_chain_banner(const eosio::chain::controller& db)
......@@ -97,7 +118,7 @@ void new_chain_banner(const eosio::chain::controller& db)
"*******************************\n"
"\n";
if( db.head_block_state()->get_slot_at_time(fc::time_point::now()) > 200 )
if( db.head_block_state()->header.timestamp.to_time_point() < (fc::time_point::now() - fc::milliseconds(200 * config::block_interval_ms)))
{
std::cerr << "Your genesis seems to have an old timestamp\n"
"Please consider using the --genesis-timestamp option to give your genesis a recent timestamp\n"
......@@ -125,6 +146,8 @@ void producer_plugin::set_program_options(
producer_options.add_options()
("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e;}), "Enable block production, even if the chain is stale.")
("max-deferred-transaction-time", bpo::value<int32_t>()->default_value(20),
"Limits the maximum time (in milliseconds) that is allowed a to push deferred transactions at the start of a block")
("required-participation", boost::program_options::value<uint32_t>()
->default_value(uint32_t(config::required_producer_participation/config::percent_1))
->notifier([this](uint32_t e) {
......@@ -186,6 +209,13 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
my->_private_keys[key_id_to_wif_pair.first] = key_id_to_wif_pair.second;
}
}
my->_max_deferred_transaction_time_ms = options.at("max-deferred-transaction-time").as<int32_t>();
my->_incoming_block_subscription = app().get_channel<channels::incoming_block>().subscribe([this](const signed_block_ptr& block){
my->on_incoming_block(block);
});
} FC_LOG_AND_RETHROW() }
void producer_plugin::plugin_startup()
......@@ -206,7 +236,7 @@ void producer_plugin::plugin_startup()
my->schedule_production_loop();
} else
elog("No producers configured! Please add producer IDs and private keys to configuration.");
ilog("producer plugin: plugin_startup() end");
ilog("producer plugin: plugin_startup() end");
} FC_CAPTURE_AND_RETHROW() }
void producer_plugin::plugin_shutdown() {
......@@ -218,6 +248,8 @@ void producer_plugin::plugin_shutdown() {
}
void producer_plugin_impl::schedule_production_loop() {
_timer.cancel();
//Schedule for the next second's tick regardless of chain state
// If we would wait less than 50ms (1/10 of block_interval), wait for the whole block interval.
fc::time_point now = fc::time_point::now();
......@@ -229,14 +261,42 @@ void producer_plugin_impl::schedule_production_loop() {
time_to_next_block_time += config::block_interval_us;
}
fc::time_point block_time = now + fc::microseconds(time_to_next_block_time);
static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
_timer.expires_at( epoch + boost::posix_time::microseconds(block_time.time_since_epoch().count()));
chain::controller& chain = app().get_plugin<chain_plugin>().chain();
try {
chain.abort_block();
chain.start_block(block_time);
} FC_LOG_AND_DROP();
if (chain.pending_block_state()) {
// TODO: BIG BAD WARNING, THIS WILL HAPPILY BLOW PAST DEADLINES BUT CONTROLLER IS NOT YET SAFE FOR DEADLINE USAGE
try {
while (chain.push_next_unapplied_transaction(fc::time_point::maximum()));
} FC_LOG_AND_DROP();
chain.abort_block();
chain.start_block( now + fc::microseconds(time_to_next_block_time) );
try {
while (chain.push_next_scheduled_transaction(fc::time_point::maximum()));
} FC_LOG_AND_DROP();
_timer.expires_from_now( boost::posix_time::microseconds(time_to_next_block_time) );
//_timer.async_wait(boost::bind(&producer_plugin_impl::block_production_loop, this));
_timer.async_wait( [&](const boost::system::error_code&){ block_production_loop(); } );
//_timer.async_wait(boost::bind(&producer_plugin_impl::block_production_loop, this));
_timer.async_wait([&](const boost::system::error_code& ec) {
if (ec != boost::asio::error::operation_aborted) {
block_production_loop();
}
});
} else {
elog("Failed to start a pending block, will try again later");
// we failed to start a block, so try again later?
_timer.async_wait([&](const boost::system::error_code& ec) {
if (ec != boost::asio::error::operation_aborted) {
schedule_production_loop();
}
});
}
}
block_production_condition::block_production_condition_enum producer_plugin_impl::block_production_loop() {
......@@ -320,19 +380,13 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
// If the next block production opportunity is in the present or future, we're synced.
if( !_production_enabled )
{
if( hbs.get_slot_time(1) >= now )
if( hbs.header.timestamp.next().to_time_point() >= now )
_production_enabled = true;
else
return block_production_condition::not_synced;
}
// is anyone scheduled to produce now or one second in the future?
uint32_t slot = hbs.get_slot_at_time( now );
if( slot == 0 )
{
capture("next_time", hbs.get_slot_time(1));
return block_production_condition::not_time_yet;
}
auto pending_block_timestamp = chain.pending_block_state()->header.timestamp;
//
// this assert should not fail, because now <= db.head_block_time()
......@@ -344,7 +398,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
//
assert( now > chain.head_block_time() );
const auto& scheduled_producer = hbs.get_scheduled_producer( slot );
const auto& scheduled_producer = hbs.get_scheduled_producer( pending_block_timestamp );
// we must control the producer scheduled to produce the next block.
if( _producers.find( scheduled_producer.producer_name ) == _producers.end() )
{
......@@ -352,7 +406,6 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
return block_production_condition::not_my_turn;
}
auto scheduled_time = hbs.get_slot_time( slot );
auto private_key_itr = _private_keys.find( scheduled_producer.block_signing_key );
if( private_key_itr == _private_keys.end() )
......@@ -361,16 +414,16 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
return block_production_condition::no_private_key;
}
uint32_t prate = hbs.producer_participation_rate();
/*uint32_t prate = hbs.producer_participation_rate();
if( prate < _required_producer_participation )
{
capture("pct", uint32_t(prate / config::percent_1));
return block_production_condition::low_participation;
}
}*/
if( llabs(( time_point(scheduled_time) - now).count()) > fc::milliseconds( config::block_interval_ms ).count() )
if( llabs(( pending_block_timestamp.to_time_point() - now).count()) > fc::milliseconds( config::block_interval_ms ).count() )
{
capture("scheduled_time", scheduled_time)("now", now);
capture("scheduled_time", pending_block_timestamp)("now", now);
return block_production_condition::lag;
}
......
......@@ -73,8 +73,6 @@ using namespace eosio::chain;
struct txn_test_gen_plugin_impl {
transaction_trace_ptr push_transaction( signed_transaction& trx ) { try {
controller& cc = app().get_plugin<chain_plugin>().chain();
if( !cc.pending_block_state() )
cc.start_block();
return cc.push_transaction( std::make_shared<transaction_metadata>(trx) );
} FC_CAPTURE_AND_RETHROW( (transaction_header(trx)) ) }
......
......@@ -544,7 +544,7 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
// 1) compilation of the smart contract should probably not count towards the CPU time of a transaction that first uses it;
// 2) checktime should eventually switch to a deterministic metric which should hopefully fix the inconsistencies
// of this test succeeding/failing on different machines (for example, succeeding on our local dev machines but failing on Jenkins).
TESTER t( {fc::milliseconds(5000), fc::milliseconds(5000), fc::milliseconds(-1)} );
TESTER t( {fc::milliseconds(5000), fc::milliseconds(5000)} );
t.produce_blocks(2);
t.create_account( N(testapi) );
......
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>
#include <eosio.token/eosio.token.wast.hpp>
#include <eosio.token/eosio.token.abi.hpp>
......@@ -13,8 +12,6 @@
using namespace eosio::testing;
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::chain::contracts;
using namespace eosio::chain_apis;
using namespace eosio::testing;
using namespace fc;
using namespace std;
......@@ -35,7 +32,7 @@ public:
produce_blocks();
const auto& accnt = control->get_database().get<account_object,by_name>( N(eosio.token) );
const auto& accnt = control->db().get<account_object,by_name>( N(eosio.token) );
abi_def abi;
BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
abi_ser.set_abi(abi);
......@@ -279,15 +276,15 @@ BOOST_FIXTURE_TEST_CASE( transfer_tests, eosio_token_tester ) try {
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: invalid quantity" ),
transfer( N(alice), N(alice), asset::from_string("4611686018427387904 CERO"), "hola" )
transfer( N(alice), N(bob), asset::from_string("4611686018427387904 CERO"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: must transfer positive quantity" ),
transfer( N(alice), N(alice), asset::from_string("-1000 CERO"), "hola" )
transfer( N(alice), N(bob), asset::from_string("-1000 CERO"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: attempt to subtract asset with different symbol" ),
transfer( N(alice), N(alice), asset::from_string("1.0 CERO"), "hola" )
transfer( N(alice), N(bob), asset::from_string("1.0 CERO"), "hola" )
);
} FC_LOG_AND_RETHROW()
......
......@@ -22,6 +22,21 @@ public_key_type get_public_key( name keyname, string role ){
BOOST_AUTO_TEST_SUITE(forked_tests)
BOOST_AUTO_TEST_CASE( irrblock ) try {
tester c;
c.produce_blocks(10);
auto r = c.create_accounts( {N(dan),N(sam),N(pam),N(scott)} );
auto res = c.set_producers( {N(dan),N(sam),N(pam),N(scott)} );
vector<producer_key> sch = { {N(dan),get_public_key(N(dan), "active")},
{N(sam),get_public_key(N(sam), "active")},
{N(scott),get_public_key(N(scott), "active")},
{N(pam),get_public_key(N(pam), "active")}
};
wlog("set producer schedule to [dan,sam,pam]");
c.produce_blocks(50);
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_CASE( forking ) try {
tester c;
c.produce_block();
......@@ -135,7 +150,7 @@ BOOST_AUTO_TEST_CASE( forking ) try {
b = c.produce_block();
expected_producer = N(cam);
BOOST_REQUIRE_EQUAL( b->producer.to_string(), expected_producer.to_string() );
// BOOST_REQUIRE_EQUAL( b->producer.to_string(), expected_producer.to_string() );
c.produce_blocks(10);
wlog( "push c1 blocks to c2" );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册