mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Optimization: reuse reward vector
Profiling shows noticeable CPU spend in allocating memory for this vector (which makes sense, since we are looping through ~1700 nodes and building a reward vector for each one). Avoid it by reusing a single vector that gets cleared (but not reallocated more than a handful of times). This reduces batching CPU time in a debug build by about 12%; curiously I didn't find a noticeable reduction in a release build.
This commit is contained in:
parent
230b6bdc0d
commit
b5a5d01b04
|
@ -315,8 +315,7 @@ namespace cryptonote {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<cryptonote::batch_sn_payment> BlockchainSQLite::calculate_rewards(hf hf_version, uint64_t distribution_amount, service_nodes::service_node_info sn_info) {
|
||||
|
||||
void BlockchainSQLite::calculate_rewards(hf hf_version, uint64_t distribution_amount, const service_nodes::service_node_info& sn_info, std::vector<cryptonote::batch_sn_payment>& payments) {
|
||||
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
|
||||
|
||||
// Find out how much is due for the operator: fee_portions/PORTIONS * reward
|
||||
|
@ -325,7 +324,7 @@ namespace cryptonote {
|
|||
|
||||
assert(operator_fee <= distribution_amount);
|
||||
|
||||
std::vector<cryptonote::batch_sn_payment> payments;
|
||||
payments.clear();
|
||||
// Pay the operator fee to the operator
|
||||
if (operator_fee > 0)
|
||||
payments.emplace_back(sn_info.operator_address, operator_fee);
|
||||
|
@ -343,8 +342,6 @@ namespace cryptonote {
|
|||
if (c_reward > 0)
|
||||
payments.emplace_back(contributor.address, c_reward);
|
||||
}
|
||||
|
||||
return payments;
|
||||
}
|
||||
|
||||
// Calculates block rewards, then invokes either `add_sn_rewards` (if `add`) or
|
||||
|
@ -367,6 +364,8 @@ namespace cryptonote {
|
|||
uint64_t block_reward = block.reward * BATCH_REWARD_FACTOR;
|
||||
uint64_t service_node_reward = cryptonote::service_node_reward_formula(0, block.major_version) * BATCH_REWARD_FACTOR;
|
||||
|
||||
std::vector<cryptonote::batch_sn_payment> payments;
|
||||
|
||||
// Step 1: Pay out the block producer their tx fees (note that, unlike the below, this applies
|
||||
// even if the SN isn't currently payable).
|
||||
if (block_reward < service_node_reward && m_nettype != cryptonote::network_type::FAKECHAIN)
|
||||
|
@ -382,9 +381,9 @@ namespace cryptonote {
|
|||
|
||||
if (auto service_node_winner = service_nodes_state.service_nodes_infos.find(block.service_node_winner_key);
|
||||
service_node_winner != service_nodes_state.service_nodes_infos.end()) {
|
||||
auto tx_fee_payments = calculate_rewards(block.major_version, tx_fees, *service_node_winner->second);
|
||||
calculate_rewards(block.major_version, tx_fees, *service_node_winner->second, payments);
|
||||
// Takes the block producer and adds its contributors to the batching database for the transaction fees
|
||||
if (!(this->*add_or_subtract)(tx_fee_payments))
|
||||
if (!(this->*add_or_subtract)(payments))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -398,23 +397,23 @@ namespace cryptonote {
|
|||
auto payable_service_node = service_nodes_state.service_nodes_infos.find(node_pubkey);
|
||||
if (payable_service_node == service_nodes_state.service_nodes_infos.end())
|
||||
continue;
|
||||
auto snode_rewards = calculate_rewards(block.major_version, service_node_reward / total_service_nodes_payable, * payable_service_node -> second);
|
||||
calculate_rewards(block.major_version, service_node_reward / total_service_nodes_payable, * payable_service_node -> second, payments);
|
||||
// Takes the node and adds its contributors to the batching database
|
||||
if (!(this->*add_or_subtract)(snode_rewards))
|
||||
if (!(this->*add_or_subtract)(payments))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: Add Governance reward to the list
|
||||
if (m_nettype != cryptonote::network_type::FAKECHAIN) {
|
||||
std::vector<cryptonote::batch_sn_payment> governance_rewards;
|
||||
if (parsed_governance_addr.first != block.major_version) {
|
||||
cryptonote::get_account_address_from_str(parsed_governance_addr.second, m_nettype,
|
||||
cryptonote::get_config(m_nettype).governance_wallet_address(block.major_version));
|
||||
parsed_governance_addr.first = block.major_version;
|
||||
}
|
||||
uint64_t foundation_reward = cryptonote::governance_reward_formula(block.major_version) * BATCH_REWARD_FACTOR;
|
||||
governance_rewards.emplace_back(parsed_governance_addr.second.address, foundation_reward);
|
||||
if (!(this->*add_or_subtract)(governance_rewards))
|
||||
payments.clear();
|
||||
payments.emplace_back(parsed_governance_addr.second.address, foundation_reward);
|
||||
if (!(this->*add_or_subtract)(payments))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,11 +89,12 @@ public:
|
|||
|
||||
// calculate_rewards -> takes the list of contributors from sn_info with their SN contribution
|
||||
// amounts and will calculate how much of the block rewards should be the allocated to the
|
||||
// contributors. The function will return a list suitable for passing to add_sn_payments
|
||||
// contributors. The function will set a list suitable for passing to add_sn_payments into the
|
||||
// vector (any existing values will be cleared).
|
||||
//
|
||||
// Note that distribution_amount here is typically passed as milli-atomic OXEN for extra
|
||||
// precision.
|
||||
std::vector<cryptonote::batch_sn_payment> calculate_rewards(hf hf_version, uint64_t distribution_amount, service_nodes::service_node_info sn_info);
|
||||
void calculate_rewards(hf hf_version, uint64_t distribution_amount, const service_nodes::service_node_info& sn_info, std::vector<cryptonote::batch_sn_payment>& rewards);
|
||||
|
||||
// add/pop_block -> takes a block that contains new block rewards to be batched and added to the database
|
||||
// and/or batching payments that need to be subtracted from the database, in addition it takes a reference to
|
||||
|
|
|
@ -103,7 +103,8 @@ TEST(SQLITE, CalculateRewards)
|
|||
cryptonote::get_account_address_from_str(first_address, cryptonote::network_type::TESTNET, "T6TzkJb5EiASaCkcH7idBEi1HSrpSQJE1Zq3aL65ojBMPZvqHNYPTL56i3dncGVNEYCG5QG5zrBmRiVwcg6b1cRM1SRNqbp44");
|
||||
single_contributor.contributors.emplace_back(0, first_address.address);
|
||||
single_contributor.contributors.back().amount = block.reward;
|
||||
auto rewards = sqliteDB.calculate_rewards(block.major_version, block.reward, single_contributor);
|
||||
std::vector<cryptonote::batch_sn_payment> rewards;
|
||||
sqliteDB.calculate_rewards(block.major_version, block.reward, single_contributor, rewards);
|
||||
auto hf_version = block.major_version;
|
||||
|
||||
// Check that 3 contributor receives their portion of the block reward
|
||||
|
@ -118,25 +119,25 @@ TEST(SQLITE, CalculateRewards)
|
|||
cryptonote::get_account_address_from_str(third_address, cryptonote::network_type::TESTNET, "T6SkkovCyLWViVDMgeJoF7X4vFrHnKX5jXyktaoGmRuNTdoFEx1xXu1joXdmeH9mx2LLNPq998fKKcsAHwdRJWhk126SapptR");
|
||||
multiple_contributors.contributors.emplace_back(0, third_address.address);
|
||||
multiple_contributors.contributors.back().amount = 34;
|
||||
auto multiple_rewards = sqliteDB.calculate_rewards(block.major_version, block.reward, multiple_contributors);
|
||||
sqliteDB.calculate_rewards(block.major_version, block.reward, multiple_contributors, rewards);
|
||||
|
||||
EXPECT_EQ(multiple_rewards[0].amount, 66);
|
||||
EXPECT_EQ(multiple_rewards[1].amount, 66);
|
||||
EXPECT_EQ(multiple_rewards[2].amount, 68);
|
||||
EXPECT_EQ(rewards[0].amount, 66);
|
||||
EXPECT_EQ(rewards[1].amount, 66);
|
||||
EXPECT_EQ(rewards[2].amount, 68);
|
||||
|
||||
// Check that 3 contributors receives their portion of the block reward when the operator takes a 10% fee
|
||||
multiple_contributors.portions_for_operator = cryptonote::old::STAKING_PORTIONS/10;
|
||||
multiple_contributors.operator_address = first_address.address;
|
||||
block.reward = 1000;
|
||||
auto multiple_rewards_with_fee = sqliteDB.calculate_rewards(block.major_version, block.reward, multiple_contributors);
|
||||
sqliteDB.calculate_rewards(block.major_version, block.reward, multiple_contributors, rewards);
|
||||
// Operator gets 10%
|
||||
EXPECT_EQ(multiple_rewards_with_fee[0].amount, 99);
|
||||
EXPECT_EQ(tools::view_guts(multiple_rewards_with_fee[0].address_info.address), tools::view_guts(first_address.address));
|
||||
EXPECT_EQ(rewards[0].amount, 99);
|
||||
EXPECT_EQ(tools::view_guts(rewards[0].address_info.address), tools::view_guts(first_address.address));
|
||||
// Contributors (including operator) receive the balance
|
||||
EXPECT_EQ(multiple_rewards_with_fee[1].amount, 297);
|
||||
EXPECT_EQ(tools::view_guts(multiple_rewards_with_fee[1].address_info.address), tools::view_guts(first_address.address));
|
||||
EXPECT_EQ(multiple_rewards_with_fee[2].amount, 297);
|
||||
EXPECT_EQ(tools::view_guts(multiple_rewards_with_fee[2].address_info.address), tools::view_guts(second_address.address));
|
||||
EXPECT_EQ(multiple_rewards_with_fee[3].amount, 306);
|
||||
EXPECT_EQ(tools::view_guts(multiple_rewards_with_fee[3].address_info.address), tools::view_guts(third_address.address));
|
||||
EXPECT_EQ(rewards[1].amount, 297);
|
||||
EXPECT_EQ(tools::view_guts(rewards[1].address_info.address), tools::view_guts(first_address.address));
|
||||
EXPECT_EQ(rewards[2].amount, 297);
|
||||
EXPECT_EQ(tools::view_guts(rewards[2].address_info.address), tools::view_guts(second_address.address));
|
||||
EXPECT_EQ(rewards[3].amount, 306);
|
||||
EXPECT_EQ(tools::view_guts(rewards[3].address_info.address), tools::view_guts(third_address.address));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue