Skip to content

account/GeniusAccount.hpp

Header file of the Genius account class. More...

Namespaces

Name
sgns
sgns::ipfs_pubsub
sgns::crdt
boost::multiprecision

Classes

Name
class sgns::GeniusAccount
struct sgns::GeniusAccount::Credentials

Detailed Description

Header file of the Genius account class.

Date: 2024-03-11 Henrique A. Klein (hklein@gnus.ai)

Source code

#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include <shared_mutex>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <functional>
#include <optional>
#include <set>
#include <storage/rocksdb/rocksdb.hpp>
#include <string_view>

#include <boost/multiprecision/cpp_int.hpp>
#include <boost/filesystem/path.hpp>
#include <WalletCore/PrivateKey.h>

#include <ProofSystem/ElGamalKeyGenerator.hpp>
#include <ProofSystem/EthereumKeyGenerator.hpp>

#include "account/TokenID.hpp"
#include "local_secure_storage/ISecureStorage.hpp"
#include "outcome/outcome.hpp"

#include <unordered_set>

namespace sgns
{
    using namespace boost::multiprecision;

    namespace ipfs_pubsub
    {
        class GossipPubSub;
    }

    namespace crdt
    {
        class GlobalDB;
    }
    class AccountMessenger;
    class TransactionManager;

    class GeniusAccount : public std::enable_shared_from_this<GeniusAccount>
    {
    public:
        using StorageWithAddress = std::pair<std::shared_ptr<ISecureStorage>,
                                             std::pair<KeyGenerator::ElGamal, ethereum::EthereumKeyGenerator>>;

        struct Credentials
        {
            std::string email;
            std::string password;
        };

        static const std::array<uint8_t, 32> ELGAMAL_PUBKEY_PREDEFINED;      
        static constexpr int64_t            NONCE_CACHE_DURATION_MS = 5000; 

        static std::shared_ptr<GeniusAccount> New( TokenID                        token_id,
                                                   const char                    *eth_private_key,
                                                   const boost::filesystem::path &base_path,
                                                   bool                           full_node = false );

        static std::shared_ptr<GeniusAccount> NewFromMnemonic( TokenID                        token_id,
                                                               const std::string             &mnemonic,
                                                               const boost::filesystem::path &base_path,
                                                               bool                           full_node = false );

        static std::shared_ptr<GeniusAccount> New( TokenID                        token_id,
                                                   const boost::filesystem::path &base_path,
                                                   bool                           full_node = false );

        bool InitMessenger( std::shared_ptr<ipfs_pubsub::GossipPubSub> pubsub );

        bool ConfigureDatabaseDependencies( std::shared_ptr<crdt::GlobalDB> global_db );

        void DeconfigureDatabaseDependencies();

        ~GeniusAccount();

        [[nodiscard]] std::string GetAddress() const;

        [[nodiscard]] TokenID GetToken() const;

        [[nodiscard]] std::string GetNonce() const
        {
            return std::to_string( GetProposedNonce() );
        }

        static bool VerifySignature( const std::string          &address,
                                     std::string_view            sig,
                                     const std::vector<uint8_t> &data );

        std::vector<uint8_t> Sign( const std::vector<uint8_t> &data ) const;

        void SetLocalConfirmedNonce( uint64_t nonce );

        void SetPeerConfirmedNonce( uint64_t nonce, const std::string &address );

        void RollBackPeerConfirmedNonce( uint64_t nonce, const std::string &address );

        outcome::result<uint64_t> GetPeerNonce( const std::string &address ) const;

        outcome::result<uint64_t> GetLocalConfirmedNonce() const;

        outcome::result<uint64_t> GetConfirmedNonce( uint64_t timeout_ms ) const;

        outcome::result<std::optional<uint64_t>> FetchNetworkNonce( uint64_t timeout_ms ) const;

        uint64_t GetProposedNonce() const;

        uint64_t ReserveNextNonce();

        void ReleaseNonce( uint64_t nonce );

        outcome::result<void> RequestGenesis(
            uint64_t                                            timeout_ms = 8000,
            std::function<void( outcome::result<std::string> )> callback   = nullptr ) const;
        outcome::result<void> RequestAccountCreation(
            uint64_t                                            timeout_ms,
            std::function<void( outcome::result<std::string> )> callback ) const;
        outcome::result<void> RequestRegularBlock(
            uint64_t                                            timeout_ms,
            const std::string                                  &cid,
            std::function<void( outcome::result<std::string> )> callback = nullptr ) const;
        outcome::result<void> RequestTransaction(
            uint64_t                                            timeout_ms,
            const std::string                                  &tx_hash,
            std::function<void( outcome::result<std::string> )> callback = nullptr ) const;
        outcome::result<std::unordered_set<std::string>> RequestUTXOs( uint64_t           timeout_ms,
                                                                       const std::string &address,
                                                                       uint64_t           silent_time_ms = 150 ) const;
        outcome::result<void> RequestHeads( const std::unordered_set<std::string> &topics ) const;

        static outcome::result<StorageWithAddress> GenerateGeniusAddress( const char *eth_private_key,
                                                                          const boost::filesystem::path &base_path );

        static outcome::result<StorageWithAddress> GenerateGeniusAddress( const TW::PrivateKey          &private_key,
                                                                          const boost::filesystem::path &base_path );

    protected:
        friend class Blockchain;
        friend class TransactionManager;
        void SetGetBlockChainCIDMethod(
            std::function<outcome::result<std::string>( uint8_t, const std::string & )> method );
        void ClearGetBlockChainCIDMethod();
        void SetHasBlockCidMethod( std::function<outcome::result<bool>( const std::string & )> method );
        void ClearHasBlockCidMethod();
        void SetGetUTXOsMethod(
            std::function<outcome::result<std::vector<std::string>>( const std::string & )> method );
        void ClearGetUTXOsMethod();
        void SetGetValidatorWeightMethod(
            std::function<outcome::result<std::optional<uint64_t>>( const std::string & )> method );
        void ClearGetValidatorWeightMethod();
        void SetGetTransactionCIDMethod( std::function<outcome::result<std::string>( const std::string & )> method );
        void ClearGetTransactionCIDMethod();
        void SetNonceStore( std::shared_ptr<storage::rocksdb> db );

    private:
        static constexpr size_t SIGNATURE_EXP_SIZE = 64; 

        static outcome::result<StorageWithAddress> LoadGeniusAccount( const boost::filesystem::path &base_path );

        static std::shared_ptr<GeniusAccount> CreateInstanceFromResponse( TokenID            token_id,
                                                                          StorageWithAddress response_value,
                                                                          bool               full_node );

        TokenID                         token;         
        std::shared_ptr<ISecureStorage> storage_;      
        bool                            is_full_node_; 

        std::shared_ptr<ethereum::EthereumKeyGenerator> eth_keypair_;      
        std::shared_ptr<KeyGenerator::ElGamal>          elgamal_address_;  
        std::unordered_map<std::string, uint64_t>       confirmed_nonces_; 
        mutable std::shared_mutex                       nonce_mutex_;      
        std::set<uint64_t>                              pending_nonces_;   
        std::optional<uint64_t>                         local_confirmed_nonce_; 
        std::shared_ptr<AccountMessenger>               messenger_;             

        // Nonce request tracking
        mutable std::mutex              nonce_request_mutex_; 
        mutable std::condition_variable nonce_request_cv_;    
        mutable bool nonce_request_in_progress_;              
        mutable std::optional<outcome::result<uint64_t>>
            cached_nonce_result_; 
        mutable std::chrono::steady_clock::time_point
                   cached_nonce_timestamp_; 
        std::mutex get_cids_mutex_;         
        std::function<outcome::result<std::string>( uint8_t, const std::string & )>
            get_cids_method_; 
        std::function<outcome::result<bool>( const std::string & )> has_cid_method_; 
        std::function<outcome::result<std::vector<std::string>>( const std::string & )>
            get_utxos_method_; 
        std::function<outcome::result<std::optional<uint64_t>>( const std::string & )>
            get_validator_weight_method_; 
        std::function<outcome::result<std::string>( const std::string & )>
                                          get_transaction_cid_method_; 
        std::shared_ptr<storage::rocksdb> nonce_db_;                   

        static constexpr std::string_view NONCE_KEY_PREFIX = "gnus-confirmed-nonce-";

        void LoadConfirmedNonces();
        void PersistConfirmedNonce( const std::string &address, uint64_t nonce );

        uint64_t GetNextNonceLocked() const;

        GeniusAccount( TokenID token_id, std::shared_ptr<ISecureStorage> storage, bool full_node );
    };
}

Updated on 2026-04-26 at 17:04:52 -0700