Skip to content

trustedpeer/TrustedPeerRegistry.cpp

Implementation of the genesis-seeded, quorum-updatable trusted-peer set (TPR-01, TPR-02, TPR-03). More...

Namespaces

Name
sgns
sgns::trustedpeer

Functions

Name
OUTCOME_CPP_DEFINE_CATEGORY_3(sgns::trustedpeer , TrustedPeerRegistry::Error , e )

Detailed Description

Implementation of the genesis-seeded, quorum-updatable trusted-peer set (TPR-01, TPR-02, TPR-03).

Date: 2026-07-24 Henrique A. Klein ([email protected])

Functions Documentation

function OUTCOME_CPP_DEFINE_CATEGORY_3

OUTCOME_CPP_DEFINE_CATEGORY_3(
    sgns::trustedpeer ,
    TrustedPeerRegistry::Error ,
    e 
)

Source code

#include "trustedpeer/TrustedPeerRegistry.hpp"

#include <system_error>
#include <limits>
#include <unordered_set>

#include "base/hexutil.hpp"
#include "securecrdt/QuorumThresholdValidation.hpp"

OUTCOME_CPP_DEFINE_CATEGORY_3( sgns::trustedpeer, TrustedPeerRegistry::Error, e )
{
    using Error = sgns::trustedpeer::TrustedPeerRegistry::Error;
    switch ( e )
    {
        case Error::NOT_CONFIRMED:
            return "trusted-peer genesis is not durably confirmed";
        case Error::INVALID_CANDIDATE:
            return "trusted-peer candidate is invalid for the durable policy";
        case Error::SIGNING_UNAVAILABLE:
            return "explicit local signing is unavailable";
    }
    return "unknown TrustedPeerRegistry::Error";
}

namespace sgns::trustedpeer
{
    TrustedPeerListPayload::TrustedPeerListPayload( std::vector<std::string> peers ) : peers_( std::move( peers ) )
    {
    }

    std::vector<uint8_t> TrustedPeerListPayload::SerializeToBytes() const
    {
        std::string joined;
        for ( size_t i = 0; i < peers_.size(); ++i )
        {
            if ( i > 0 )
            {
                joined.push_back( '\n' );
            }
            joined += peers_[i];
        }
        return std::vector<uint8_t>( joined.begin(), joined.end() );
    }

    std::optional<TrustedPeerListPayload> TrustedPeerListPayload::FromBytes( const std::vector<uint8_t> &bytes )
    {
        if ( bytes.empty() )
        {
            return std::nullopt;
        }

        std::string              raw( bytes.begin(), bytes.end() );
        std::vector<std::string> parsed;
        size_t                   start = 0;
        while ( start <= raw.size() )
        {
            const auto pos = raw.find( '\n', start );
            if ( pos == std::string::npos )
            {
                parsed.push_back( raw.substr( start ) );
                break;
            }
            parsed.push_back( raw.substr( start, pos - start ) );
            start = pos + 1;
        }

        return TrustedPeerListPayload( std::move( parsed ) );
    }

    bool TrustedPeerListPayload::DeserializeFromBytes( const std::vector<uint8_t> &bytes )
    {
        auto payload = FromBytes( bytes );
        if ( !payload )
        {
            return false;
        }

        peers_ = std::move( payload->peers_ );
        return true;
    }

    bool TrustedPeerListPayload::Verify( const std::vector<uint8_t> &payload ) const
    {
        auto parsed = FromBytes( payload );
        if ( !parsed || parsed->peers_.empty() )
        {
            return false;
        }

        std::unordered_set<std::string> unique_entries;
        for ( const auto &entry : parsed->peers_ )
        {
            if ( !sgns::base::IsHexAddress( entry ) )
            {
                return false;
            }
            if ( !unique_entries.insert( entry ).second )
            {
                return false; // duplicate entry
            }
        }

        return true;
    }

    void TrustedPeerListPayload::Apply()
    {
    }

    TrustedPeerRegistry::TrustedPeerRegistry( std::shared_ptr<sgns::securecrdt::SecureCrdt> secure_crdt,
                                              std::vector<std::string>                      genesis_peers,
                                              std::string                                   bootstrapper_address,
                                              uint64_t                                      quorum_threshold,
                                              sgns::crdt::HierarchicalKey                   base_key ) :
        secure_crdt_( std::move( secure_crdt ) ),
        base_key_( std::move( base_key ) ),
        bootstrapper_address_( std::move( bootstrapper_address ) ),
        quorum_threshold_( quorum_threshold ),
        cached_peers_( std::move( genesis_peers ) )
    {
    }

    TrustedPeerRegistry::~TrustedPeerRegistry()
    {
        Unregister();
    }

    outcome::result<std::shared_ptr<TrustedPeerRegistry>> TrustedPeerRegistry::New(
        std::shared_ptr<sgns::securecrdt::SecureCrdt> secure_crdt,
        std::vector<std::string>                      genesis_peers,
        std::string                                   bootstrapper_address,
        uint64_t                                      quorum_threshold,
        sgns::crdt::HierarchicalKey                   base_key )
    {
        auto validation_result = sgns::securecrdt::ValidateMembershipQuorumThreshold( quorum_threshold,
                                                                                      genesis_peers.size() );
        if ( validation_result.has_error() )
        {
            return validation_result.error();
        }

        auto instance = std::make_shared<TrustedPeerRegistry>( std::move( secure_crdt ),
                                                               std::move( genesis_peers ),
                                                               std::move( bootstrapper_address ),
                                                               quorum_threshold,
                                                               std::move( base_key ) );
        if ( !instance->RegisterSignerSetSource() )
        {
            return outcome::failure( std::errc::file_exists );
        }
        return instance;
    }

    outcome::result<std::shared_ptr<TrustedPeerRegistry>> TrustedPeerRegistry::NewProduction(
        std::shared_ptr<sgns::securecrdt::SecureCrdt> secure_crdt,
        std::shared_ptr<TrustStateStore>              trust_store,
        GenesisManifest                               reviewed_manifest,
        std::vector<uint8_t>                          bootstrap_manifest_signature,
        std::string                                   local_signer_address,
        SignCallback                                  sign_callback,
        std::string                                   policy_domain )
    {
        const auto canonical = reviewed_manifest.Canonicalized();
        const auto bytes     = reviewed_manifest.CanonicalBytes();
        if ( !secure_crdt || !trust_store || !canonical || !bytes || policy_domain.empty() )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }

        auto instance                           = std::make_shared<TrustedPeerRegistry>( std::move( secure_crdt ),
                                                               std::vector<std::string>{},
                                                               canonical->bootstrapper_public_key,
                                                               canonical->membership_threshold,
                                                               sgns::crdt::HierarchicalKey( policy_domain ) );
        instance->production_mode_              = true;
        instance->trust_store_                  = std::move( trust_store );
        instance->reviewed_manifest_            = *canonical;
        instance->bootstrap_manifest_signature_ = std::move( bootstrap_manifest_signature );
        instance->local_signer_address_         = std::move( local_signer_address );
        instance->sign_callback_                = std::move( sign_callback );
        instance->policy_domain_                = std::move( policy_domain );
        instance->genesis_domain_               = instance->policy_domain_ + "-genesis";

        if ( !instance->RegisterProductionDomains() )
        {
            return outcome::failure( std::errc::file_exists );
        }
        auto restored = instance->trust_store_->LoadAndVerify();
        if ( restored.has_value() )
        {
            if ( restored.value().genesis_fingerprint != instance->reviewed_manifest_.Fingerprint().value() )
            {
                instance->Unregister();
                return outcome::failure( TrustStateStore::Error::CORRUPT_FINGERPRINT );
            }
            instance->PublishSnapshot( restored.value() );
        }
        else if ( restored.error() != TrustStateStore::Error::NOT_FOUND )
        {
            instance->Unregister();
            return restored.error();
        }
        return instance;
    }

    bool TrustedPeerRegistry::RegisterProductionDomains()
    {
        const bool genesis_registered = secure_crdt_->Registry().RegisterCandidateDomain(
            genesis_domain_,
            sgns::securecrdt::CandidateDomainEntry{
                genesis_domain_,
                sgns::securecrdt::CandidateKind::TrustedPeerGenesis,
                [weak_self = weak_from_this()]() -> outcome::result<sgns::securecrdt::CandidateAuthorizationSnapshot>
                {
                    auto self = weak_self.lock();
                    if ( !self )
                    {
                        return outcome::failure( Error::NOT_CONFIRMED );
                    }
                    return self->ResolveGenesisAuthorization();
                },
                &registry_token_ } );
        const bool policy_registered = secure_crdt_->Registry().RegisterCandidateDomain(
            policy_domain_,
            sgns::securecrdt::CandidateDomainEntry{
                policy_domain_,
                sgns::securecrdt::CandidateKind::TrustPolicy,
                [weak_self = weak_from_this()]() -> outcome::result<sgns::securecrdt::CandidateAuthorizationSnapshot>
                {
                    auto self = weak_self.lock();
                    if ( !self )
                    {
                        return outcome::failure( Error::NOT_CONFIRMED );
                    }
                    auto authorization = self->ResolvePolicyAuthorization();
                    if ( authorization.has_error() && authorization.error() == Error::NOT_CONFIRMED )
                    {
                        return outcome::failure(
                            sgns::securecrdt::SecureCrdt::Error::CANDIDATE_AUTHORIZATION_PENDING );
                    }
                    return authorization;
                },
                &registry_token_ } );
        if ( !genesis_registered || !policy_registered )
        {
            secure_crdt_->Registry().UnregisterCandidateDomainIf( genesis_domain_, &registry_token_ );
            secure_crdt_->Registry().UnregisterCandidateDomainIf( policy_domain_, &registry_token_ );
            return false;
        }
        return true;
    }

    outcome::result<sgns::securecrdt::CandidateAuthorizationSnapshot> TrustedPeerRegistry::ResolveGenesisAuthorization()
        const
    {
        const auto fingerprint = reviewed_manifest_.Fingerprint();
        if ( !fingerprint )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        return sgns::securecrdt::CandidateAuthorizationSnapshot{ reviewed_manifest_.network_id,
                                                                 sgns::securecrdt::CandidateKind::TrustedPeerGenesis,
                                                                 reviewed_manifest_.policy_version,
                                                                 *fingerprint,
                                                                 *fingerprint,
                                                                 { reviewed_manifest_.bootstrapper_public_key } };
    }

    outcome::result<sgns::securecrdt::CandidateAuthorizationSnapshot> TrustedPeerRegistry::ResolvePolicyAuthorization()
        const
    {
        auto snapshot = GetConfirmedSnapshot();
        if ( snapshot.has_error() )
        {
            return snapshot.error();
        }
        const auto policy_hash = snapshot.value().policy.Hash();
        if ( !policy_hash || snapshot.value().policy.version == std::numeric_limits<uint64_t>::max() )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        return sgns::securecrdt::CandidateAuthorizationSnapshot{ snapshot.value().policy.network_id,
                                                                 sgns::securecrdt::CandidateKind::TrustPolicy,
                                                                 snapshot.value().policy.version + 1,
                                                                 *policy_hash,
                                                                 *policy_hash,
                                                                 snapshot.value().policy.peers };
    }

    std::optional<sgns::securecrdt::CandidateCore> TrustedPeerRegistry::PolicyCandidateCore(
        const QuorumPolicyState &candidate,
        const std::string       &domain )
    {
        auto bytes = candidate.CanonicalBytes();
        if ( !bytes || domain.empty() )
        {
            return std::nullopt;
        }
        return sgns::securecrdt::CandidateCore{ sgns::securecrdt::CandidateCore::ENCODING_VERSION,
                                                domain,
                                                candidate.network_id,
                                                sgns::securecrdt::CandidateKind::TrustPolicy,
                                                candidate.version,
                                                candidate.expected_previous_hash,
                                                candidate.authorizing_policy_hash,
                                                std::move( *bytes ) };
    }

    outcome::result<sgns::securecrdt::CandidateId> TrustedPeerRegistry::SubmitLocalApproval(
        const sgns::securecrdt::CandidateCore &core )
    {
        if ( !sign_callback_ || local_signer_address_.empty() )
        {
            return outcome::failure( Error::SIGNING_UNAVAILABLE );
        }
        const auto bytes = core.CanonicalBytes();
        if ( !bytes )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        const auto id = sgns::securecrdt::CandidateId::FromCore( core );
        if ( !id )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto existing = secure_crdt_->ReadCandidateApprovals( *id );
        if ( existing.has_value() &&
             std::any_of( existing.value().begin(),
                          existing.value().end(),
                          [&]( const auto &approval ) { return approval.signer == local_signer_address_; } ) )
        {
            return *id;
        }
        sgns::securecrdt::CandidateApprovalRecord approval{ sgns::securecrdt::CandidateApprovalRecord::ENCODING_VERSION,
                                                            core,
                                                            local_signer_address_,
                                                            sign_callback_( *bytes ) };
        return secure_crdt_->SubmitCandidateApproval( approval );
    }

    outcome::result<sgns::securecrdt::CandidateId> TrustedPeerRegistry::SubmitReviewedGenesisApproval()
    {
        if ( !production_mode_ || local_signer_address_ != reviewed_manifest_.bootstrapper_public_key )
        {
            return outcome::failure( Error::SIGNING_UNAVAILABLE );
        }
        const auto fingerprint = reviewed_manifest_.Fingerprint();
        const auto payload     = reviewed_manifest_.CanonicalBytes();
        if ( !fingerprint || !payload )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto core = GenesisCandidateCore( reviewed_manifest_, *payload, *fingerprint, genesis_domain_ );
        auto submitted = SubmitLocalApproval( core );
        if ( submitted.has_error() )
        {
            return submitted.error();
        }
        auto committed = trust_store_->CommitGenesis( reviewed_manifest_, bootstrap_manifest_signature_ );
        if ( committed.has_error() )
        {
            return committed.error();
        }
        PublishSnapshot( committed.value() );
        return submitted.value();
    }

    outcome::result<bool> TrustedPeerRegistry::TryActivateReviewedGenesisCandidate(
        const sgns::securecrdt::CandidateId &candidate_id )
    {
        if ( !production_mode_ || !trust_store_ )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        const auto fingerprint = reviewed_manifest_.Fingerprint();
        const auto payload     = reviewed_manifest_.CanonicalBytes();
        if ( !fingerprint || !payload )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        const auto expected = GenesisCandidateCore( reviewed_manifest_, *payload, *fingerprint, genesis_domain_ );
        const auto expected_id = sgns::securecrdt::CandidateId::FromCore( expected );
        if ( !expected_id || !( *expected_id == candidate_id ) )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto approvals = secure_crdt_->ReadCandidateApprovals( candidate_id );
        if ( approvals.has_error() )
        {
            return approvals.error();
        }
        const auto approval = std::find_if(
            approvals.value().begin(),
            approvals.value().end(),
            [&]( const auto &record )
            { return record.core == expected && record.signer == reviewed_manifest_.bootstrapper_public_key; } );
        if ( approval == approvals.value().end() )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        const auto authorization_bytes = expected.CanonicalBytes();
        if ( !authorization_bytes )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto committed = trust_store_->CommitGenesis( reviewed_manifest_, approval->signature, *authorization_bytes );
        if ( committed.has_error() )
        {
            if ( committed.error() == TrustStateStore::Error::ALREADY_INITIALIZED )
            {
                auto existing = trust_store_->LoadAndVerify();
                if ( existing.has_error() || existing.value().genesis_fingerprint != *fingerprint )
                {
                    return committed.error();
                }
                PublishSnapshot( existing.value() );
                return false;
            }
            return committed.error();
        }
        PublishSnapshot( committed.value() );
        return true;
    }

    outcome::result<std::vector<sgns::securecrdt::CandidateId>> TrustedPeerRegistry::ListPendingPolicyCandidates() const
    {
        auto snapshot = GetConfirmedSnapshot();
        if ( snapshot.has_error() )
        {
            return snapshot.error();
        }
        const auto hash = snapshot.value().policy.Hash();
        if ( !hash )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        return secure_crdt_->ListCandidates( policy_domain_, *hash );
    }

    outcome::result<sgns::securecrdt::CandidateId> TrustedPeerRegistry::ProposePolicyCandidate(
        const QuorumPolicyState &candidate )
    {
        auto current = GetConfirmedSnapshot();
        if ( current.has_error() )
        {
            return current.error();
        }
        if ( !ValidatePolicySuccessor( current.value().policy, candidate ) )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto core = PolicyCandidateCore( candidate, policy_domain_ );
        if ( !core )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        return SubmitLocalApproval( *core );
    }

    outcome::result<sgns::securecrdt::CandidateId> TrustedPeerRegistry::ApprovePolicyCandidate(
        const sgns::securecrdt::CandidateId &candidate_id )
    {
        if ( candidate_id.domain != policy_domain_ )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto approvals = secure_crdt_->ReadCandidateApprovals( candidate_id );
        if ( approvals.has_error() )
        {
            return approvals.error();
        }
        if ( approvals.value().empty() )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        // Already activated by a concurrent refresh before this approval could be
        // submitted — the authorization context has advanced, so submitting would be
        // rejected as a context mismatch. The approval is redundant; succeed.
        auto current = GetConfirmedSnapshot();
        if ( current.has_value() &&
             current.value().policy.Hash() == std::optional<std::string>( candidate_id.content_hash ) )
        {
            return candidate_id;
        }
        auto submitted = SubmitLocalApproval( approvals.value().front().core );
        if ( submitted.has_error() &&
             submitted.error() == sgns::securecrdt::SecureCrdt::Error::CANDIDATE_CONTEXT_MISMATCH )
        {
            // The refresh activated the candidate while this approval was in flight;
            // the authorization context moved past it. Re-check durability.
            current = GetConfirmedSnapshot();
            if ( current.has_value() &&
                 current.value().policy.Hash() == std::optional<std::string>( candidate_id.content_hash ) )
            {
                return candidate_id;
            }
        }
        return submitted;
    }

    outcome::result<bool> TrustedPeerRegistry::TryActivatePolicyCandidate(
        const sgns::securecrdt::CandidateId &candidate_id )
    {
        auto current = GetConfirmedSnapshot();
        if ( current.has_error() )
        {
            return current.error();
        }
        auto approvals = secure_crdt_->ReadCandidateApprovals( candidate_id );
        if ( approvals.has_error() )
        {
            return approvals.error();
        }
        if ( approvals.value().empty() )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        const auto &core          = approvals.value().front().core;
        auto        candidate     = QuorumPolicyState::DecodeCanonical( core.payload );
        auto        expected_core = candidate ? PolicyCandidateCore( *candidate, policy_domain_ ) : std::nullopt;
        if ( candidate_id.domain != policy_domain_ || !candidate || !expected_core || !( *expected_core == core ) )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        // Already the durable policy (admin/refresh activation race) — idempotent.
        const auto current_policy_hash = current.value().policy.Hash();
        const auto candidate_hash      = candidate->Hash();
        if ( current_policy_hash && candidate_hash && *current_policy_hash == *candidate_hash &&
             current.value().policy.version == candidate->version )
        {
            return false;
        }
        if ( !ValidatePolicySuccessor( current.value().policy, *candidate ) )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        multisig::CollectedSignatures proof;
        for ( const auto &approval : approvals.value() )
        {
            proof.emplace_back( approval.signer, approval.signature );
        }
        if ( proof.size() < current.value().policy.membership_threshold )
        {
            return false;
        }
        const auto authorization_bytes = core.CanonicalBytes();
        if ( !authorization_bytes )
        {
            return outcome::failure( Error::INVALID_CANDIDATE );
        }
        auto committed = trust_store_->CommitPolicySuccessor( *candidate, proof, *authorization_bytes );
        if ( committed.has_error() )
        {
            return committed.error();
        }
        PublishSnapshot( committed.value() );
        return true;
    }

    outcome::result<ConfirmedTrustSnapshot> TrustedPeerRegistry::GetConfirmedSnapshot() const
    {
        if ( !production_mode_ || !trust_store_ )
        {
            return outcome::failure( Error::NOT_CONFIRMED );
        }
        auto loaded = trust_store_->LoadAndVerify();
        if ( loaded.has_error() && loaded.error() == TrustStateStore::Error::NOT_FOUND )
        {
            return outcome::failure( Error::NOT_CONFIRMED );
        }
        return loaded;
    }

    void TrustedPeerRegistry::PublishSnapshot( const ConfirmedTrustSnapshot &snapshot )
    {
        std::unique_lock<std::shared_mutex> lock( cache_mutex_ );
        cached_peers_      = snapshot.policy.peers;
        quorum_threshold_  = snapshot.policy.membership_threshold;
        genesis_confirmed_ = true;
    }

    bool TrustedPeerRegistry::RegisterSignerSetSource()
    {
        sgns::securecrdt::SecureCrdtRegistryEntry entry;
        entry.signer_set_source = [weak_self = weak_from_this()](
                                      const std::string & ) -> outcome::result<sgns::securecrdt::SignerSetSnapshot>
        {
            auto self = weak_self.lock();
            if ( !self )
            {
                return sgns::securecrdt::SignerSetSnapshot{};
            }
            return self->ResolveSignerSet();
        };
        entry.make_instance = []() -> std::shared_ptr<sgns::securecrdt::ISignedCRDTData>
        { return std::make_shared<TrustedPeerListPayload>(); };
        entry.owner_token = &registry_token_;
        // D-04: the global registry's own policy entry records its authority,
        // so Resolve() callers can see which PeerRegistry owns the key.
        entry.peer_registry = shared_from_this();

        return secure_crdt_->Registry().Register( base_key_.GetKey(), std::move( entry ) );
    }

    outcome::result<sgns::securecrdt::SignerSetSnapshot> TrustedPeerRegistry::CurrentSignerSet() const
    {
        return ResolveSignerSet();
    }

    outcome::result<sgns::securecrdt::SignerSetSnapshot> TrustedPeerRegistry::ResolveSignerSet() const
    {
        std::shared_lock<std::shared_mutex> lock( cache_mutex_ );
        if ( !genesis_confirmed_ )
        {
            return sgns::securecrdt::SignerSetSnapshot{ { bootstrapper_address_ }, 1 };
        }
        return sgns::securecrdt::SignerSetSnapshot{ cached_peers_, quorum_threshold_ };
    }

    outcome::result<void> TrustedPeerRegistry::SeedGenesis( const std::vector<std::string> &genesis_peers,
                                                            const std::vector<uint8_t>     &ephemeral_signature )
    {
        logger_->info( "{}: seeding genesis trusted-peer list ({} peers)", __func__, genesis_peers.size() );

        TrustedPeerListPayload payload( genesis_peers );
        auto                   propose_result = secure_crdt_->ProposeValue( base_key_, payload.SerializeToBytes() );
        if ( propose_result.has_error() )
        {
            logger_->error( "{}: ProposeValue failed", __func__ );
            return propose_result.error();
        }

        auto sign_result = secure_crdt_->AddSignature(
            base_key_,
            bootstrapper_address_,
            std::vector<uint8_t>( ephemeral_signature.begin(), ephemeral_signature.end() ) );
        if ( sign_result.has_error() )
        {
            logger_->error( "{}: AddSignature failed", __func__ );
            return sign_result.error();
        }

        return outcome::success();
    }

    outcome::result<void> TrustedPeerRegistry::ProposeMembershipChange( const std::vector<std::string> &new_peers )
    {
        logger_->info( "{}: proposing membership change ({} peers)", __func__, new_peers.size() );
        TrustedPeerListPayload payload( new_peers );
        return secure_crdt_->ProposeValue( base_key_, payload.SerializeToBytes() );
    }

    outcome::result<void> TrustedPeerRegistry::SignMembershipChange( const std::string          &signer_address,
                                                                     const std::vector<uint8_t> &signature )
    {
        logger_->info( "{}: signing membership change (signer={})", __func__, signer_address );
        return secure_crdt_->AddSignature( base_key_,
                                           signer_address,
                                           std::vector<uint8_t>( signature.begin(), signature.end() ) );
    }

    outcome::result<bool> TrustedPeerRegistry::TryConfirm()
    {
        auto read_result = secure_crdt_->ReadIfQuorum( base_key_ );
        if ( read_result.has_error() )
        {
            return read_result.error();
        }

        if ( !read_result.value().has_value() )
        {
            return outcome::success( false );
        }

        const auto bytes   = read_result.value()->toVector();
        auto       payload = TrustedPeerListPayload::FromBytes( bytes );
        if ( !payload )
        {
            logger_->error( "{}: confirmed value failed to deserialize", __func__ );
            return outcome::failure( std::errc::bad_message );
        }
        if ( !payload->Verify( bytes ) )
        {
            logger_->error( "{}: confirmed value failed structural verification", __func__ );
            return outcome::failure( std::errc::bad_message );
        }
        payload->Apply();

        {
            std::unique_lock<std::shared_mutex> lock( cache_mutex_ );
            cached_peers_      = payload->GetPeers();
            genesis_confirmed_ = true;
        }

        logger_->info( "{}: confirmed trusted-peer set ({} peers)", __func__, payload->GetPeers().size() );
        return outcome::success( true );
    }

    std::vector<std::string> TrustedPeerRegistry::GetCurrentPeers() const
    {
        std::shared_lock<std::shared_mutex> lock( cache_mutex_ );
        return cached_peers_;
    }

    bool TrustedPeerRegistry::IsGenesisConfirmed() const
    {
        std::shared_lock<std::shared_mutex> lock( cache_mutex_ );
        return genesis_confirmed_;
    }

    void TrustedPeerRegistry::Unregister()
    {
        secure_crdt_->Registry().UnregisterIf( base_key_.GetKey(), &registry_token_ );
        if ( production_mode_ )
        {
            secure_crdt_->Registry().UnregisterCandidateDomainIf( genesis_domain_, &registry_token_ );
            secure_crdt_->Registry().UnregisterCandidateDomainIf( policy_domain_, &registry_token_ );
        }
    }
} // namespace sgns::trustedpeer

Updated on 2026-10-10 at 04:54:24 +0000