Skip to content

Commit

Permalink
refactor: rewards stats passing
Browse files Browse the repository at this point in the history
  • Loading branch information
kstdl committed Apr 28, 2023
1 parent 37166cc commit 4ffe863
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 78 deletions.
7 changes: 1 addition & 6 deletions libraries/common/include/common/range_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <functional>
#include <type_traits>

namespace taraxa::util::range_view {
namespace taraxa::util {

template <typename Element>
struct RangeView {
Expand Down Expand Up @@ -72,9 +72,4 @@ auto make_range_view(Seq const &seq) {
return RangeView<decltype(*seq.begin())>(seq);
}

} // namespace taraxa::util::range_view

namespace taraxa::util {
using range_view::make_range_view;
using range_view::RangeView;
} // namespace taraxa::util
22 changes: 11 additions & 11 deletions libraries/core_libs/consensus/include/final_chain/rewards_stats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace taraxa {
*/
class RewardsStats {
public:
RewardsStats() = default;
RewardsStats(const addr_t& author);
/**
* @brief Process PeriodData and returns vector of validators, who included provided block.transactions as first in
* dag block, e.g. returned validator on position 2 included transaction block.transactions[2] as first in his dag
Expand All @@ -25,7 +27,8 @@ class RewardsStats {
* @param committee_size
* @return vector of validators
*/
std::vector<addr_t> processStats(const PeriodData& block, uint64_t dpos_vote_count, uint32_t committee_size);

void processStats(const PeriodData& block, uint64_t dpos_vote_count, uint32_t committee_size);

HAS_RLP_FIELDS

Expand Down Expand Up @@ -56,15 +59,6 @@ class RewardsStats {
*/
bool addVote(const std::shared_ptr<Vote>& vote);

/**
* @brief Prepares reward statistics bases on period data data
*
* @param sync_blk
* @param dpos_vote_count - votes count for previous block
* @param committee_size
*/
void initStats(const PeriodData& sync_blk, uint64_t dpos_vote_count, uint32_t committee_size);

private:
struct ValidatorStats {
// count of rewardable(with 1 or more unique transactions) DAG blocks produced by this validator
Expand All @@ -76,8 +70,14 @@ class RewardsStats {
HAS_RLP_FIELDS
};

// Pbft block author
addr_t block_author_;

// Transactions validators: tx hash -> validator that included it as first in his block
std::unordered_map<trx_hash_t, addr_t> txs_validators_;
std::unordered_map<trx_hash_t, addr_t> validator_by_tx_hash_;

// Vector with all transactions validators
std::vector<addr_t> txs_validators_;

// Txs stats: validator -> ValidatorStats
std::unordered_map<addr_t, ValidatorStats> validators_stats_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ class StateAPI {
StateDescriptor get_last_committed_state_descriptor() const;
const StateTransitionResult& transition_state(const EVMBlock& block,
const util::RangeView<EVMTransaction>& transactions,
const util::RangeView<addr_t>& transactions_validators = {},
const util::RangeView<UncleBlock>& uncles = {},
const RewardsStats& rewards_stats = {});
const std::vector<RewardsStats>& rewards_stats = {});
void transition_state_commit();
void create_snapshot(PbftPeriod period);
void prune(const dev::h256& state_root_to_keep, const std::vector<dev::h256>& state_root_to_prune,
Expand Down
29 changes: 20 additions & 9 deletions libraries/core_libs/consensus/src/final_chain/final_chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,30 @@ class FinalChainImpl final : public FinalChain {

EthBlockNumber delegation_delay() const override { return delegation_delay_; }

std::shared_ptr<const FinalizationResult> finalize_(PeriodData&& new_blk,
std::vector<h256>&& finalized_dag_blk_hashes,
std::shared_ptr<DagBlock>&& anchor) {
auto batch = db_->createWriteBatch();
std::vector<RewardsStats> prepare_rewards_stats_(const PeriodData& blk) {
std::vector<RewardsStats> rewards_stats;

RewardsStats rewards_stats;
RewardsStats period_stats(blk.pbft_blk->getBeneficiary());
uint64_t dpos_vote_count = kCommitteeSize;

// Block zero
if (!new_blk.previous_block_cert_votes.empty()) [[unlikely]] {
dpos_vote_count = dpos_eligible_total_vote_count(new_blk.previous_block_cert_votes[0]->getPeriod() - 1);
if (!blk.previous_block_cert_votes.empty()) [[likely]] {
dpos_vote_count = dpos_eligible_total_vote_count(blk.previous_block_cert_votes[0]->getPeriod() - 1);
}

// returns list of validators for new_blk.transactions
const std::vector<addr_t> txs_validators = rewards_stats.processStats(new_blk, dpos_vote_count, kCommitteeSize);
period_stats.processStats(blk, dpos_vote_count, kCommitteeSize);
rewards_stats.push_back(period_stats);

return rewards_stats;
}

std::shared_ptr<const FinalizationResult> finalize_(PeriodData&& new_blk,
std::vector<h256>&& finalized_dag_blk_hashes,
std::shared_ptr<DagBlock>&& anchor) {
auto batch = db_->createWriteBatch();

auto rewards_stats = prepare_rewards_stats_(new_blk);

block_applying_emitter_.emit(block_header()->number + 1);

Expand All @@ -178,7 +189,7 @@ class FinalChainImpl final : public FinalChain {
auto const& [exec_results, state_root, total_reward] =
state_api_.transition_state({new_blk.pbft_blk->getBeneficiary(), kBlockGasLimit,
new_blk.pbft_blk->getTimestamp(), BlockHeader::difficulty()},
to_state_api_transactions(new_blk.transactions), txs_validators, {}, rewards_stats);
to_state_api_transactions(new_blk.transactions), rewards_stats);

TransactionReceipts receipts;
receipts.reserve(exec_results.size());
Expand Down
43 changes: 18 additions & 25 deletions libraries/core_libs/consensus/src/final_chain/rewards_stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@

namespace taraxa {

RewardsStats::RewardsStats(const addr_t& author) : block_author_(author) {}

bool RewardsStats::addTransaction(const trx_hash_t& tx_hash, const addr_t& validator) {
auto found_tx = txs_validators_.find(tx_hash);
auto found_tx = validator_by_tx_hash_.find(tx_hash);

// Already processed tx
if (found_tx != txs_validators_.end()) {
if (found_tx != validator_by_tx_hash_.end()) {
return false;
}

// New tx
txs_validators_[tx_hash] = validator;
validator_by_tx_hash_[tx_hash] = validator;

return true;
}

std::optional<addr_t> RewardsStats::getTransactionValidator(const trx_hash_t& tx_hash) {
auto found_tx = txs_validators_.find(tx_hash);
if (found_tx == txs_validators_.end()) {
auto found_tx = validator_by_tx_hash_.find(tx_hash);
if (found_tx == validator_by_tx_hash_.end()) {
return {};
}

Expand Down Expand Up @@ -52,12 +54,12 @@ std::set<trx_hash_t> toTrxHashesSet(const SharedTransactions& transactions) {
return block_transactions_hashes_;
}

void RewardsStats::initStats(const PeriodData& sync_blk, uint64_t dpos_vote_count, uint32_t committee_size) {
txs_validators_.reserve(sync_blk.transactions.size());
validators_stats_.reserve(std::max(sync_blk.dag_blocks.size(), sync_blk.previous_block_cert_votes.size()));
auto block_transactions_hashes_ = toTrxHashesSet(sync_blk.transactions);
void RewardsStats::processStats(const PeriodData& block, uint64_t dpos_vote_count, uint32_t committee_size) {
validator_by_tx_hash_.reserve(block.transactions.size());
validators_stats_.reserve(std::max(block.dag_blocks.size(), block.previous_block_cert_votes.size()));
auto block_transactions_hashes_ = toTrxHashesSet(block.transactions);

for (const auto& dag_block : sync_blk.dag_blocks) {
for (const auto& dag_block : block.dag_blocks) {
const addr_t& dag_block_author = dag_block.getSender();
bool has_unique_transactions = false;
for (const auto& tx_hash : dag_block.getTrxs()) {
Expand All @@ -78,34 +80,25 @@ void RewardsStats::initStats(const PeriodData& sync_blk, uint64_t dpos_vote_coun
}
}
// total_unique_txs_count_ should be always equal to transactions count in block
assert(txs_validators_.size() == sync_blk.transactions.size());
assert(validator_by_tx_hash_.size() == block.transactions.size());

max_votes_weight_ = std::min<uint64_t>(committee_size, dpos_vote_count);
for (const auto& vote : sync_blk.previous_block_cert_votes) {
for (const auto& vote : block.previous_block_cert_votes) {
addVote(vote);
}
}

std::vector<addr_t> RewardsStats::processStats(const PeriodData& block, uint64_t dpos_vote_count,
uint32_t committee_size) {
initStats(block, dpos_vote_count, committee_size);

// Dag blocks validators that included transactions to be executed as first in their blocks
std::vector<addr_t> txs_validators;
txs_validators.reserve(block.transactions.size());

txs_validators_.reserve(block.transactions.size());
for (const auto& tx : block.transactions) {
// Non-executed trxs
auto tx_validator = getTransactionValidator(tx->getHash());
assert(tx_validator.has_value());

txs_validators.push_back(*tx_validator);
txs_validators_.push_back(*tx_validator);
}

return txs_validators;
}

RLP_FIELDS_DEFINE(RewardsStats::ValidatorStats, dag_blocks_count_, vote_weight_)
RLP_FIELDS_DEFINE(RewardsStats, validators_stats_, total_dag_blocks_count_, total_votes_weight_, max_votes_weight_)
RLP_FIELDS_DEFINE(RewardsStats, block_author_, validators_stats_, txs_validators_, total_dag_blocks_count_,
total_votes_weight_, max_votes_weight_)

} // namespace taraxa
7 changes: 2 additions & 5 deletions libraries/core_libs/consensus/src/final_chain/state_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,11 @@ StateDescriptor StateAPI::get_last_committed_state_descriptor() const {

const StateTransitionResult& StateAPI::transition_state(const EVMBlock& block,
const util::RangeView<EVMTransaction>& transactions,
const util::RangeView<addr_t>& transactions_validators,
const util::RangeView<UncleBlock>& uncles,
const RewardsStats& rewards_stats) {
const std::vector<RewardsStats>& rewards_stats) {
result_buf_transition_state_.execution_results.clear();
rlp_enc_transition_state_.clear();
c_method_args_rlp<StateTransitionResult, from_rlp, taraxa_evm_state_api_transition_state>(
this_c_, rlp_enc_transition_state_, result_buf_transition_state_, block, transactions, transactions_validators,
uncles, rewards_stats);
this_c_, rlp_enc_transition_state_, result_buf_transition_state_, block, transactions, rewards_stats);
return result_buf_transition_state_;
}

Expand Down
23 changes: 12 additions & 11 deletions libraries/types/pbft_block/include/pbft/pbft_block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace taraxa {
*/

/**
* @brief The PbftBlockk class is a PBFT block class that includes PBFT block hash, previous PBFT block hash, DAG anchor
* @brief The PbftBlock class is a PBFT block class that includes PBFT block hash, previous PBFT block hash, DAG anchor
* hash, DAG blocks ordering hash, period number, timestamp, proposer address, and proposer signature.
*/
class PbftBlock {
Expand All @@ -35,8 +35,8 @@ class PbftBlock {
PbftBlock(const blk_hash_t& prev_blk_hash, const blk_hash_t& dag_blk_hash_as_pivot, const blk_hash_t& order_hash,
const blk_hash_t& prev_state_root, PbftPeriod period, const addr_t& beneficiary, const secret_t& sk,
std::vector<vote_hash_t>&& reward_votes);
explicit PbftBlock(dev::RLP const& rlp);
explicit PbftBlock(bytes const& RLP);
explicit PbftBlock(const dev::RLP& rlp);
explicit PbftBlock(const bytes& RLP);

/**
* @brief Secure Hash Algorithm 3
Expand Down Expand Up @@ -77,33 +77,33 @@ class PbftBlock {
* @param dag_blks DAG blocks hashes
* @return PBFT block with DAG blocks in JSON
*/
static Json::Value toJson(PbftBlock const& b, std::vector<blk_hash_t> const& dag_blks);
static Json::Value toJson(const PbftBlock& b, const std::vector<blk_hash_t>& dag_blks);

/**
* @brief Get PBFT block hash
* @return PBFT block hash
*/
auto const& getBlockHash() const { return block_hash_; }
const auto& getBlockHash() const { return block_hash_; }

/**
* @brief Get previous PBFT block hash
* @return previous PBFT block hash
*/
auto const& getPrevBlockHash() const { return prev_block_hash_; }
const auto& getPrevBlockHash() const { return prev_block_hash_; }

/**
* @brief Get DAG anchor hash for the finalized PBFT block
* @return DAG anchor hash
*/
auto const& getPivotDagBlockHash() const { return dag_block_hash_as_pivot_; }
const auto& getPivotDagBlockHash() const { return dag_block_hash_as_pivot_; }

/**
* @brief Get DAG blocks ordering hash
* @return DAG blocks ordering hash
*/
auto const& getOrderHash() const { return order_hash_; }
const auto& getOrderHash() const { return order_hash_; }

auto const& getPrevStateRoot() const { return prev_state_root_hash_; }
const auto& getPrevStateRoot() const { return prev_state_root_hash_; }

/**
* @brief Get period number
Expand All @@ -121,7 +121,8 @@ class PbftBlock {
* @brief Get PBFT block proposer address
* @return PBFT block proposer address
*/
auto const& getBeneficiary() const { return beneficiary_; }
const auto& getBeneficiary() const { return beneficiary_; }

const auto& getRewardVotes() const { return reward_votes_; }

private:
Expand All @@ -136,7 +137,7 @@ class PbftBlock {
*/
void checkUniqueRewardVotes();
};
std::ostream& operator<<(std::ostream& strm, PbftBlock const& pbft_blk);
std::ostream& operator<<(std::ostream& strm, const PbftBlock& pbft_blk);

/** @}*/

Expand Down
31 changes: 28 additions & 3 deletions tests/final_chain_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,22 @@ struct FinalChainTest : WithDataDir {
for (const auto& trx : trxs) {
trx_hashes.emplace_back(trx->getHash());
}
DagBlock dag_blk({}, {}, {}, trx_hashes, {}, {}, secret_t::random());

auto proposer_keys = dev::KeyPair::create();
DagBlock dag_blk({}, {}, {}, trx_hashes, {}, {}, proposer_keys.secret());
db->saveDagBlock(dag_blk);
std::vector<vote_hash_t> reward_votes_hashes;
auto pbft_block =
std::make_shared<PbftBlock>(kNullBlockHash, kNullBlockHash, kNullBlockHash, kNullBlockHash, expected_blk_num,
addr_t::random(), dev::KeyPair::create().secret(), std::move(reward_votes_hashes));
addr_t::random(), proposer_keys.secret(), std::move(reward_votes_hashes));

std::vector<std::shared_ptr<Vote>> votes;
PeriodData period_data(pbft_block, votes);
period_data.dag_blocks.push_back(dag_blk);
period_data.transactions = trxs;

auto batch = db->createWriteBatch();
db->savePeriodData(period_data, batch);

db->commitWriteBatch(batch);

auto result = SUT->finalize(std::move(period_data), {dag_blk.getHash()}).get();
Expand Down Expand Up @@ -447,6 +449,9 @@ TEST_F(FinalChainTest, failed_transaction_fee) {
auto trx2_1 = std::make_shared<Transaction>(2, 101, 1, gas, dev::bytes(), sk, receiver);

advance({trx1});
auto blk = SUT->block_header(expected_blk_num);
auto proposer_balance = SUT->getBalance(blk->author);
EXPECT_EQ(proposer_balance.first, 21000);
advance({trx2});
advance({trx3});

Expand Down Expand Up @@ -600,6 +605,26 @@ TEST_F(FinalChainTest, incorrect_estimation_regress) {
}
}

TEST_F(FinalChainTest, fee_rewards_distribution) {
auto sender_keys = dev::KeyPair::create();
auto gas = 30000;

const auto& receiver = dev::KeyPair::create().address();
const auto& addr = sender_keys.address();
const auto& sk = sender_keys.secret();
cfg.genesis.state.initial_balances = {};
cfg.genesis.state.initial_balances[addr] = 100000;
init();
const auto gas_price = 1;
auto trx1 = std::make_shared<Transaction>(1, 100, gas_price, gas, dev::bytes(), sk, receiver);

auto res = advance({trx1});
auto gas_used = res->trx_receipts.front().gas_used;
auto blk = SUT->block_header(expected_blk_num);
auto proposer_balance = SUT->getBalance(blk->author);
EXPECT_EQ(proposer_balance.first, gas_used * gas_price);
}

// This test should be last as state_api isn't destructed correctly because of exception
TEST_F(FinalChainTest, initial_validator_exceed_maximum_stake) {
const dev::KeyPair key = dev::KeyPair::create();
Expand Down
Loading

0 comments on commit 4ffe863

Please sign in to comment.