Skip to content

securecrdt/SecureCrdt.hpp

Mandatory wrapper (D-03) for writing to a registered CRDT key and the reader-side logic (D-04) that always re-derives trust from base_key + sig/<addr> children rather than trusting any "final" marker. This is the ONLY sanctioned write entry point for keys registered via SecureCrdtRegistry. More...

Namespaces

Name
sgns
sgns::securecrdt

Classes

Name
class sgns::securecrdt::SecureCrdt
Mandatory wrapper for reading/writing registered SecureCrdt keys.

Functions

Name
OUTCOME_HPP_DECLARE_ERROR_2(sgns::securecrdt , SecureCrdt::Error )

Detailed Description

Mandatory wrapper (D-03) for writing to a registered CRDT key and the reader-side logic (D-04) that always re-derives trust from base_key + sig/<addr> children rather than trusting any "final" marker. This is the ONLY sanctioned write entry point for keys registered via SecureCrdtRegistry.

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

Functions Documentation

function OUTCOME_HPP_DECLARE_ERROR_2

OUTCOME_HPP_DECLARE_ERROR_2(
    sgns::securecrdt ,
    SecureCrdt::Error 
)

Source code

#ifndef SGNS_SECURECRDT_SECURECRDT_HPP
#define SGNS_SECURECRDT_SECURECRDT_HPP

#include <cstdint>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <unordered_map>

#include "base/buffer.hpp"
#include "base/logger.hpp"
#include "crdt/crdt_data_filter.hpp"
#include "crdt/globaldb/globaldb.hpp"
#include "crdt/hierarchical_key.hpp"
#include "crdt/proto/delta.pb.h"
#include "outcome/outcome.hpp"
#include "securecrdt/SecureCrdtRegistry.hpp"

namespace sgns::securecrdt
{
    class SecureCrdt : public std::enable_shared_from_this<SecureCrdt>
    {
    public:
        enum class Error : uint8_t
        {
            UNREGISTERED_KEY = 0,         
            NO_VALUE_PROPOSED,            
            INVALID_SIGNATURE,            
            UNAUTHORIZED_SIGNER,          
            SIGNATURE_LIMIT_EXCEEDED,     
            MALFORMED_VALUE,              
            QUORUM_THRESHOLD_BELOW_FLOOR, 
            UNREGISTERED_CANDIDATE_DOMAIN,
            CANDIDATE_CONTEXT_MISMATCH,
            UNAUTHORIZED_CANDIDATE_SIGNER,
            CANDIDATE_LIMIT_EXCEEDED,
            DUPLICATE_CANDIDATE_APPROVAL,
            CANDIDATE_AUTHORIZATION_PENDING, 
        };

        using CandidateCallback = std::function<void( const CandidateId &, const CandidateApprovalRecord & )>;

        SecureCrdt( std::shared_ptr<sgns::crdt::GlobalDB> db,
                    std::string                           topic,
                    std::shared_ptr<SecureCrdtRegistry>   registry = nullptr );

        SecureCrdtRegistry &Registry();

        outcome::result<void> ProposeValue( const sgns::crdt::HierarchicalKey &base_key,
                                            const std::vector<uint8_t>        &payload );

        outcome::result<void> AddSignature( const sgns::crdt::HierarchicalKey &base_key,
                                            const std::string                 &signer_address,
                                            const std::vector<uint8_t>        &signature );

        outcome::result<std::optional<sgns::base::Buffer>> ReadIfQuorum( const sgns::crdt::HierarchicalKey &base_key );

        outcome::result<CandidateId> SubmitCandidateApproval( const CandidateApprovalRecord &record );
        outcome::result<std::vector<CandidateApprovalRecord>> ReadCandidateApprovals( const CandidateId &id );
        outcome::result<std::vector<CandidateId>>             ListCandidates( const std::string &domain,
                                                                              const std::string &predecessor_hash,
                                                                              bool               current_only = true );
        // owner_token is an opaque identity key: stored and compared by address only,
        // never dereferenced. Callers may pass any pointer whose lifetime covers the
        // registration (e.g. `this`) — SecureCrdt does not take ownership of it.
        bool                                                  RegisterCandidateCallback( const std::string &domain,
                                                                                         CandidateCallback  callback,
                                                                                         const void        *owner_token );
        void UnregisterCandidateCallbackIf( const std::string &domain, const void *owner_token );

        bool RegisterFilters();

        void UnregisterFiltersFor( const std::string &escaped_base_key );

    private:
        std::optional<std::vector<sgns::crdt::pb::Element>> FilterSecureCrdtUpdate(
            const sgns::crdt::HierarchicalKey &base_key,
            const SecureCrdtRegistryEntry     &entry,
            const sgns::crdt::pb::Element     &element );

        outcome::result<SignerSetSnapshot> ResolveLegacySignerSnapshot(
            const SecureCrdtRegistryEntry             &entry,
            const sgns::crdt::HierarchicalKey         &base_key,
            const std::optional<std::string_view>     &claimed_address = std::nullopt ) const;
        using LegacySignatures = std::vector<std::pair<std::string, std::vector<uint8_t>>>;
        outcome::result<LegacySignatures> RetainAuthorizedLegacySignatures(
            const sgns::crdt::HierarchicalKey &base_key,
            const SignerSetSnapshot           &snapshot );

        outcome::result<CandidateApprovalRecord> ValidateCandidateApproval( const sgns::crdt::HierarchicalKey &key,
                                                                            const std::vector<uint8_t>        &bytes,
                                                                            bool check_duplicate );
        sgns::crdt::CRDTDataFilter::ElementFilterResult FilterCandidateApproval(
            const sgns::crdt::pb::Element &element );
        void OnCandidateApproval( const std::string &domain, const std::pair<std::string, sgns::base::Buffer> &data );

        struct CandidateCallbackEntry
        {
            CandidateCallback callback;
            const void       *owner_token = nullptr;
        };

        std::shared_ptr<sgns::crdt::GlobalDB>                   db_;
        std::string                                             topic_;
        std::shared_ptr<SecureCrdtRegistry>                     registry_;
        std::mutex                                              candidate_write_mutex_;
        std::mutex                                              candidate_callbacks_mutex_;
        std::unordered_map<std::string, CandidateCallbackEntry> candidate_callbacks_;
        sgns::base::Logger                                      logger_ = sgns::base::createLogger( "SecureCrdt" );
    };
} // namespace sgns::securecrdt

OUTCOME_HPP_DECLARE_ERROR_2( sgns::securecrdt, SecureCrdt::Error );

#endif // SGNS_SECURECRDT_SECURECRDT_HPP

Updated on 2026-10-06 at 13:34:22 +0000