Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0349c25ccf | |||
| e2de5957ac |
@@ -10,7 +10,8 @@ add_contract(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/powerup.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/limit_auth_changes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/block_info.cpp)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/block_info.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/finalizer_key.cpp)
|
||||
|
||||
if(IS_TESTNET)
|
||||
target_compile_definitions(eosio.system PUBLIC IS_TESTNET=1)
|
||||
|
||||
+41
@@ -511,6 +511,32 @@ namespace eosiosystem {
|
||||
indexed_by<"byexpires"_n, const_mem_fun<powerup_order, uint64_t, &powerup_order::by_expires>>
|
||||
> powerup_order_table;
|
||||
|
||||
/**
|
||||
* Параметры финализаторов Savanna (порт setfinalizer из upstream eosio.bios).
|
||||
* Этап 1 (bootstrap): политику финализаторов задаёт оператор напрямую.
|
||||
* Этап 2 — выборная машинерия финализаторов под кооперативную модель
|
||||
* голосования (1 пайщик = 1 голос); upstream-вариант regfinkey/switchtosvnn
|
||||
* (top-21 по stake-весу) нашей модели не соответствует и потому не переносится как есть.
|
||||
*/
|
||||
constexpr size_t max_finalizers = 64*1024;
|
||||
constexpr size_t max_finalizer_description_size = 256;
|
||||
|
||||
struct finalizer_authority {
|
||||
std::string description; // человеко-читаемое описание финализатора
|
||||
uint64_t weight = 0; // вес голоса финализатора для достижения threshold
|
||||
std::string public_key; // BLS-ключ финализатора в формате base64 (PUB_BLS...)
|
||||
std::string pop; // proof of possession ключа (SIG_BLS...)
|
||||
|
||||
EOSLIB_SERIALIZE(finalizer_authority, (description)(weight)(public_key)(pop))
|
||||
};
|
||||
|
||||
struct finalizer_policy {
|
||||
uint64_t threshold = 0; // порог суммарного веса для финализации
|
||||
std::vector<finalizer_authority> finalizers;
|
||||
|
||||
EOSLIB_SERIALIZE(finalizer_policy, (threshold)(finalizers));
|
||||
};
|
||||
|
||||
/**
|
||||
* The `eosio.system` smart contract is provided by `block.one` as a sample system contract, and it defines the structures and actions needed for blockchain's core functionality.
|
||||
*
|
||||
@@ -616,6 +642,21 @@ namespace eosiosystem {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Предложить новую политику финализаторов Savanna.
|
||||
* Проверяет BLS-ключи и proof of possession каждого финализатора и
|
||||
* передаёт политику в хост-функцию set_finalizers. Вступает в силу,
|
||||
* когда не вытеснена более поздней политикой. Первый вызов после
|
||||
* активации протокол-фичи SAVANNA запускает переход цепи на
|
||||
* instant finality.
|
||||
*
|
||||
* @param finalizer_policy - предлагаемая политика финализаторов
|
||||
*
|
||||
* @note Авторизация требуется от аккаунта: @p get_self()
|
||||
*/
|
||||
[[eosio::action]]
|
||||
void setfinalizer( const finalizer_policy& finalizer_policy );
|
||||
|
||||
[[eosio::action]]
|
||||
void onblock( ignore<block_header> header );
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#include <eosio.system/eosio.system.hpp>
|
||||
|
||||
#include <eosio/crypto_bls_ext.hpp>
|
||||
#include <eosio/instant_finality.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace eosiosystem {
|
||||
|
||||
// Порт setfinalizer из upstream eosio.bios (reference-contracts):
|
||||
// все дорогие проверки выполняются здесь, чтобы хост-функция
|
||||
// set_finalizers гарантированно не упала.
|
||||
// Это bootstrap-механизм этапа 1 (политика от оператора); выборная
|
||||
// машинерия финализаторов под кооперативное голосование — этап 2.
|
||||
void system_contract::setfinalizer( const finalizer_policy& finalizer_policy ) {
|
||||
require_auth( get_self() );
|
||||
|
||||
check(finalizer_policy.finalizers.size() <= max_finalizers, "number of finalizers exceeds the maximum allowed");
|
||||
check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer");
|
||||
|
||||
eosio::finalizer_policy fin_policy;
|
||||
fin_policy.threshold = finalizer_policy.threshold;
|
||||
fin_policy.finalizers.reserve(finalizer_policy.finalizers.size());
|
||||
|
||||
const std::string pk_prefix = "PUB_BLS";
|
||||
const std::string sig_prefix = "SIG_BLS";
|
||||
|
||||
// сырой affine-формат (bls_g1 = std::array<char, 96>) для проверки уникальности
|
||||
struct g1_hash {
|
||||
std::size_t operator()(const eosio::bls_g1& g1) const {
|
||||
std::hash<const char*> hash_func;
|
||||
return hash_func(g1.data());
|
||||
}
|
||||
};
|
||||
struct g1_equal {
|
||||
bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const {
|
||||
return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
|
||||
}
|
||||
};
|
||||
std::unordered_set<eosio::bls_g1, g1_hash, g1_equal> unique_finalizer_keys;
|
||||
|
||||
uint64_t weight_sum = 0;
|
||||
|
||||
for (const auto& f: finalizer_policy.finalizers) {
|
||||
check(f.description.size() <= max_finalizer_description_size, "Finalizer description greater than max allowed size");
|
||||
|
||||
// базовые проверки формата ключа
|
||||
check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key shoud start with PUB_BLS");
|
||||
check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature should start with SIG_BLS");
|
||||
|
||||
// защита от переполнения суммы весов
|
||||
check(std::numeric_limits<uint64_t>::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow");
|
||||
weight_sum += f.weight;
|
||||
|
||||
// decode_bls_public_key_to_g1 сам падает (check) на невалидном ключе
|
||||
const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key);
|
||||
check(unique_finalizer_keys.insert(pk).second, "duplicate public key");
|
||||
|
||||
const auto signature = eosio::decode_bls_signature_to_g2(f.pop);
|
||||
|
||||
// проверка владения приватным ключом
|
||||
check(eosio::bls_pop_verify(pk, signature), "proof of possession failed");
|
||||
|
||||
std::vector<char> pk_vector(pk.begin(), pk.end());
|
||||
fin_policy.finalizers.emplace_back(eosio::finalizer_authority{f.description, f.weight, std::move(pk_vector)});
|
||||
}
|
||||
|
||||
check( weight_sum >= finalizer_policy.threshold && finalizer_policy.threshold > weight_sum / 2,
|
||||
"Finalizer policy threshold must be greater than half of the sum of the weights, and less than or equal to the sum of the weights");
|
||||
|
||||
set_finalizers(std::move(fin_policy));
|
||||
}
|
||||
|
||||
} /// namespace eosiosystem
|
||||
Reference in New Issue
Block a user