Skip to content

account/GeniusNode.hpp

Top-level node orchestration API for account, transaction, blockchain, and processing services. More...

Namespaces

Name
sgns
sgns::ipfs_bitswap
sgns::evmwatcher

Classes

Name
struct DevConfig
Runtime configuration values used to bootstrap a Genius node instance.
struct sgns::NewAccount
Account-creation source for GeniusNode::New(dev_config, AccountSource).Generate a new identity.
struct sgns::FromPrivateKey
Restore from an Ethereum hex private key.
struct sgns::FromMnemonic
Restore from a BIP39 mnemonic.
struct sgns::FromPublicKey
Load from storage by public address (read-only).
class sgns::GeniusNode
High-level facade that initializes and coordinates account, networking, transaction, blockchain, and processing subsystems.

Types

Name
typedef struct DevConfig GeniusNodeConfig
Runtime configuration values used to bootstrap a Genius node instance.
using std::variant< NewAccount, FromPrivateKey, FromMnemonic, FromPublicKey > AccountSource

Functions

Name
OUTCOME_HPP_DECLARE_ERROR_2(sgns , GeniusNode::Error )

Attributes

Name
GeniusNodeConfig DEV_CONFIG
constexpr uint64_t kDefaultTimestampToleranceMs

Defines

Name
OUTGOING_TIMEOUT_MILLISECONDS
INCOMING_TIMEOUT_MILLISECONDS

Detailed Description

Top-level node orchestration API for account, transaction, blockchain, and processing services.

Date: 2024-03-11 Henrique A. Klein ([email protected])

Types Documentation

typedef GeniusNodeConfig

typedef struct DevConfig GeniusNodeConfig;

Runtime configuration values used to bootstrap a Genius node instance.

using AccountSource

using sgns::AccountSource = typedef std::variant<NewAccount, FromPrivateKey, FromMnemonic, FromPublicKey>;

Functions Documentation

function OUTCOME_HPP_DECLARE_ERROR_2

OUTCOME_HPP_DECLARE_ERROR_2(
    sgns ,
    GeniusNode::Error 
)

Attributes Documentation

variable DEV_CONFIG

GeniusNodeConfig DEV_CONFIG;

variable kDefaultTimestampToleranceMs

constexpr uint64_t kDefaultTimestampToleranceMs = 300000;

Macros Documentation

define OUTGOING_TIMEOUT_MILLISECONDS

#define OUTGOING_TIMEOUT_MILLISECONDS 50000

define INCOMING_TIMEOUT_MILLISECONDS

#define INCOMING_TIMEOUT_MILLISECONDS 150000

Source code

#ifndef _GENIUS_NODE_HPP_
#define _GENIUS_NODE_HPP_

#include <chrono>
#include <memory>
#include <cstdint>
#include <functional>
#include <vector>
#include <thread>
#include <optional>
#include <variant>
#include <mutex>
#include <atomic>

#include <boost/asio.hpp>
#include <spdlog/sinks/basic_file_sink.h>
#include <libp2p/log/logger.hpp>
#include <libp2p/multi/multibase_codec/multibase_codec_impl.hpp>
#include <libp2p/multi/content_identifier_codec.hpp>

#include "account/GeniusAccount.hpp"
#include "base/buffer.hpp"
#include "account/PublicChainInputValidator.hpp"
#include "account/TransactionManager.hpp"
#include "account/BridgeRelayer.hpp"
#include "account/ChainRpcEndpointProvider.hpp"
#include "eth/eth_watch_service.hpp"
#include <ipfs_lite/ipfs/graphsync/graphsync.hpp>
#include "crypto/hasher.hpp"
#include "processing/impl/processing_core_impl.hpp"
#include "processing/impl/processing_subtask_result_storage_impl.hpp"
#include "processing/processing_service.hpp"
#include "singleton/IComponent.hpp"
#include "processing/processing_task_queue.hpp"
#include "coinprices/coinprices.hpp"
#include "blockchain/Blockchain.hpp"
#include <boost/algorithm/string/replace.hpp>
#include <ipfs_lite/ipfs/graphsync/impl/network/network.hpp>
#include <processingbase/ProcessingManager.hpp>
#include <libp2p/peer/peer_info.hpp>
#include <libp2p/event/bus.hpp>
#include <libp2p/network/connection_manager.hpp>

// Forward declaration for bitswap
namespace sgns::ipfs_bitswap
{
    class Bitswap;
}

typedef struct DevConfig
{
    std::string   Addr;             
    std::string   Cut;              
    std::string   TokenValueInGNUS; 
    sgns::TokenID TokenID;          
    std::string   BaseWritePath;    
} GeniusNodeConfig;

extern GeniusNodeConfig DEV_CONFIG;

constexpr uint64_t kDefaultTimestampToleranceMs = 300000; // ±5 minutes

#define OUTGOING_TIMEOUT_MILLISECONDS 50000  // just communication time
#define INCOMING_TIMEOUT_MILLISECONDS 150000 // communication + verify proof

namespace sgns
{
    class MigrationManager;

    namespace evmwatcher
    {
        class BridgeCatchupWatcher;
    }

    struct NewAccount
    {
    }; 

    struct FromPrivateKey
    {
        std::string eth_private_key;
    }; 

    struct FromMnemonic
    {
        std::string mnemonic;
    }; 

    struct FromPublicKey
    {
        std::string public_address;
    }; 

    using AccountSource = std::variant<NewAccount, FromPrivateKey, FromMnemonic, FromPublicKey>;

    class GeniusNode : public IComponent, public IBridgeInitObserver, public std::enable_shared_from_this<GeniusNode>
    {
    public:
        static std::shared_ptr<GeniusNode> New( const GeniusNodeConfig &dev_config, AccountSource source );

        static outcome::result<void> WriteNetworkConfig( const std::string &base_path,
                                                         uint16_t           port_seed,
                                                         bool               auto_dht );

        static outcome::result<void> WriteSgnsConfig( const std::string &base_path,
                                                      const std::string &node_type,
                                                      bool               is_processor,
                                                      bool               rpc_catchup = true );

        ~GeniusNode() override;

        enum class NodeState : uint8_t
        {
            CREATING = 0,              
            MIGRATING_DATABASE,        
            INITIALIZING_DATABASE,     
            INITIALIZING_BLOCKCHAIN,   
            INITIALIZING_TRANSACTIONS, 
            INITIALIZING_PROCESSING,   
            READY,                     
        };

        enum class Error : uint8_t
        {
            INSUFFICIENT_FUNDS        = 1,  
            DATABASE_WRITE_ERROR      = 2,  
            INVALID_TRANSACTION_HASH  = 3,  
            INVALID_CHAIN_ID          = 4,  
            INVALID_TOKEN_ID          = 5,  
            TOKEN_ID_MISMATCH         = 6,  
            PROCESS_COST_ERROR        = 7,  
            PROCESS_INFO_MISSING      = 8,  
            INVALID_JSON              = 9,  
            INVALID_BLOCK_PARAMETERS  = 10, 
            NO_PROCESSOR              = 11, 
            NO_PRICE                  = 12, 
            TRANSACTIONS_NOT_READY    = 13, 
            TRANSACTION_NOT_FINALIZED = 14, 
            TRANSACTION_FAILED        = 15, 
            INVALID_NODE_TYPE         = 16, 
        };

        enum class NodeType : uint8_t
        {
            Full    = 0, 
            Light   = 1, 
            Archive = 2, 
        };

#ifdef SGNS_DEBUG
        static constexpr std::chrono::milliseconds TIMEOUT_ESCROW_PAY{ 50000 }; 
        static constexpr std::chrono::milliseconds TIMEOUT_TRANSFER{ 50000 };   
        static constexpr std::chrono::milliseconds TIMEOUT_MINT{ 50000 };       
#else
        static constexpr std::chrono::milliseconds TIMEOUT_ESCROW_PAY{ 30000 }; 
        static constexpr std::chrono::milliseconds TIMEOUT_TRANSFER{ 30000 };   
        static constexpr std::chrono::milliseconds TIMEOUT_MINT{ 30000 };       
#endif
        std::vector<std::string> GetAvailableAccounts();

        uint16_t GetPubsubPort() const noexcept;

        bool IsAutodhtEnabled() const noexcept;

        bool IsFullNode() const noexcept;

        NodeType GetNodeType() const noexcept;

        outcome::result<void> AddAccountWithKey( const char *private_key ) const;

        outcome::result<void> AddAccountWithMnemonic( const std::string &mnemonic ) const;

        outcome::result<std::string> AddAccountWithRandomMnemonic() const;

        outcome::result<void> SelectAccount( std::string_view public_address );

        outcome::result<void> TransferAccount( std::string_view public_address );

        outcome::result<void> DeleteAccount( std::string_view public_address );

        outcome::result<void> MergeAccount( std::string_view public_address );

        outcome::result<void> SetPayoutAddress( std::string_view payout_address );

        outcome::result<std::string> ProcessImage( const std::string &jsondata );

        std::vector<std::string> GetMyTaskIds( size_t limit = 50, size_t offset = 0 ) const;

        outcome::result<SGProcessing::TaskResult> GetTaskResult( const std::string &taskId );

        uint64_t GetProcessCost( std::shared_ptr<sgns::sgprocessing::ProcessingManager> &procmgr );

        static constexpr uint64_t GetBurnBasisPoints()
        {
            return TransactionManager::BURN_BASIS_POINTS;
        }

        static constexpr uint64_t GetBasisPointsTotal()
        {
            return TransactionManager::BASIS_POINTS_TOTAL;
        }

        outcome::result<double> GetGNUSPrice();

        std::string GetName() override
        {
            return "GeniusNode";
        }

        std::string GetVersion();

        void LoadLogConfig();

        outcome::result<std::string> MintTokens( uint64_t           amount,
                                                 const std::string &transaction_hash,
                                                 const std::string &chainid,
                                                 TokenID            tokenid,
                                                 std::string        destination = "" );

        outcome::result<std::pair<std::string, uint64_t>> MintTokens( uint64_t                  amount,
                                                                      const std::string        &transaction_hash,
                                                                      const std::string        &chainid,
                                                                      TokenID                   tokenid,
                                                                      std::string               destination,
                                                                      std::chrono::milliseconds timeout );

        void AddPeer( const std::string &peer );

        void AddPeers( const std::vector<std::string> &peers );

        void RefreshUPNP( uint16_t pubsubport );

        uint64_t GetBalance();

        uint64_t GetBalance( TokenID token_id );

        uint64_t GetBalance( const std::string &address );

        uint64_t GetBalance( TokenID token_id, const std::string &address );

        [[nodiscard]] std::vector<std::vector<uint8_t>> GetInTransactions() const;

        [[nodiscard]] std::vector<std::vector<uint8_t>> GetOutTransactions() const;

        [[nodiscard]] size_t CountTransactions(
            std::optional<TransactionManager::TransactionStatus> tx_status = std::nullopt ) const;

        std::string GetAddress() const;

        std::optional<std::string> GetMnemonicOfActiveAccount() const;

        [[nodiscard]] TokenID GetTokenID() const
        {
            return dev_config_.TokenID;
        }

        [[nodiscard]] std::pair<float, std::string> GetInitializationStatus() const;

        [[nodiscard]] processing::ProcessingServiceImpl::ProcessingStatus GetProcessingStatus() const
        {
            return processing_service_ == nullptr ? processing::ProcessingServiceImpl::ProcessingStatus(
                                                        processing::ProcessingServiceImpl::Status::DISABLED,
                                                        0.0f )
                                                  : processing_service_->GetProcessingStatus();
        }

        outcome::result<std::pair<std::string, uint64_t>> TransferFunds( uint64_t                  amount,
                                                                         const std::string        &destination,
                                                                         TokenID                   token_id,
                                                                         std::chrono::milliseconds timeout );

        outcome::result<std::string> TransferFunds( uint64_t amount, const std::string &destination, TokenID token_id );

        outcome::result<std::string> PayDev( uint64_t amount, TokenID token_id );

        outcome::result<std::pair<std::string, uint64_t>> PayDev( uint64_t                  amount,
                                                                  TokenID                   token_id,
                                                                  std::chrono::milliseconds timeout );

        outcome::result<std::pair<TransactionManager::TransactionStatus, uint64_t>> WaitForFinalized(
            const std::string        &tx_id,
            std::chrono::milliseconds timeout );

        std::optional<TransactionManager::TransactionStatus> IsFinalized( const std::string &tx_id );

        std::shared_ptr<ipfs_pubsub::GossipPubSub> GetPubSub()
        {
            return pubsub_;
        }

        void ResetProcessingMembers();

        outcome::result<std::string> FormatTokens( uint64_t amount, TokenID tokenId );

        outcome::result<uint64_t> ParseTokens( const std::string &str, TokenID tokenId );

        void PrintDataStore() const;

        void StopProcessing();

        void StartProcessing();

        outcome::result<std::map<std::string, double>> GetCoinprice( const std::vector<std::string> &tokenIds );

        outcome::result<std::map<std::string, std::map<int64_t, double>>> GetCoinPriceByDate(
            const std::vector<std::string> &tokenIds,
            const std::vector<int64_t>     &timestamps );

        outcome::result<std::map<std::string, std::map<int64_t, double>>> GetCoinPricesByDateRange(
            const std::vector<std::string> &tokenIds,
            int64_t                         from,
            int64_t                         to );

        TransactionManager::TransactionStatus WaitForTransactionIncoming( const std::string        &txId,
                                                                          std::chrono::milliseconds timeout );

        TransactionManager::TransactionStatus WaitForTransactionOutgoing( const std::string        &txId,
                                                                          std::chrono::milliseconds timeout );

        TransactionManager::TransactionStatus WaitForEscrowRelease( const std::string        &originalEscrowId,
                                                                    std::chrono::milliseconds timeout );

        TransactionManager::State GetTransactionManagerState() const;

        outcome::result<std::shared_ptr<TransactionManager>> GetTransactionManager() const;

        bool ConfigureRpcEndpoint( const std::string &chain_id, std::vector<WeightedRpcEndpoint> endpoints );

        void SetChainlistFetcher( std::function<std::optional<std::string>()> fetcher );

        TransactionManager::TransactionStatus GetTransactionStatus( const std::string &txId ) const;

        void SetAuthorizedFullNodeAddress( const std::string &pub_address );

        std::string GetAuthorizedFullNodeAddress() const;

        NodeState GetState() const
        {
            return state_.load();
        }

    protected:
        friend class TransactionSyncTest;
        friend class MultiAccountTestAccess;
        friend class GeniusNodeTestAccess;

        void SendTransactionAndProof( std::shared_ptr<GeniusTransaction> tx, std::vector<uint8_t> proof );

        std::string                    write_base_path_; 
        std::shared_ptr<GeniusAccount> account_;         

    private:
        std::shared_ptr<boost::asio::io_context> io_; 
        boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
                                                     io_work_guard_;     
        std::shared_ptr<crdt::GlobalDB>              tx_globaldb_;       
        std::shared_ptr<crdt::GlobalDB>              job_globaldb_;      
        std::shared_ptr<ipfs_pubsub::GossipPubSub>   pubsub_;            
        std::shared_ptr<libp2p::event::Bus>          bitswap_event_bus_; 
        std::shared_ptr<sgns::ipfs_bitswap::Bitswap> bitswap_; 
        std::shared_ptr<TransactionManager>          transaction_manager_; 
        std::shared_ptr<MigrationManager> migration_manager_; 
        mutable std::mutex                migration_mutex_;   
        std::shared_ptr<eth::EthWatchService>            eth_watch_service_; 
        std::shared_ptr<BridgeRelayer>                   bridge_relayer_;    
        std::shared_ptr<processing::ProcessingTaskQueue> task_queue_;        
        std::vector<std::string> my_task_ids_; 
        static constexpr size_t  kMyTasksMemoryLimit = 50; 
        std::shared_ptr<processing::ProcessingCoreImpl>       processing_core_;     
        std::shared_ptr<processing::ProcessingServiceImpl>    processing_service_;  
        std::shared_ptr<processing::SubTaskResultStorageImpl> task_result_storage_; 
        std::shared_ptr<soralog::LoggingSystem>               logging_system_;      
        bool                                                  autodht_;     
        bool                                                  isprocessor_; 
        bool     is_full_node_ = false; 
        NodeType node_type_ =
            NodeType::Light; 
        base::Logger     node_logger_;                            
        GeniusNodeConfig dev_config_;                             
        std::string      ipfs_cache_dir_          = "ipfs_cache"; 
        bool             mirror_results_          = false; 
        int              result_retention_hours_  = 168;   
        int              result_retention_max_mb_ = 0;     

        std::vector<ChainContractPair> catchup_chains_; 

        mutable std::mutex catchup_mutex_;
        std::shared_ptr<ChainRpcEndpointProvider>
            rpc_endpoint_provider_; 
        std::shared_ptr<evmwatcher::BridgeCatchupWatcher>
            catchup_watcher_; 
        std::function<std::optional<std::string>()>
            chainlist_fetcher_; 
        std::atomic<uint64_t> bridge_init_generation_{ 0 };
        std::string           gnus_network_full_path_;       
        std::string           processing_channel_topic_;     
        std::string           processing_grid_chanel_topic_; 
        uint16_t              subnet_id_ = 0;                
        bool rpc_catchup_ = true;

        std::vector<std::string>                 bootstrap_peers_;
        std::vector<std::string>                 bootstrap_fullnodes_;
        std::vector<libp2p::peer::PeerInfo>      bootstrap_fullnode_infos_;
        std::unordered_set<libp2p::peer::PeerId> bootstrap_fullnode_ids_;
        std::vector<libp2p::peer::PeerInfo>      bootstrap_peer_infos_;
        std::unordered_set<libp2p::peer::PeerId> bootstrap_peer_ids_;
        uint16_t                                 pubsubport_; 
        std::shared_ptr<Blockchain>              blockchain_; 

        std::shared_ptr<boost::asio::steady_timer> gc_timer_; 

        GeniusNode( const GeniusNodeConfig &dev_config, AccountSource source );

        void InitOpenSSL();

        void LoadSgnsConfig();

        void StartResultGC();

        void RunResultGC();

        bool InitLoggers( const std::string &base_path );

        base::Logger ConfigureLogger( const std::string        &tag,
                                      const std::string        &logdir,
                                      spdlog::level::level_enum level );

        bool InitNetwork( uint16_t port_seed, bool is_full_node );

        void LoadCrdtConfig();

        bool InitUPNP();

        bool InitDatabase();

        bool InitProcessingModules();

        void BeginDBInitialization();

        void StateTransition( NodeState next_state );

        void MigrateDatabase( std::function<void( outcome::result<void> )> callback );

        void ScheduleMigrationRetry();

        void ScheduleBlockchainRetry( std::chrono::seconds delay = std::chrono::seconds( 5 ) );

        std::filesystem::path ResolveBridgeChainsConfigPath() const;

        void InitializeAndStartBridge();

        void OnRpcEndpointsReady( std::vector<ChainContractPair> chains ) override;

        void ShutdownForDestruction();

        outcome::result<void> ShutdownAccountBoundServices( bool deconfigure_account,
                                                            bool release_members = true );

        void ReleaseRuntimeMembersAfterIoStopped();

        outcome::result<std::shared_ptr<crdt::AtomicTransaction>> CreateEscrowInfoCRDTTransaction(
            std::string        path,
            sgns::base::Buffer value );

        void DHTInit();

        static boost::optional<libp2p::peer::PeerInfo> ParsePeerInfoFromString( const std::string &multiaddr_str );

        void ConnectPeer( std::string peer, libp2p::peer::PeerInfo peer_info, unsigned attempt );

        void InitBootstrapReconnect();

        void StartBootstrapHealthCheck();

        void ScheduleBootstrapReconnect( const libp2p::peer::PeerId &peer_id, unsigned attempt );

        void DoReconnectToBootstrapPeer( const libp2p::peer::PeerId &peer_id );

        void ScheduleNextHealthCheck();

        void PerformHealthCheck();

        struct PriceInfo
        {
            double                                             price;      
            std::chrono::time_point<std::chrono::system_clock> lastUpdate; 
        };

        std::map<std::string, PriceInfo>                   m_tokenPriceCache; 
        const std::chrono::minutes                         m_cacheValidityDuration{ 1 }; 
        std::chrono::time_point<std::chrono::system_clock> m_lastApiCall{}; 
        static constexpr std::chrono::seconds              MIN_API_CALL_INTERVAL{ 5 }; 

        static constexpr size_t                   DEFAULT_IO_THREADS = 4;                 
        size_t                                    io_thread_count_{ DEFAULT_IO_THREADS }; 
        std::vector<std::thread>                  io_threads_;                            
        std::thread                               upnp_thread;        
        std::atomic<bool>                         stop_upnp{ false }; 
        std::string                               base58key_;                       
        std::shared_ptr<libp2p::basic::Scheduler> scheduler_;                       
        std::shared_ptr<ipfs_lite::ipfs::graphsync::RequestIdGenerator> generator_; 
        std::shared_ptr<ipfs_lite::ipfs::graphsync::Network>            graphsyncnetwork_; 

        std::atomic<NodeState> state_{ NodeState::CREATING }; 
        std::atomic_bool       shutdown_started_{ false };    

        // ── Bootstrap fullnode reconnection ──
        struct BootstrapReconnectConfig
        {
            std::chrono::seconds base_delay{ 5 };
            std::chrono::seconds max_delay{ 300 };
            std::chrono::seconds health_check_interval{ 60 };
            std::chrono::seconds health_check_disconnected_interval{ 15 };
            double               background_multiplier{ 3.0 };
        };

        BootstrapReconnectConfig                           reconnect_config_;
        std::optional<libp2p::event::Handle>               bootstrap_disconnect_subscription_;
        std::optional<libp2p::basic::Scheduler::Handle>    health_check_handle_;
        std::unordered_map<libp2p::peer::PeerId, unsigned> reconnect_attempts_;
        std::mutex                                         reconnect_mutex_;

        crdt::GlobalDB::BackupOptions crdt_backup_config_{ true, 15, 12, true };

        void ProcessingDone( const std::string &task_id, const SGProcessing::TaskResult &taskresult );

        void ProcessingError( const std::string &task_id );

        void RotateLogFiles( const std::string &base_path );

        outcome::result<uint64_t> ParseBlockSize( const std::string &json_data );

        void TransactionStateChanged( TransactionManager::State old_state, TransactionManager::State new_state );

        static constexpr std::string_view DB_PATH         = "bc-%d/"; 
        static constexpr std::uint16_t    MAIN_NET        = 369;      
        static constexpr std::uint16_t    TEST_NET        = 963;      
        static constexpr std::size_t      MAX_NODES_COUNT = 1;        

        static constexpr std::string_view PROCESSING_GRID_CHANNEL = "SGNUS.Jobs.Channel";  
        static constexpr std::string_view PROCESSING_CHANNEL = "SGNUS.Processing.Channel"; 
        static constexpr std::string_view GNUS_NETWORK_PATH  = "SuperGNUSNode.Node";       

        static std::string GetLoggingSystem( const std::string &base_path )
        {
            std::string config( R"(
# ----------------
sinks:
    - name: file
      type: file
      capacity: 1000
      path: [basepath]/sgnslog.log
groups:
    - name: SuperGeniusNode
      sink: file
      level: error
      children:
        - name: libp2p
        - name: Gossip
        - name: yx-stream
# ----------------
  )" );

            boost::replace_all( config, "[basepath]", base_path );
            return config;
        }

        std::string MyTasksFilePath() const;

        void LoadMyTaskIds();

        void PersistMyTaskIds();
    };
}

OUTCOME_HPP_DECLARE_ERROR_2( sgns, GeniusNode::Error );

#endif

Updated on 2026-08-06 at 13:59:19 +0000