Skip to content

Commit

Permalink
Merge pull request #33 from AntelopeIO/setfinalizer
Browse files Browse the repository at this point in the history
IF: Add setfinalizer action to eosio.bios
  • Loading branch information
linh2931 authored Dec 14, 2023
2 parents a199ba0 + 89672ac commit 57218e4
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .cicd/defaults.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"leap-dev":{
"target":"3",
"target":"hotstuff_integration",
"prerelease":false
},
"cdt":{
"target":"3",
"target":"hotstuff_integration",
"prerelease":false
}
}
7 changes: 3 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,16 @@ jobs:
echo cdt-prerelease=${{inputs.override-cdt-prerelease}} >> $GITHUB_OUTPUT
fi
- name: Download cdt
uses: AntelopeIO/asset-artifact-download-action@v2
uses: AntelopeIO/asset-artifact-download-action@v3
with:
owner: AntelopeIO
repo: cdt
file: 'cdt_.*amd64.deb'
target: '${{steps.versions.outputs.cdt-target}}'
prereleases: ${{fromJSON(steps.versions.outputs.cdt-prerelease)}}
artifact-name: cdt_ubuntu_package_amd64
token: ${{github.token}}
- name: Download leap-dev
uses: AntelopeIO/asset-artifact-download-action@v2
uses: AntelopeIO/asset-artifact-download-action@v3
with:
owner: AntelopeIO
repo: leap
Expand All @@ -81,9 +80,9 @@ jobs:
prereleases: ${{fromJSON(steps.versions.outputs.leap-dev-prerelease)}}
artifact-name: leap-dev-ubuntu20-amd64
container-package: experimental-binaries
token: ${{github.token}}
- name: Install packages
run: |
sudo apt-get update && sudo apt-get upgrade -y
sudo apt install ./*.deb
sudo apt-get install cmake
rm ./*.deb
Expand Down
42 changes: 42 additions & 0 deletions contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <eosio/eosio.hpp>
#include <eosio/fixed_bytes.hpp>
#include <eosio/privileged.hpp>
#include <eosio/instant_finality.hpp>
#include <eosio/producer_schedule.hpp>

namespace eosiobios {
Expand Down Expand Up @@ -66,6 +67,38 @@ namespace eosiobios {
(schedule_version)(new_producers))
};

/**
* finalizer_authority
*
* The public bls key and proof of possession of private key signature,
* and vote weight of a finalizer.
*/
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; // weight that this finalizer's vote has for meeting threshold
std::string public_key; // public key of the finalizer in base64 format
std::string pop; // proof of possession of private key in base64 format

// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE(finalizer_authority, (description)(weight)(public_key)(pop))
};

/**
* finalizer_policy
*
* List of finalizer authorties along with the threshold
*/
struct finalizer_policy {
uint64_t threshold = 0; // quorum threshold
std::vector<finalizer_authority> finalizers;

// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE(finalizer_policy, (threshold)(finalizers));
};

/**
* The `eosio.bios` is the first sample of system contract provided by `block.one` through the EOSIO platform. It is a minimalist system contract because it only supplies the actions that are absolutely critical to bootstrap a chain and nothing more. This allows for a chain agnostic approach to bootstrapping a chain.
*
Expand Down Expand Up @@ -190,6 +223,15 @@ namespace eosiobios {
[[eosio::action]]
void onerror( ignore<uint128_t> sender_id, ignore<std::vector<char>> sent_trx );

/**
* Propose new finalizer policy that, unless superseded by a later
* finalizer policy, will eventually become the active finalizer policy.
*
* @param finalizer_policy - proposed finalizer policy
*/
[[eosio::action]]
void setfinalizer( const finalizer_policy& finalizer_policy );

/**
* Set privilege action allows to set privilege status for an account (turn it on/off).
* @param account - the account to set the privileged status for.
Expand Down
66 changes: 66 additions & 0 deletions contracts/eosio.bios/src/eosio.bios.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <eosio.bios/eosio.bios.hpp>
#include <eosio/crypto_bls_ext.hpp>

#include <unordered_set>

namespace eosiobios {

Expand All @@ -17,6 +20,69 @@ void bios::setabi( name account, const std::vector<char>& abi ) {
}
}

void bios::setfinalizer( const finalizer_policy& finalizer_policy ) {
// exensive checks are performed to make sure setfinalizer host function
// will never fail

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::abi_finalizer_policy abi_finalizer_policy;
abi_finalizer_policy.fthreshold = finalizer_policy.threshold;
abi_finalizer_policy.finalizers.reserve(finalizer_policy.finalizers.size());

const std::string pk_prefix = "PUB_BLS";
const std::string sig_prefix = "SIG_BLS";

// use raw affine format (bls_g1 is std::array<char, 96>) for uniqueness check
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");

// basic key format checks
check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS");
check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS");

// check overflow
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 will fail ("check" function fails)
// if the key is invalid
const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key);
// duplicate key check
check(unique_finalizer_keys.insert(pk).second, "duplicate public key");

const auto signature = eosio::decode_bls_signature_to_g2(f.pop);

// proof of possession of private key check
check(eosio::bls_pop_verify(pk, signature), "proof of possession failed");

std::vector<char> pk_vector(pk.begin(), pk.end());
abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)});
}

check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold cannot be met by finalizer weights");

set_finalizers(std::move(abi_finalizer_policy));
}

void bios::onerror( ignore<uint128_t>, ignore<std::vector<char>> ) {
check( false, "the onerror action cannot be called directly" );
}
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.5)

set(EOSIO_VERSION_MIN "3.1")
set(EOSIO_VERSION_SOFT_MAX "4.1")
set(EOSIO_VERSION_SOFT_MAX "5.0")
# set(EOSIO_VERSION_HARD_MAX "")

find_package(leap)
Expand Down
Loading

0 comments on commit 57218e4

Please sign in to comment.