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

Commit

Permalink
Ref #19: Progress on producer voting and race
Browse files Browse the repository at this point in the history
Begin defining objects and contract handlers for tracking producer votes
and the "race" to select runner-up producers
  • Loading branch information
nathanielhourt committed Jun 3, 2017
1 parent 0e03af7 commit 8c8e555
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 56 deletions.
1 change: 0 additions & 1 deletion libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ add_library( eos_chain
chain_controller.cpp
fork_database.cpp

producer_object.cpp
transaction.cpp
block.cpp

Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eos/chain/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const static UInt32 DefaultMaxTrxLifetime = 60*60;
const static int ProducerCount = 21;
const static int IrreversibleThresholdPercent = 70 * Percent1;

const static UInt128 ProducerScheduleLapLength = std::numeric_limits<UInt128>::max();
const static UInt128 ProducerRaceLapLength = std::numeric_limits<UInt128>::max();
} } // namespace eos::config

template<typename Number>
Expand Down
45 changes: 1 addition & 44 deletions libraries/chain/include/eos/chain/producer_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,49 +40,6 @@ class producer_object : public chainbase::object<producer_object_type, producer_

/// The blockchain configuration values this producer recommends
BlockchainConfiguration configuration;

/**
* @brief Update the tally of votes for the producer, while maintaining virtual time accounting
*
* This function will update @ref votes to @ref new_votes, while also updating all of the @ref virtual_time
* accounting as well.
*
* @param new_votes The new tally of votes for this producer
* @param current_virtual_time The current virtual time (see @ref virtual_time)
*/
void update_votes(ShareType new_votes, UInt128 current_virtual_time);

/// The total votes for this producer
/// @warning Do not update this value directly; use @ref update_votes instead!
ShareType votes;

/**
* These fields are used for the producer scheduling algorithm which uses virtual time to ensure that all producers
* are given proportional time for producing blocks.
*
* @ref votes is used to determine speed. The @ref virtual_scheduled_time is the expected time at which this
* producer should complete a virtual lap which is defined as the position equal to
* config::ProducerScheduleLapLength
*
* virtual_scheduled_time = virtual_last_update + (config::ProducerScheduleLapLength - virtual_position) / votes
*
* Every time the number of votes changes the virtual_position and virtual_scheduled_time must update. There is a
* global current virtual_scheduled_time which gets updated every time a producer is scheduled. To update the
* virtual_position the following math is performed.
*
* virtual_position = virtual_position + votes * (virtual_current_time - virtual_last_update)
* virtual_last_update = virtual_current_time
* votes += delta_vote
* virtual_scheduled_time = virtual_last_update + (config::ProducerScheduleLapLength - virtual_position) / votes
*
*/
///@defgroup virtual_time Virtual Time Scheduling
/// @warning Do not update these values directly; use @ref update_votes instead!
///@{
UInt128 virtual_last_update_time;
UInt128 virtual_position;
UInt128 virtual_scheduled_time = std::numeric_limits<UInt128>::max();
///@}
};

struct by_key;
Expand All @@ -101,4 +58,4 @@ using producer_multi_index = chainbase::shared_multi_index_container<
CHAINBASE_SET_INDEX_TYPE(eos::chain::producer_object, eos::chain::producer_multi_index)

FC_REFLECT(eos::chain::producer_object, (id)(owner)(last_aslot)(signing_key)(total_missed)(last_confirmed_block_num)
(configuration)(virtual_last_update_time)(virtual_position)(virtual_scheduled_time))
(configuration))
2 changes: 2 additions & 0 deletions libraries/chain/include/eos/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ namespace eos { namespace chain {
transaction_object_type,
producer_object_type,
chain_property_object_type,
producer_votes_object_type, ///< Defined by native_system_contract_plugin
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
};

Expand Down Expand Up @@ -195,6 +196,7 @@ FC_REFLECT_ENUM( eos::chain::object_type,
(transaction_object_type)
(producer_object_type)
(chain_property_object_type)
(producer_votes_object_type)
(OBJECT_TYPE_COUNT)
)
FC_REFLECT( eos::chain::void_t, )
10 changes: 0 additions & 10 deletions libraries/chain/producer_object.cpp

This file was deleted.

2 changes: 2 additions & 0 deletions plugins/native_system_contract_plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ file(GLOB HEADERS "include/eos/native_system_contract_plugin/*.hpp")
add_library( native_system_contract_plugin
native_system_contract_plugin.cpp
staked_balance_contract.cpp
staked_balance_objects.hpp
staked_balance_objects.cpp
system_contract.cpp
eos_contract.cpp
${HEADERS} )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ struct UpdateProducer {
static void apply(chain::apply_context& context);
};

struct ApproveProducer {
static void validate(chain::message_validate_context& context);
static void validate_preconditions(chain::precondition_validate_context& context);
static void apply(chain::apply_context& context);
};

} // namespace eos
13 changes: 13 additions & 0 deletions plugins/native_system_contract_plugin/staked_balance_contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <eos/chain/account_object.hpp>
#include <eos/chain/exceptions.hpp>


namespace eos {
using namespace chain;

Expand Down Expand Up @@ -55,4 +56,16 @@ void UpdateProducer::apply(apply_context& context) {
});
}

void ApproveProducer::validate(message_validate_context& context) {

}

void ApproveProducer::validate_preconditions(precondition_validate_context& context) {

}

void ApproveProducer::apply(apply_context& context) {

}

} // namespace eos
19 changes: 19 additions & 0 deletions plugins/native_system_contract_plugin/staked_balance_objects.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "staked_balance_objects.hpp"

namespace eos {
using namespace chain;
using namespace types;

void ProducerVotesObject::updateVotes(ShareType deltaVotes, UInt128 currentRaceTime) {
auto timeSinceLastUpdate = currentRaceTime - race.positionUpdateTime;
race.position += race.speed * timeSinceLastUpdate;
race.positionUpdateTime = currentRaceTime;

race.speed += deltaVotes;
auto distanceRemaining = config::ProducerRaceLapLength - race.position;
auto projectedTimeToFinish = distanceRemaining / race.speed;

race.projectedFinishTime = currentRaceTime + projectedTimeToFinish;
}

} // namespace eos
106 changes: 106 additions & 0 deletions plugins/native_system_contract_plugin/staked_balance_objects.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#pragma once

#include <eos/chain/types.hpp>
#include <eos/chain/multi_index_includes.hpp>

#include <eos/types/types.hpp>

#include <boost/multi_index/mem_fun.hpp>

namespace eos {

/**
* @brief The ProducerVotesObject class tracks all votes for and by the block producers
*
* This class tracks the voting for block producers, as well as the virtual time 'race' to select the runner-up block
* producer.
*
* This class also tracks the votes cast by block producers on various chain configuration options and key documents.
*/
class ProducerVotesObject : public chainbase::object<chain::producer_votes_object_type, ProducerVotesObject> {
OBJECT_CTOR(ProducerVotesObject)

id_type id;
types::AccountName ownerName;

/**
* @brief Update the tally of votes for the producer, while maintaining virtual time accounting
*
* This function will update the producer's position in the race
*
* @param deltaVotes The change in votes since the last update
* @param currentRaceTime The current "race time"
*/
void updateVotes(types::ShareType deltaVotes, types::UInt128 currentRaceTime);
/// @brief Get the number of votes this producer has received
types::ShareType getVotes() const { return race.speed; }

/**
* These fields are used for the producer scheduling algorithm which uses a virtual race to ensure that runner-up
* producers are given proportional time for producing blocks. Producers are constantly running a racetrack of
* length config::ProducerRaceLapLength, at a speed equal to the number of votes they have received. Runner-up
* producers, who lack sufficient votes to get in as a top-N voted producer, get scheduled to produce a block every
* time they finish the race. The race algorithm ensures that runner-up producers are scheduled with a frequency
* proportional to their relative vote tallies; i.e. a runner-up with more votes is scheduled more often than one
* with fewer votes, but all runners-up with any votes will theoretically be scheduled eventually.
*
* Whenever a runner-up producer needs to be scheduled, the one projected to finish the race next is taken, with the
* caveat that any producers already scheduled for other reasons (such as being a top-N voted producer) cannot be
* scheduled a second time in the same round, and thus they are skipped/ignored when looking for the producer
* projected to finish next. After selecting the runner-up for scheduling, the global current race time is updated
* to the point at which the winner crossed the finish line (i.e. his position is zero: he is now beginning his next
* lap). Furthermore, all producers which crossed the finish line ahead of the winner, but were ineligible to win as
* they were already scheduled in the next round, are effectively held at the finish line until the winner crosses,
* so their positions are all also set to zero.
*
* Every time the number of votes for a given producer changes, the producer's speed in the race changes and thus
* his projected finishing time changes. In this event, the stats must be updated: first, the producer's position is
* updated to reflect his progress since the last stats update to the current race time; second, the producer's
* projected finishing time based on his new position and speed are updated so we know where he shakes out in the
* new projected finish times.
*
* @warning Do not update these values directly; use @ref updateVotes instead!
*/
struct {
/// The current speed for this producer (which is actually the total votes for the producer)
types::ShareType speed;
/// The position of this producer when we last updated the records
types::UInt128 position;
/// The "race time" when we last updated the records
types::UInt128 positionUpdateTime;
/// The projected "race time" at which this producer will finish the race
types::UInt128 projectedFinishTime = std::numeric_limits<types::UInt128>::max();
} race;

types::UInt128 projectedRaceFinishTime() const { return race.projectedFinishTime; }
};

using boost::multi_index::const_mem_fun;

/// Index producers by their owner account's name
struct byOwnerName;
/// Index producers by projected race finishing time, from soonest to latest
struct byProjectedRaceFinishTime;
/// Index producers by votes, from greatest to least
struct byVotes;

using ProducerMultiIndex = chainbase::shared_multi_index_container<
ProducerVotesObject,
indexed_by<
ordered_unique<tag<by_id>,
member<ProducerVotesObject, ProducerVotesObject::id_type, &ProducerVotesObject::id>
>,
ordered_unique<tag<byOwnerName>,
member<ProducerVotesObject, types::AccountName, &ProducerVotesObject::ownerName>
>,
ordered_non_unique<tag<byVotes>,
const_mem_fun<ProducerVotesObject, types::ShareType, &ProducerVotesObject::getVotes>,
std::greater<types::ShareType>
>,
ordered_non_unique<tag<byProjectedRaceFinishTime>,
const_mem_fun<ProducerVotesObject, types::UInt128, &ProducerVotesObject::projectedRaceFinishTime>
>
>
>;

} // namespace eos

0 comments on commit 8c8e555

Please sign in to comment.