16        std::unique_lock<std::shared_mutex> l(m_mut);
 
   17        bool running = m_running;
 
   19            m_applied_dtxs.erase(dtx_id);
 
 
   25        const std::pair<uint8_t, uint8_t>& output_range,
 
   26        std::shared_ptr<logging::log> logger,
 
   27        size_t completed_txs_cache_size,
 
   28        const std::string& preseed_file,
 
   31          m_logger(std::move(logger)),
 
   32          m_completed_txs(completed_txs_cache_size),
 
   33          m_opts(std::move(opts)) {
 
   34        m_uhs.max_load_factor(std::numeric_limits<float>::max());
 
   35        m_applied_dtxs.max_load_factor(std::numeric_limits<float>::max());
 
   36        m_prepared_dtxs.max_load_factor(std::numeric_limits<float>::max());
 
   37        m_locked.max_load_factor(std::numeric_limits<float>::max());
 
   39        static constexpr auto dtx_buckets = 100000;
 
   40        m_applied_dtxs.rehash(dtx_buckets);
 
   41        m_prepared_dtxs.rehash(dtx_buckets);
 
   43        static constexpr auto locked_buckets = 10000000;
 
   44        m_locked.rehash(locked_buckets);
 
   46        if(!preseed_file.empty()) {
 
   47            m_logger->info(
"Reading preseed file into memory");
 
   48            if(!read_preseed_file(preseed_file)) {
 
   49                m_logger->error(
"Preseeding failed");
 
   51                m_logger->info(
"Preseeding complete -", m_uhs.size(), 
"utxos");
 
 
   56    auto locking_shard::read_preseed_file(
const std::string& preseed_file)
 
   58        if(std::filesystem::exists(preseed_file)) {
 
   59            auto in = std::ifstream(preseed_file, std::ios::binary);
 
   60            in.seekg(0, std::ios::end);
 
   65            in.seekg(0, std::ios::beg);
 
   66            auto deser = istream_serializer(in);
 
   68            static constexpr auto uhs_size_factor = 2;
 
   69            auto bucket_count = 
static_cast<unsigned long>(sz / cbdc::hash_size
 
   71            m_uhs.rehash(bucket_count);
 
   78    auto locking_shard::lock_outputs(std::vector<tx>&& txs,
 
   80        -> std::optional<std::vector<bool>> {
 
   81        std::unique_lock<std::shared_mutex> l(m_mut);
 
   86        auto prepared_dtx_it = m_prepared_dtxs.find(dtx_id);
 
   87        if(prepared_dtx_it != m_prepared_dtxs.end()) {
 
   88            return prepared_dtx_it->second.m_results;
 
   91        auto ret = std::vector<bool>();
 
   92        ret.reserve(txs.size());
 
   93        for(
auto&& 
tx : txs) {
 
   94            auto success = check_and_lock_tx(
tx);
 
   95            ret.push_back(success);
 
   97        auto p = prepared_dtx();
 
   99        p.m_txs = std::move(txs);
 
  100        m_prepared_dtxs.emplace(dtx_id, std::move(p));
 
 
  104    auto locking_shard::check_and_lock_tx(
const tx& t) -> 
bool {
 
  108               m_opts.m_sentinel_public_keys,
 
  109               m_opts.m_attestation_threshold)) {
 
  110            m_logger->warn(
"Received invalid compact transaction",
 
  115            for(
const auto& uhs_id : t.m_tx.m_inputs) {
 
  116                if(hash_in_shard_range(uhs_id)
 
  117                   && m_uhs.find(uhs_id) == m_uhs.end()) {
 
  124            for(
const auto& uhs_id : t.m_tx.m_inputs) {
 
  126                    auto n = m_uhs.extract(uhs_id);
 
  128                    m_locked.emplace(uhs_id);
 
  135    auto locking_shard::apply_outputs(std::vector<bool>&& complete_txs,
 
  136                                      const hash_t& dtx_id) -> 
bool {
 
  137        std::unique_lock<std::shared_mutex> l(m_mut);
 
  141        auto prepared_dtx_it = m_prepared_dtxs.find(dtx_id);
 
  142        if(prepared_dtx_it == m_prepared_dtxs.end()) {
 
  143            if(m_applied_dtxs.find(dtx_id) == m_applied_dtxs.end()) {
 
  144                m_logger->fatal(
"Unable to find dtx data for apply",
 
  149        auto& dtx = prepared_dtx_it->second.m_txs;
 
  150        if(complete_txs.size() != dtx.size()) {
 
  152            m_logger->fatal(
"Incorrect number of complete tx flags for apply",
 
  158        for(
size_t i{0}; i < dtx.size(); i++) {
 
  165                if(hash_in_shard_range(uhs_id) && complete_txs[i]) {
 
  166                    m_uhs.emplace(uhs_id);
 
  170                if(hash_in_shard_range(uhs_id)) {
 
  171                    auto was_locked = m_locked.erase(uhs_id);
 
  172                    if(!complete_txs[i] && (was_locked != 0U)) {
 
  173                        m_uhs.emplace(uhs_id);
 
  179        m_prepared_dtxs.erase(dtx_id);
 
  180        m_applied_dtxs.insert(dtx_id);
 
 
  184    void locking_shard::stop() {
 
 
  188    auto locking_shard::check_unspent(
const hash_t& uhs_id)
 
  189        -> std::optional<bool> {
 
  190        std::shared_lock<std::shared_mutex> l(m_mut);
 
  191        return m_uhs.find(uhs_id) != m_uhs.end()
 
  192            || m_locked.find(uhs_id) != m_locked.end();
 
 
  195    auto locking_shard::check_tx_id(
const hash_t& tx_id)
 
  196        -> std::optional<bool> {
 
  197        return m_completed_txs.contains(tx_id);
 
 
Interface for a locking shard.
auto discard_dtx(const hash_t &dtx_id) -> bool final
Discards any cached information about a given distributed transaction.
Tools for reading options from a configuration file and building application-specific parameter sets ...
auto hash_in_shard_range(const shard_range_t &range, const hash_t &val) -> bool
Checks if a hash is in the given range handled.
auto check_attestations(const transaction::compact_tx &tx, const std::unordered_set< pubkey_t, hashing::null > &pubkeys, size_t threshold) -> bool
Validates the sentinel attestations attached to a compact transaction.
std::array< unsigned char, cbdc::hash_size > hash_t
SHA256 hash container.
auto to_string(const hash_t &val) -> std::string
Converts a hash to a hexadecimal string.
Project-wide configuration options.
Transaction type processed by locking shards.
transaction::compact_tx m_tx
Compact TX.
std::vector< hash_t > m_inputs
The set of hashes of the transaction's inputs.
hash_t m_id
The hash of the full transaction returned by tx_id.
std::vector< hash_t > m_uhs_outputs
The set of hashes of the new outputs created in the transaction.