Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
dafdd4b
Adjust BP Pay Curve based on TSDP
aamirpashaa May 28, 2024
06c1410
Remove REX/sTLOS payouts auto adjustment based on TLOS price
aamirpashaa May 28, 2024
6be7ee8
Apply tiered BP pay scale
aamirpashaa Mar 5, 2025
63ca6ae
Drop deprecated action in CI and update cdt container
Mar 5, 2025
cb03872
Increase supported leap version for tests
Mar 5, 2025
e908c14
Disable trace debugging function thats giving linking issues in tests…
Mar 5, 2025
89dd088
Adapt last steps of CI to match new artifact actions APIs
Mar 5, 2025
0ef0284
Simplify CI
Mar 5, 2025
624f2fe
Vote decay implementation
poplexity Apr 7, 2025
314a208
Correcting rank variable in calculations
aamirpashaa Apr 20, 2025
0688cf2
Merge pull request #52 from telosnetwork/tiered_bp_pay
poplexity Apr 24, 2025
37d90d8
Add ability to get and store EVM votes
aamirpashaa May 1, 2025
0ebcbfa
Add action for updating BP status on EVM
aamirpashaa May 1, 2025
2730a7c
Remove an additional check, when the BP vote becomes zero in EVM
aamirpashaa May 1, 2025
fd2a0fa
Relax some of the checks
aamirpashaa May 1, 2025
5661e61
Add self-stake boost support
aamirpashaa May 5, 2025
4ee8830
Merge pull request #56 from telosnetwork/self_stake_boost
poplexity May 5, 2025
c686c8c
Merge pull request #55 from telosnetwork/evm_voting
poplexity May 5, 2025
0798af0
Better decay math and syncing decay values into EVM when they are set…
poplexity May 27, 2025
58b5f97
Using proper precision for passing the decay_increase_yearly into the…
poplexity Jun 5, 2025
6a6d4d8
Refactor self_stake_boost to use uint32_t type and adjust related log…
aamirpashaa Aug 9, 2025
f0854b0
Update self_stake_boost to use uint64_t and add self_stake_boost_mult…
aamirpashaa Aug 14, 2025
cabf1d6
Enhance producer pay calculation by implementing a detailed multiplie…
aamirpashaa Sep 12, 2025
7d917ba
Update comments
aamirpashaa Sep 12, 2025
ac5e0c0
Add checks to ensure EVM voting contract is set before executing rela…
aamirpashaa Sep 12, 2025
d6ce6e1
Merge branch 'tsdp_changes' into voting_changes
aamirpashaa Sep 12, 2025
4a1c95e
Update MAX_PRODUCERS to 35 in producer_pay.cpp, system_rotation.cpp, …
aamirpashaa Sep 21, 2025
0d47d86
Refactor producer pay calculation to use double division for improved…
aamirpashaa Nov 18, 2025
cb8bc83
Update GitHub Actions to use latest versions of checkout and upload/d…
aamirpashaa Nov 18, 2025
4ae2291
Merge branch 'fix_ci' into voting_changes
aamirpashaa Nov 18, 2025
b350fff
Change builder image to cdt 4.0.1
aamirpashaa Nov 29, 2025
62be13c
Refactor producer payment calculations in system tests to use dynamic…
aamirpashaa Nov 30, 2025
0172b78
Merge branch 'fix_ci_cdt4.0.1' into voting_changes
aamirpashaa Dec 1, 2025
1a5d156
Merge branch 'reduce_standby_bps' into voting_changes
aamirpashaa Dec 1, 2025
8a843bb
Update producer payment calculations in system tests to reflect new p…
aamirpashaa Dec 1, 2025
b00953b
Refactor producer payment calculations to use double precision for sh…
aamirpashaa Dec 4, 2025
68f1d1b
Enhance multi-producer payment tests by collecting and comparing actu…
aamirpashaa Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion contracts/eosio.system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ target_include_directories(eosio.system PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inclu
${CMAKE_CURRENT_SOURCE_DIR}/../eosio.token/include
#// TELOS BEGIN
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/eosio.tedp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/delphioracle/include)
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/delphioracle/include
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/eosio.evm/include
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/intx/include
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/rlp/include)
#// TELOS END

set_target_properties(eosio.system PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
Expand Down
96 changes: 94 additions & 2 deletions contracts/eosio.system/include/eosio.system/eosio.system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ namespace eosiosystem {
uint32_t reserved2 = 0;
eosio::asset reserved3;

// TELOS BEGIN
eosio::binary_extension<bool> self_stake_boost = false;
// TELOS END

uint64_t primary_key()const { return owner.value; }

enum class flags1_fields : uint32_t {
Expand All @@ -462,13 +466,79 @@ namespace eosiosystem {
cpu_managed = 4
};

// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE( voter_info, (owner)(proxy)(producers)(staked)(last_stake)(last_vote_weight)(proxied_vote_weight)(is_proxy)(flags1)(reserved2)(reserved3) )
// TELOS BEGIN
template<typename DataStream>
friend DataStream& operator << ( DataStream& ds, const voter_info& v ) {
ds << v.owner
<< v.proxy
<< v.producers
<< v.staked
<< v.last_stake
<< v.last_vote_weight
<< v.proxied_vote_weight
<< v.is_proxy
<< v.flags1
<< v.reserved2
<< v.reserved3;

if( !v.self_stake_boost.has_value() ) return ds;

return ds << v.self_stake_boost;
}

template<typename DataStream>
friend DataStream& operator >> ( DataStream& ds, voter_info& v ) {
return ds >> v.owner
>> v.proxy
>> v.producers
>> v.staked
>> v.last_stake
>> v.last_vote_weight
>> v.proxied_vote_weight
>> v.is_proxy
>> v.flags1
>> v.reserved2
>> v.reserved3
>> v.self_stake_boost;
}
// TELOS END
};


typedef eosio::multi_index< "voters"_n, voter_info > voters_table;

// TELOS BEGIN
// EVM Vote info. EVM Vote info stores information about the EVM vote:
// - `bp` the bp name
// - `total_vote` the total vote of the bp
struct [[eosio::table, eosio::contract("eosio.system")]] evm_vote_info {
eosio::name bp; /// bp name
eosio::checksum256 total_vote; /// the total vote of the bp

uint64_t primary_key()const { return bp.value; }

// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE( evm_vote_info, (bp)(total_vote) )
};
// TELOS END

// TELOS BEGIN
typedef eosio::multi_index< "evmvotes"_n, evm_vote_info,
indexed_by<"byname"_n, const_mem_fun<evm_vote_info, uint64_t, &evm_vote_info::primary_key> >
> evm_votes_table;
// TELOS END

// TELOS BEGIN
struct[[ eosio::table("votingconfig"), eosio::contract("eosio.system") ]] votingconfig {
eosio::checksum160 evm_voting_contract;
double decay;
EOSLIB_SERIALIZE(votingconfig, (evm_voting_contract)(decay))
};
// TELOS END

// TELOS BEGIN
typedef eosio::singleton< "votingconfig"_n, votingconfig > votingconfig_singleton;
// TELOS END

typedef eosio::multi_index< "producers"_n, producer_info,
indexed_by<"prototalvote"_n, const_mem_fun<producer_info, double, &producer_info::by_votes> >
Expand Down Expand Up @@ -853,6 +923,9 @@ namespace eosiosystem {
payrate_singleton _payrate;
payrates _gpayrate;
payments_table _payments;
evm_votes_table _evm_votes;
votingconfig_singleton _voting_config;
votingconfig _gvoting_config;
// TELOS END

public:
Expand All @@ -878,6 +951,7 @@ namespace eosiosystem {
static constexpr eosio::name works_account{"works.decide"_n};
static constexpr eosio::name amend_account{"amend.decide"_n};
static constexpr eosio::name delphi_oracle_account{"delphioracle"_n};
static constexpr eosio::name evm_account{"eosio.evm"_n};
// TELOS END

system_contract( name s, name code, datastream<const char*> ds );
Expand Down Expand Up @@ -1621,11 +1695,27 @@ namespace eosiosystem {
[[eosio::action]]
void pay();

[[eosio::action]]
void setvotedecay( double decay );

[[eosio::action]]
void setvotecontr( eosio::checksum160 contract );

[[eosio::action]]
void getevmvote( std::vector<eosio::name> bps );

[[eosio::action]]
void setbpevmstat( eosio::name bp );

using unregreason_action = eosio::action_wrapper<"unregreason"_n, &system_contract::unregreason>;
using votebpout_action = eosio::action_wrapper<"votebpout"_n, &system_contract::votebpout>;
using setpayrates_action = eosio::action_wrapper<"setpayrates"_n, &system_contract::setpayrates>;
using distviarex_action = eosio::action_wrapper<"distviarex"_n, &system_contract::distviarex>;
using pay_action = eosio::action_wrapper<"pay"_n, &system_contract::pay>;
using setvotedecay_action = eosio::action_wrapper<"setvotedecay"_n, &system_contract::setvotedecay>;
using setvotecontr_action = eosio::action_wrapper<"setvotecontr"_n, &system_contract::setvotecontr>;
using getevmvote_action = eosio::action_wrapper<"getevmvote"_n, &system_contract::getevmvote>;
using setbpevmstat_action = eosio::action_wrapper<"setbpevmstat"_n, &system_contract::setbpevmstat>;
// TELOS END

private:
Expand Down Expand Up @@ -1744,6 +1834,8 @@ namespace eosiosystem {
uint64_t get_telos_average_price();

double inverse_vote_weight(double staked, double amountVotedProducers);
double decay_vote_weight_multiplier(double weighted_vote);
double apply_decay_multiplier(double weighted_vote, uint32_t sec_since_epoch, uint64_t decay_start_epoch, uint64_t decay_increase_yearly);
void recalculate_votes();

//defined in system_kick.cpp
Expand Down
201 changes: 200 additions & 1 deletion contracts/eosio.system/src/eosio.system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
#include <eosio/crypto.hpp>
#include <eosio/dispatcher.hpp>

// TELOS BEGIN
#include <eosio.evm/tables.hpp>
#include <eosio/crypto_ext.hpp>
#include <eosio.evm/util.hpp>
#include <intx/intx.hpp>
#include <intx/base.hpp>
#include <rlp/rlp.hpp>
// TELOS END
#include <cmath>

namespace eosiosystem {
Expand Down Expand Up @@ -35,7 +43,9 @@ namespace eosiosystem {
_schedule_metrics(_self, _self.value),
_rotation(_self, _self.value),
_payrate(_self, _self.value),
_payments(_self, _self.value)
_payments(_self, _self.value),
_evm_votes(_self, _self.value),
_voting_config(_self, _self.value)
// TELOS END
{
_gstate = _global.exists() ? _global.get() : get_default_parameters();
Expand All @@ -46,6 +56,7 @@ namespace eosiosystem {
_gschedule_metrics = _schedule_metrics.get_or_create(_self, schedule_metrics_state{ name(0), 0, std::vector<producer_metric>() });
_grotation = _rotation.get_or_create(_self, rotation_state{ name(0), name(0), 21, 75, block_timestamp(), block_timestamp() });
_gpayrate = _payrate.get_or_create(_self, payrates{ max_bpay_rate, max_worker_monthly_amount });
_gvoting_config = _voting_config.get_or_create(_self, votingconfig{ eosio::checksum160(), 1.0 });
// TELOS END
}

Expand Down Expand Up @@ -77,6 +88,7 @@ namespace eosiosystem {
_schedule_metrics.set(_gschedule_metrics, _self);
_rotation.set(_grotation, _self);
_payrate.set(_gpayrate, _self);
_voting_config.set(_gvoting_config, _self);
// TELOS END
}

Expand Down Expand Up @@ -551,5 +563,192 @@ namespace eosiosystem {
void system_contract::distviarex(name from, asset amount) {
system_contract::channel_to_rex(from, amount);
}

void system_contract::setvotedecay( double decay ) {
require_auth(_self);
_gvoting_config.decay = decay;
}

void system_contract::setvotecontr( eosio::checksum160 contract ) {
require_auth(_self);
_gvoting_config.evm_voting_contract = contract;
}

void system_contract::getevmvote( std::vector<eosio::name> bps ) {

check( bps.size() <= 30, "attempt to uodate EVM vote for too many BPs" );
for( size_t i = 1; i < bps.size(); ++i ) {
check( bps[i-1] < bps[i], "list of BPs that need to be updated must be unique and sorted" );
}

// Get the EVM voting contract

eosio_evm::account_table account(evm_account, evm_account.value);
auto accounts_byaddress = account.get_index<eosio::name("byaddress")>();
std::array<uint8_t, 20> evm_voting_contract_address = _gvoting_config.evm_voting_contract.extract_as_byte_array();
std::array<uint8_t, 32> evm_voting_contract_address_256{};
std::copy(evm_voting_contract_address.begin(), evm_voting_contract_address.end(), evm_voting_contract_address_256.begin() + 12);
auto evm_voting_account = accounts_byaddress.find(eosio::checksum256(evm_voting_contract_address_256));
eosio::check(evm_voting_account != accounts_byaddress.end(),"EVM voting contract not found");

// Get the access to the state
eosio_evm::account_state_table accounts_states(evm_account, evm_voting_account->primary_key());
auto accounts_states_bykey = accounts_states.get_index<eosio::name("bykey")>();

// Add a flag to make sure at least a single vote is changed
bool is_changed = false;

for (eosio::name bp : bps) {

// Access the vote of the BP in the EVM voting contract internal state
std::array<uint8_t, 64> vote_memory_location = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3};
std::array<uint8_t, 8> bp_name_bytes{};
for (size_t i = 0; i < 8; ++i) {
bp_name_bytes[7 - i] = static_cast<uint8_t>(bp.value >> (i * 8));
}
std::copy(std::begin(bp_name_bytes), std::end(bp_name_bytes), vote_memory_location.begin() + 24);
eosio::checksum256 vote_memory_location_key = eosio::keccak((char*)vote_memory_location.data(), 64);

// Get the total votes of the BP
auto total_votes_of_bp = accounts_states_bykey.find(vote_memory_location_key);

// Search for the BP in the `evmvotes` table
auto evmvotes_byname = _evm_votes.get_index<eosio::name("byname")>();
auto evm_vote = evmvotes_byname.find(bp.value);
const uint256_t ten_power_14 = intx::from_string<uint256_t>("0x5af3107a4000");

if (evm_vote == evmvotes_byname.end()) {
// First time EVM vote

is_changed = true;

// Apply the EVM votes of the BP
auto pitr = _producers.find( bp.value );
eosio::check( pitr != _producers.end(), "BP not found" );
_producers.modify( pitr, same_payer, [&]( auto& p ) {
uint256_t current_vote = eosio_evm::checksum256ToValue(total_votes_of_bp->value);
uint256_t current_vote_normalized = current_vote / ten_power_14; // Divide be 1e14
uint64_t current_vote_normalized_u64 = current_vote_normalized.lo.lo;
p.total_votes += double(current_vote_normalized_u64);
_gstate.total_producer_vote_weight += double(current_vote_normalized_u64);
});

// Add a new row to store the new BP vote data
_evm_votes.emplace(_self, [&](auto &a) {
a.bp = bp;
a.total_vote = total_votes_of_bp->value;
});
} else {
// Old EVM vote updated

// Check whether the list of voted BPs or the vote weight has changed
if (!is_changed) {
is_changed = evm_vote->total_vote != total_votes_of_bp->value;
}

// Apply the EVM votes of the BP
auto pitr = _producers.find( bp.value );
eosio::check( pitr != _producers.end(), "BP not found" );
_producers.modify( pitr, same_payer, [&]( auto& p ) {
uint256_t previous_vote = eosio_evm::checksum256ToValue(evm_vote->total_vote);
uint256_t previous_vote_normalized = previous_vote / ten_power_14; // Divide be 1e14
uint64_t previous_vote_normalized_u64 = previous_vote_normalized.lo.lo;
uint256_t current_vote = eosio_evm::checksum256ToValue(total_votes_of_bp->value);
uint256_t current_vote_normalized = current_vote / ten_power_14; // Divide be 1e14
uint64_t current_vote_normalized_u64 = current_vote_normalized.lo.lo;
p.total_votes += double(current_vote_normalized_u64 - previous_vote_normalized_u64);
if ( p.total_votes < 0 ) {
p.total_votes = 0;
}
_gstate.total_producer_vote_weight += double(current_vote_normalized_u64 - previous_vote_normalized_u64);
});

// Apply the updated vote to the existing row
evmvotes_byname.modify(evm_vote, same_payer, [&](auto& a) {
a.total_vote = total_votes_of_bp->value;
});
}

}

eosio::check(is_changed, "None of the BPs EVM votes has been changed");
}
void system_contract::setbpevmstat( eosio::name bp ) {
auto pitr = _producers.find( bp.value );
eosio::check(pitr != _producers.end(), "BP not found");

// Get the EVM voting contract
eosio_evm::account_table account(evm_account, evm_account.value);
auto accounts_byaddress = account.get_index<eosio::name("byaddress")>();
std::array<uint8_t, 20> evm_voting_contract_address = _gvoting_config.evm_voting_contract.extract_as_byte_array();
std::array<uint8_t, 32> evm_voting_contract_address_256{};
std::copy(evm_voting_contract_address.begin(), evm_voting_contract_address.end(), evm_voting_contract_address_256.begin() + 12);
auto evm_voting_account = accounts_byaddress.find(eosio::checksum256(evm_voting_contract_address_256));
eosio::check(evm_voting_account != accounts_byaddress.end(),"EVM voting contract not found");

// Get the access to the state
eosio_evm::account_state_table accounts_states(evm_account, evm_voting_account->primary_key());
auto accounts_states_bykey = accounts_states.get_index<eosio::name("bykey")>();

// Access the status of the BP in the EVM voting contract internal state
std::array<uint8_t, 64> bp_status_location = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4};
std::array<uint8_t, 8> bp_name_bytes{};
for (size_t i = 0; i < 8; ++i) {
bp_name_bytes[7 - i] = static_cast<uint8_t>(bp.value >> (i * 8));
}
std::copy(std::begin(bp_name_bytes), std::end(bp_name_bytes), bp_status_location.begin() + 24);
eosio::checksum256 bp_status_location_key = eosio::keccak((char*)bp_status_location.data(), 64);

// Get the status of the BP
auto status_of_bp = accounts_states_bykey.find(bp_status_location_key);
// Get status of BP in EVM
bool bp_status_in_evm = status_of_bp->value.extract_as_byte_array()[31];

eosio::check(pitr->active() != bp_status_in_evm, "The status of BP is not changed");

// Create a EVM TX for to update the status of BP in EVM
std::array<uint8_t, 36> tx_data{};
// Fill the 4-byte checksum of function
if (pitr->active()) {
// Call registerBP 0x159071ec
tx_data[0] = 21;
tx_data[1] = 144;
tx_data[2] = 113;
tx_data[3] = 236;
} else {
// Call unregisterBP 0xab2e2ac4
tx_data[0] = 171;
tx_data[1] = 46;
tx_data[2] = 42;
tx_data[3] = 196;
}
std::copy(std::begin(bp_name_bytes), std::end(bp_name_bytes), tx_data.begin() + 28);
// Get eosio EVM address nonce
auto accounts_byaccount = account.get_index<eosio::name("byaccount")>();
auto eosio_account = accounts_byaccount.find(get_self().value);
std::optional<eosio::checksum160> eosio_account_address = eosio_account->address;
eosio::check(eosio_account != accounts_byaccount.end(),"eosio EVM address not found");

// REGISTER 159071ec UNREGISTER ab2e2ac4
auto tx_hex = rlp::encode(
uint256_t(eosio_account->nonce), // Nonce
uint256_t(0), // Gas price
uint256_t(100000), // Gas limit
evm_voting_contract_address, // To
uint256_t(0), // Value
tx_data, // Data
uint8_t(0), // V
uint256_t(0), // R
uint256_t(0) // S
);

eosio::action(
eosio::permission_level{get_self(),active_permission},
evm_account,
"raw"_n,
std::make_tuple(evm_account, tx_hex, false, eosio_account_address)
).send();

}
// TELOS END
} /// eosio.system
Loading
Loading