Skip to content

Commit

Permalink
Extends the version reporting further. Witnesses now vote on a hard f…
Browse files Browse the repository at this point in the history
…ork version and time which is used to create a consensus for when a hard fork should take place. Witnesses on old nodes have knowledge of the hard fork and will stop producing after this time. steemit#54
  • Loading branch information
Michael Vandeberg committed May 23, 2016
1 parent b674403 commit dcd279a
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 45 deletions.
11 changes: 10 additions & 1 deletion libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,20 @@ witness_schedule_object database_api::get_witness_schedule()const
return witness_schedule_id_type()( my->_db );
}

version database_api::get_hardfork_version()const
hardfork_version database_api::get_hardfork_version()const
{
return hardfork_property_id_type()( my->_db ).current_hardfork_version;
}

scheduled_hardfork database_api::get_next_scheduled_hardfork() const
{
scheduled_hardfork shf;
const auto& hpo = hardfork_property_id_type()( my->_db );
shf.hf_version = hpo.next_hardfork;
shf.live_time = hpo.next_hardfork_time;
return shf;
}

//////////////////////////////////////////////////////////////////////
// //
// Keys //
Expand Down
11 changes: 10 additions & 1 deletion libraries/app/include/steemit/app/database_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ struct order_book
vector< order > bids;
};

struct scheduled_hardfork
{
hardfork_version hf_version;
fc::time_point_sec live_time;
};

class database_api_impl;
class application;

Expand Down Expand Up @@ -140,7 +146,8 @@ class database_api
price get_current_median_history_price()const;
feed_history_object get_feed_history()const;
witness_schedule_object get_witness_schedule()const;
version get_hardfork_version()const;
hardfork_version get_hardfork_version()const;
scheduled_hardfork get_next_scheduled_hardfork()const;

//////////
// Keys //
Expand Down Expand Up @@ -351,6 +358,7 @@ class database_api

FC_REFLECT( steemit::app::order, (order_price)(steem)(sbd)(created) );
FC_REFLECT( steemit::app::order_book, (asks)(bids) );
FC_REFLECT( steemit::app::scheduled_hardfork, (hf_version)(live_time) );

FC_API(steemit::app::database_api,
// Subscriptions
Expand All @@ -376,6 +384,7 @@ FC_API(steemit::app::database_api,
(get_current_median_history_price)
(get_witness_schedule)
(get_hardfork_version)
(get_next_scheduled_hardfork)

// Keys
(get_key_references)
Expand Down
123 changes: 88 additions & 35 deletions libraries/chain/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <cstdint>
#include <fstream>
#include <functional>
#include <iostream>

#define VIRTUAL_SCHEDULE_LAP_LENGTH ( fc::uint128(uint64_t(-1)) )
#define VIRTUAL_SCHEDULE_LAP_LENGTH2 ( fc::uint128::max_value() )
Expand Down Expand Up @@ -714,11 +713,19 @@ signed_block database::_generate_block(
pending_block.timestamp = when;
pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
pending_block.witness = witness_owner;
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 ) && get_witness( witness_owner ).running_version != STEEMIT_BLOCKCHAIN_VERSION ) // TODO: Hardfork requirement can be removed after hardfork time
pending_block.extensions.insert( future_extensions( STEEMIT_BLOCKCHAIN_VERSION ) );
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 ) && _confirm_hardfork )
pending_block.extensions.insert( future_extensions( hardfork_property_id_type()(*this).current_hardfork_version ) );
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 ) )
{
if( get_witness( witness_owner ).running_version != STEEMIT_BLOCKCHAIN_VERSION ) // TODO: Hardfork requirement can be removed after hardfork time
pending_block.extensions.insert( future_extensions( STEEMIT_BLOCKCHAIN_VERSION ) );

const auto& hfp = hardfork_property_id_type()( *this );

if( STEEMIT_NUM_HARDFORKS > hfp.last_hardfork )
{
pending_block.extensions.insert( future_extensions( _hardfork_versions[ hfp.last_hardfork + 1 ] ) );
pending_block.extensions.insert( future_extensions( _hardfork_times[ hfp.last_hardfork + 1 ] ) );
}
}

if( !(skip & skip_witness_signature) )
pending_block.sign( block_signing_private_key );
Expand Down Expand Up @@ -968,6 +975,7 @@ void database::update_witness_schedule4() {
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 ) )
{
flat_map< version, uint32_t, std::greater< version > > witness_versions;
flat_map< std::tuple< hardfork_version, time_point_sec >, uint32_t > hardfork_version_votes;

for( uint32_t i = 0; i < wso.current_shuffled_witnesses.size(); i++ )
{
Expand All @@ -979,6 +987,13 @@ void database::update_witness_schedule4() {
witness_versions[ witness.running_version ] = 1;
else
witness_versions[ witness.running_version ] += 1;

auto version_vote = std::make_tuple( witness.hardfork_version_vote, witness.hardfork_time_vote );

if( hardfork_version_votes.find( version_vote ) == hardfork_version_votes.end() )
hardfork_version_votes[ version_vote ] = 1;
else
hardfork_version_votes[ version_vote ] += 1;
}
}

Expand All @@ -995,6 +1010,24 @@ void database::update_witness_schedule4() {

ver_itr++;
}

auto hf_itr = hardfork_version_votes.begin();

while( hf_itr != hardfork_version_votes.end() )
{
if( hf_itr->second > STEEMIT_HARDFORK_REQUIRED_WITNESSES )
{
modify( hardfork_property_id_type()( *this ), [&]( hardfork_property_object& hpo )
{
hpo.next_hardfork = std::get<0>( hf_itr->first );
hpo.next_hardfork_time = std::get<1>( hf_itr->first );
});

break;
}

hf_itr++;
}
}

modify( wso, [&]( witness_schedule_object& _wso ) {
Expand Down Expand Up @@ -1440,7 +1473,6 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar
share_type unclaimed_rewards = max_rewards;
const auto& cvidx = get_index_type<comment_vote_index>().indices().get<by_comment_weight_voter>();
auto itr = cvidx.lower_bound( c.id );
auto start = itr;
while( itr != cvidx.end() && itr->comment == c.id ) {
// TODO: Add minimum curation pay limit
u256 weight( itr->weight );
Expand Down Expand Up @@ -2014,7 +2046,6 @@ FC_LOG_AND_RETHROW() }
void database::process_header_extensions( const signed_block& next_block )
{
auto itr = next_block.extensions.begin();
bool received_hardfork_confirmation = false;

while( itr != next_block.extensions.end() )
{
Expand All @@ -2025,7 +2056,7 @@ void database::process_header_extensions( const signed_block& next_block )
case 1: // version
{
auto reported_version = itr->get< version >();
auto signing_witness = get_witness( next_block.witness );
const auto& signing_witness = get_witness( next_block.witness );

if( reported_version != signing_witness.running_version )
{
Expand All @@ -2034,31 +2065,40 @@ void database::process_header_extensions( const signed_block& next_block )
wo.running_version = reported_version;
});
}
break;
}
case 2: // hardfork_version vote
{
auto hfv = itr->get< hardfork_version >();
const auto& signing_witness = get_witness( next_block.witness );

if( hfv != signing_witness.hardfork_version_vote )
modify( signing_witness, [&]( witness_object& wo )
{
wo.hardfork_version_vote = hfv;
});

break;
}
case 2: // hardfork_version
if( itr->get< hardfork_version >() != hardfork_property_id_type()( *this ).current_hardfork_version )
if( _confirm_hardfork )
FC_ASSERT( false, "Did not receive correct hardfork confirmation" );
else
elog( "Received unexpected hardfork confirmation", ("hardfork_version", itr->get< hardfork_version>()) );
else
received_hardfork_confirmation = true;
case 3: // time_point_sec, for voting on hardfork time
{
auto hft = itr->get< time_point_sec >();
const auto& signing_witness = get_witness( next_block.witness );

if( hft != signing_witness.hardfork_time_vote )
modify( signing_witness, [&]( witness_object& wo )
{
wo.hardfork_time_vote = hft;
});

break;
}
default:
FC_ASSERT( false, "Unknown extension in block header" );
}

itr++;
}

if( _confirm_hardfork )
{
FC_ASSERT( received_hardfork_confirmation, "Did not receive expected hardfork confirmation" );
_confirm_hardfork = false;
}
}

const feed_history_object& database::get_feed_history()const {
Expand Down Expand Up @@ -2689,15 +2729,25 @@ void database::process_hardforks()
// If there are upcoming hardforks and the next one is later, do nothing
const auto& hardforks = hardfork_property_id_type()( *this );

while( hardforks.last_hardfork < STEEMIT_NUM_HARDFORKS
&& _hardfork_times[ hardforks.last_hardfork + 1 ] <= head_block_time() )
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 ) )
{
// After hardfork 0.5, we only trigger hardforks on round barriers and if there is a majority of witness on the required version for the hardfork
if( has_hardfork( STEEMIT_HARDFORK_0_5__54 )
&& witness_schedule_id_type()(*this).majority_version < _hardfork_versions[ hardforks.last_hardfork + 1 ] )
return;

apply_hardfork( hardforks.last_hardfork + 1 );
while( _hardfork_versions[ hardforks.last_hardfork ] < hardforks.next_hardfork
&& hardforks.next_hardfork_time <= head_block_time() )
{
if( hardforks.last_hardfork < STEEMIT_NUM_HARDFORKS )
apply_hardfork( hardforks.last_hardfork + 1 );
else
throw unknown_hardfork_exception();
}
}
else
{
while( hardforks.last_hardfork < STEEMIT_NUM_HARDFORKS
&& _hardfork_times[ hardforks.last_hardfork + 1 ] <= head_block_time()
&& hardforks.last_hardfork < STEEMIT_HARDFORK_0_5__54 )
{
apply_hardfork( hardforks.last_hardfork + 1 );
}
}
}
FC_CAPTURE_AND_RETHROW() }
Expand All @@ -2709,13 +2759,18 @@ bool database::has_hardfork( uint32_t hardfork )const

void database::set_hardfork( uint32_t hardfork, bool apply_now )
{
FC_ASSERT( hardfork <= STEEMIT_NUM_HARDFORKS );

auto const& hardforks = hardfork_property_id_type()( *this );

for( int i = hardforks.last_hardfork + 1; i <= hardfork && i <= STEEMIT_NUM_HARDFORKS; i++ )
{
_hardfork_times[i] = head_block_time();
if( i <= STEEMIT_HARDFORK_0_5__54 )
_hardfork_times[i] = head_block_time();
else
modify( hardforks, [&]( hardfork_property_object& hpo )
{
hpo.next_hardfork = _hardfork_versions[i];
hpo.next_hardfork_time = head_block_time();
});

if( apply_now )
apply_hardfork( i );
Expand Down Expand Up @@ -2778,8 +2833,6 @@ void database::apply_hardfork( uint32_t hardfork )
hfp.current_hardfork_version = _hardfork_versions[ hardfork ];
FC_ASSERT( hfp.processed_hardforks[ hfp.last_hardfork ] == _hardfork_times[ hfp.last_hardfork ], "Hardfork processing failed sanity check..." );
});

_confirm_hardfork = true;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion libraries/chain/hardfork.d/0-preamble.hf
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ class hardfork_property_object : public abstract_object< hardfork_property_objec
vector< fc::time_point_sec > processed_hardforks;
int last_hardfork = 0;
hardfork_version current_hardfork_version;
hardfork_version next_hardfork;
fc::time_point_sec next_hardfork_time;
};

} } // namespace steemit::chain

FC_REFLECT_DERIVED( steemit::chain::hardfork_property_object, (graphene::db::object), (processed_hardforks)(last_hardfork)(current_hardfork_version) )
FC_REFLECT_DERIVED( steemit::chain::hardfork_property_object, (graphene::db::object),
(processed_hardforks)(last_hardfork)(current_hardfork_version)
(next_hardfork)(next_hardfork_time) )

#define STEEMIT_NUM_HARDFORKS 5

3 changes: 2 additions & 1 deletion libraries/chain/hardfork.d/0_5.hf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define STEEMIT_HARDFORK_0_5__58 ( STEEMIT_HARDFORK_0_5 )
#define STEEMIT_HARDFORK_0_5__59 ( STEEMIT_HARDFORK_0_5 )

#define STEEMIT_HARDFORK_0_5_TIME 2462028400
// May 31 2016 17:00:00 UTC (1:00 PM EDT)
#define STEEMIT_HARDFORK_0_5_TIME 1464714000
#define STEEMIT_HARDFORK_0_5_VERSION hardfork_version( 0, 5 )
#endif
1 change: 0 additions & 1 deletion libraries/chain/include/steemit/chain/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@ namespace steemit { namespace chain {
fork_database _fork_db;
fc::time_point_sec _hardfork_times[ STEEMIT_NUM_HARDFORKS + 1 ];
hardfork_version _hardfork_versions[ STEEMIT_NUM_HARDFORKS + 1 ];
bool _confirm_hardfork = false;

/**
* Note: we can probably store blocks by block num rather than
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/steemit/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ namespace steemit { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( utility_exception, steemit::chain::chain_exception, 3060000, "utility method exception" )
FC_DECLARE_DERIVED_EXCEPTION( undo_database_exception, steemit::chain::chain_exception, 3070000, "undo database exception" )
FC_DECLARE_DERIVED_EXCEPTION( unlinkable_block_exception, steemit::chain::chain_exception, 3080000, "unlinkable block" )
FC_DECLARE_DERIVED_EXCEPTION( unknown_hardfork_exception, steemit::chain::chain_exception, 3090000, "chain attempted to apply unknown hardfork" )

FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, steemit::chain::transaction_exception, 3030001, "missing required active authority" )
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, steemit::chain::transaction_exception, 3030002, "missing required owner authority" )
Expand Down
9 changes: 8 additions & 1 deletion libraries/chain/include/steemit/chain/protocol/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <steemit/chain/protocol/authority.hpp>
#include <steemit/chain/protocol/version.hpp>

#include <fc/time.hpp>

namespace steemit { namespace chain {

struct base_operation
Expand All @@ -15,7 +17,12 @@ namespace steemit { namespace chain {
void validate()const{}
};

typedef static_variant<void_t, version, hardfork_version> future_extensions;
typedef static_variant<
void_t,
version, // Normal witness version reporting, for diagnostics and voting
hardfork_version, // Voting for the next hardfork to trigger
fc::time_point_sec // Voting for when that hardfork should happen
> future_extensions;
typedef flat_set<future_extensions> extensions_type;

} } // steemit::chain
Expand Down
16 changes: 15 additions & 1 deletion libraries/chain/include/steemit/chain/protocol/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ struct hardfork_version : version
hardfork_version():version() {}
hardfork_version( uint8_t m, uint8_t h ):version( m, h, 0 ) {}
~hardfork_version() {}

bool operator == ( const hardfork_version& o )const { return v_num == o.v_num; }
bool operator != ( const hardfork_version& o )const { return v_num != o.v_num; }
bool operator < ( const hardfork_version& o )const { return v_num < o.v_num; }
bool operator <= ( const hardfork_version& o )const { return v_num <= o.v_num; }
bool operator > ( const hardfork_version& o )const { return v_num > o.v_num; }
bool operator >= ( const hardfork_version& o )const { return v_num >= o.v_num; }

bool operator == ( const version& o )const { return v_num == ( o.v_num & 0xFFFF0000 ); }
bool operator != ( const version& o )const { return v_num != ( o.v_num & 0xFFFF0000 ); }
bool operator < ( const version& o )const { return v_num < ( o.v_num & 0xFFFF0000 ); }
bool operator <= ( const version& o )const { return v_num <= ( o.v_num & 0xFFFF0000 ); }
bool operator > ( const version& o )const { return v_num > ( o.v_num & 0xFFFF0000 ); }
bool operator >= ( const version& o )const { return v_num >= ( o.v_num & 0xFFFF0000 ); }
};

} } // steemit::chain
Expand All @@ -48,4 +62,4 @@ namespace fc

#include <fc/reflect/reflect.hpp>
FC_REFLECT( steemit::chain::version, (v_num) )
FC_REFLECT_DERIVED( steemit::chain::hardfork_version, (steemit::chain::version), )
FC_REFLECT_DERIVED( steemit::chain::hardfork_version, (steemit::chain::version), )
8 changes: 6 additions & 2 deletions libraries/chain/include/steemit/chain/witness_objects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ namespace steemit { namespace chain {
/**
* This field represents the Steem blockchain version the witness is running.
*/
version running_version;
version running_version;

hardfork_version hardfork_version_vote;
time_point_sec hardfork_time_vote = STEEMIT_GENESIS_TIME;

witness_id_type get_id()const { return id; }
};
Expand Down Expand Up @@ -194,5 +197,6 @@ FC_REFLECT_DERIVED( steemit::chain::witness_vote_object, (graphene::db::object),
FC_REFLECT_DERIVED(
steemit::chain::witness_schedule_object,
(graphene::db::object),
(current_virtual_time)(next_shuffle_block_num)(current_shuffled_witnesses)(median_props)(majority_version)
(current_virtual_time)(next_shuffle_block_num)(current_shuffled_witnesses)(median_props)
(majority_version)
)
Loading

0 comments on commit dcd279a

Please sign in to comment.