Skip to content

account/TrustStartupController.hpp

Durable trust bootstrap and restart state machine for GeniusNode.

Namespaces

Name
sgns
sgns::account

Classes

Name
class sgns::account::TrustStartupController
struct sgns::account::TrustStartupController::Event
struct sgns::account::TrustStartupController::RefreshTestHooks
struct fmt::formatter< sgns::account::TrustStartupController::EventCode >
Lets an EventCode be passed straight to any spdlog/fmt call: logger->info( "{}", event.code ).

Source code

#ifndef SGNS_ACCOUNT_TRUST_STARTUP_CONTROLLER_HPP
#define SGNS_ACCOUNT_TRUST_STARTUP_CONTROLLER_HPP

#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <system_error>
#include <vector>

#include <fmt/format.h>

#include "outcome/outcome.hpp"
#include "trustedpeer/GenesisManifest.hpp"
#include "trustedpeer/TrustStateStore.hpp"
#include "trustedpeer/TrustedPeerRegistry.hpp"

namespace sgns::account
{
    class BurnConfig;

    class TrustStartupController
    {
    public:
        enum class State : uint8_t
        {
            FreshWaitingForGenesis = 0,
            WaitingForInitialBurn,
            ConfirmedReady,
            FatalMismatch,
        };

        enum class EventCode : uint8_t
        {
            TRUST_CONFIG_CONFLICT = 0,
            TRUST_NETWORK_MISMATCH,
            TRUST_LOCAL_STATE_CORRUPT,
            TRUST_CRDT_MISSING,
            TRUST_CRDT_ROLLBACK,
            TRUST_CRDT_FORK,
            TRUST_ACTIVATION_FAILED,
            TRUST_REFRESH_RETRY_SCHEDULED,
            TRUST_REFRESH_RETRY_EXHAUSTED,
        };

        enum class RefreshStage : uint8_t
        {
            DurableState = 0,
            GenesisDiscovery,
            PolicyDiscovery,
            PolicyActivation,
            BurnDiscovery,
            BurnActivation,
            Publication,
        };

        enum class RetryDisposition : uint8_t
        {
            Success = 0,
            Transient,
            Actionable,
            Fatal,
        };

        [[nodiscard]] static const char *EventCodeName( EventCode code ) noexcept;

        struct Event
        {
            EventCode                code;
            std::vector<std::string> fields;
            std::string              persisted_fingerprint;
        };

        using EventCallback = std::function<void( const Event & )>;
        using StateCallback = std::function<void( State )>;

        struct RefreshTestHooks
        {
            using CandidateList = outcome::result<std::vector<sgns::securecrdt::CandidateId>>;

            std::function<CandidateList( sgns::trustedpeer::TrustedPeerRegistry & )> list_policy_candidates;
            std::function<CandidateList( BurnConfig & )>                            list_burn_candidates;
            std::function<void( uint32_t )>                                         observe_attempt;
            std::function<void( std::chrono::milliseconds, std::function<void()> )> schedule_retry;
            std::function<void()>                                                   observe_dispatch_idle;
            std::function<void()>                                                   observe_coalesced_request;
            std::function<void( std::function<void()> )>                            bind_request_refresh;
        };

        static outcome::result<std::shared_ptr<TrustStartupController>> New(
            std::shared_ptr<sgns::securecrdt::SecureCrdt>        secure_crdt,
            std::shared_ptr<sgns::trustedpeer::TrustStateStore>  trust_store,
            std::optional<sgns::trustedpeer::GenesisManifest>    diagnostic_manifest,
            std::string                                          local_signer_address,
            sgns::trustedpeer::TrustedPeerRegistry::SignCallback sign_callback,
            EventCallback                                        event_callback = {},
            StateCallback                                        state_callback = {},
            std::shared_ptr<RefreshTestHooks>                     refresh_test_hooks = {} );

        ~TrustStartupController();

        outcome::result<void> Refresh();
        outcome::result<void> ObserveReplicatedSnapshot(
            const std::optional<sgns::trustedpeer::ConfirmedTrustSnapshot> &replicated );

        [[nodiscard]] State                    GetState() const noexcept;
        [[nodiscard]] bool                     CanApproveSuccessors() const noexcept;
        [[nodiscard]] bool                     IsEconomicallyReady() const noexcept;
        [[nodiscard]] std::vector<std::string> GetCurrentPeers() const;

        [[nodiscard]] std::shared_ptr<sgns::trustedpeer::TrustedPeerRegistry> registry() const;
        [[nodiscard]] std::shared_ptr<BurnConfig>                             burn_config() const;

    private:
        TrustStartupController() = default;
        struct RefreshDispatchState;

        void SetState( State state );
        void Emit( EventCode code, std::vector<std::string> fields = {} ) const;
        void EmitActivationFailed( const std::string &domain,
                                   const std::string &version,
                                   const std::string &content_hash,
                                   const std::error_code &error ) const;
        void RequestRefresh();
        void QueuePendingCandidate( const sgns::securecrdt::CandidateId &candidate );
        void MarkCandidateFailed( const sgns::securecrdt::CandidateId &candidate );
        outcome::result<void> RefreshClassified( RefreshStage &stage );
        static RetryDisposition ClassifyRefreshResult( RefreshStage                 stage,
                                                       const outcome::result<void> &result );
        static void RequestDispatch( const std::shared_ptr<RefreshDispatchState> &dispatch );
        static void RunDispatchAttempt( const std::shared_ptr<RefreshDispatchState> &dispatch,
                                        uint32_t                                     attempt );
        static void FinishDispatch( const std::shared_ptr<RefreshDispatchState> &dispatch );

        std::shared_ptr<sgns::securecrdt::SecureCrdt>           secure_crdt_;
        std::shared_ptr<sgns::trustedpeer::TrustStateStore>     trust_store_;
        std::shared_ptr<sgns::trustedpeer::TrustedPeerRegistry> registry_;
        std::shared_ptr<BurnConfig>                             burn_config_;
        std::shared_ptr<RefreshTestHooks>                       refresh_test_hooks_;
        sgns::trustedpeer::GenesisManifest                      manifest_;
        std::string                                             local_signer_address_;
        EventCallback                                           event_callback_;
        StateCallback                                           state_callback_;
        std::atomic<State>                                      state_{ State::FreshWaitingForGenesis };
        std::mutex                                              refresh_execution_mutex_;
        std::shared_ptr<RefreshDispatchState>                   refresh_dispatch_;
        mutable std::mutex                                      candidate_mutex_;
        std::vector<sgns::securecrdt::CandidateId>              pending_policy_candidates_;
        std::vector<sgns::securecrdt::CandidateId>              failed_policy_candidates_;
        std::vector<sgns::securecrdt::CandidateId>              pending_burn_candidates_;
        std::vector<sgns::securecrdt::CandidateId>              failed_burn_candidates_;
        std::optional<sgns::securecrdt::CandidateId>            failed_genesis_candidate_;
    };
}

template <>
struct fmt::formatter<sgns::account::TrustStartupController::EventCode> : formatter<std::string_view>
{
    format_context::iterator format( const sgns::account::TrustStartupController::EventCode &code,
                                     format_context                                          &ctx ) const
    {
        return formatter<string_view>::format( sgns::account::TrustStartupController::EventCodeName( code ), ctx );
    }
};

#endif

Updated on 2026-09-25 at 15:46:11 +0000