Skip to content

node/node.cpp

Source code

#include "node.hpp"
#include "node.hpp"
#include "ipfs_lite_store.hpp"
sgns::node::node (sgns::alarm & alarm_a, sgns::node_config const & config_a, sgns::node_flags flags_a) :
config (config_a),
flags (flags_a),
alarm (alarm_a),
store_impl (sgns::make_store ()),
store (*store_impl),
ledger (store, stats, flags_a.generate_cache)
// wallets_store_impl (std::make_unique<sgns::mdb_wallets_store> (application_path_a / "wallets.ldb", config_a.lmdb_config)),
// wallets_store (*wallets_store_impl),
// wallets (wallets_store.init_error (), *this),
{
    check_genesis();
}

std::shared_ptr<sgns::node> sgns::node::shared ()
{
    return shared_from_this ();
}
int sgns::node::store_version ()
{
    auto transaction (store.tx_begin_read ());
    return store.version_get (transaction);
}

void sgns::node::check_genesis() {

    // First do a pass with a read to see if any writing needs doing, this saves needing to open a write lock (and potentially blocking)
    auto is_initialized (false);
    {
        auto transaction (store.tx_begin_read ());
        is_initialized = (store.latest_begin (transaction) != store.latest_end ());
    }

    sgns::genesis genesis;
    if (!is_initialized)
    {
        release_assert (!flags.read_only);
        auto transaction (store.tx_begin_write ({ tables::accounts, tables::cached_counts, tables::confirmation_height, tables::frontiers, tables::open_blocks }));
        // Store was empty meaning we just created it, add the genesis block
        store.initialize (transaction, genesis, ledger.cache);
    }

    if (!ledger.block_exists (genesis.hash ()))
    {
        std::stringstream ss;
        ss << "Genesis block not found. Make sure the node network ID is correct.";
        if (network_params.network.is_beta_network ())
        {
            ss << " Beta network may have reset, try clearing database files";
        }
        auto str = ss.str ();

        // logger.always_log (str);
        std::cerr << str << std::endl;
        std::exit (1);
    }
}

sgns::block_hash sgns::node::latest (sgns::account const & account_a)
{
    auto transaction (store.tx_begin_read ());
    return ledger.latest (transaction, account_a);
}

sgns::uint128_t sgns::node::balance (sgns::account const & account_a)
{
    auto transaction (store.tx_begin_read ());
    return ledger.account_balance (transaction, account_a);
}

std::shared_ptr<sgns::block> sgns::node::block (sgns::block_hash const & hash_a)
{
    auto transaction (store.tx_begin_read ());
    return store.block_get (transaction, hash_a);
}

std::pair<sgns::uint128_t, sgns::uint128_t> sgns::node::balance_pending (sgns::account const & account_a)
{
    std::pair<sgns::uint128_t, sgns::uint128_t> result;
    auto transaction (store.tx_begin_read ());
    result.first = ledger.account_balance (transaction, account_a);
    result.second = ledger.account_pending (transaction, account_a);
    return result;
}

sgns::process_return sgns::node::process (sgns::block & block_a)
{
    auto transaction (store.tx_begin_write ({ tables::accounts, tables::cached_counts, tables::change_blocks, tables::frontiers, tables::open_blocks, tables::pending, tables::receive_blocks, tables::representation, tables::send_blocks, tables::state_blocks }, { tables::confirmation_height }));
    auto result (ledger.process (transaction, block_a));
    return result;
}

// namespace
// {
// class confirmed_visitor : public sgns::block_visitor
// {
// public:
//  confirmed_visitor (sgns::transaction const & transaction_a, sgns::node & node_a, std::shared_ptr<sgns::block> const & block_a, sgns::block_hash const & hash_a) :
//  transaction (transaction_a),
//  node (node_a),
//  block (block_a),
//  hash (hash_a)
//  {
//  }
//  virtual ~confirmed_visitor () = default;
//  void scan_receivable (sgns::account const & account_a)
//  {
//      for (auto i (node.wallets.items.begin ()), n (node.wallets.items.end ()); i != n; ++i)
//      {
//          auto const & wallet (i->second);
//          auto transaction_l (node.wallets.tx_begin_read ());
//          if (wallet->store.exists (transaction_l, account_a))
//          {
//              sgns::account representative;
//              sgns::pending_info pending;
//              representative = wallet->store.representative (transaction_l);
//              auto error (node.store.pending_get (transaction, sgns::pending_key (account_a, hash), pending));
//              if (!error)
//              {
//                  auto node_l (node.shared ());
//                  auto amount (pending.amount.number ());
//                  wallet->receive_async (block, representative, amount, [](std::shared_ptr<sgns::block>) {});
//              }
//              else
//              {
//                  if (!node.store.block_exists (transaction, hash))
//                  {
//                      node.logger.try_log (boost::str (boost::format ("Confirmed block is missing:  %1%") % hash.to_string ()));
//                      debug_assert (false && "Confirmed block is missing");
//                  }
//                  else
//                  {
//                      node.logger.try_log (boost::str (boost::format ("Block %1% has already been received") % hash.to_string ()));
//                  }
//              }
//          }
//      }
//  }
//  void state_block (sgns::state_block const & block_a) override
//  {
//      scan_receivable (block_a.hashables.link);
//  }
//  void send_block (sgns::send_block const & block_a) override
//  {
//      scan_receivable (block_a.hashables.destination);
//  }
//  void receive_block (sgns::receive_block const &) override
//  {
//  }
//  void open_block (sgns::open_block const &) override
//  {
//  }
//  void change_block (sgns::change_block const &) override
//  {
//  }
//  sgns::transaction const & transaction;
//  sgns::node & node;
//  std::shared_ptr<sgns::block> block;
//  sgns::block_hash const & hash;
// };
// }

void sgns::node::receive_confirmed (sgns::transaction const & transaction_a, std::shared_ptr<sgns::block> block_a, sgns::block_hash const & hash_a)
{
    // confirmed_visitor visitor (transaction_a, *this, block_a, hash_a);
    // block_a->visit (visitor);
}

void sgns::node::process_confirmed_data (sgns::transaction const & transaction_a, std::shared_ptr<sgns::block> block_a, sgns::block_hash const & hash_a, sgns::account & account_a, sgns::uint128_t & amount_a, bool & is_state_send_a, sgns::account & pending_account_a)
{
    // Faster account calculation
    account_a = block_a->account ();
    if (account_a.is_zero ())
    {
        account_a = block_a->sideband ().account;
    }
    // Faster amount calculation
    auto previous (block_a->previous ());
    auto previous_balance (ledger.balance (transaction_a, previous));
    auto block_balance (store.block_balance_calculated (block_a));
    if (hash_a != ledger.network_params.ledger.genesis_account)
    {
        amount_a = block_balance > previous_balance ? block_balance - previous_balance : previous_balance - block_balance;
    }
    else
    {
        amount_a = ledger.network_params.ledger.genesis_amount;
    }
    if (auto state = dynamic_cast<sgns::state_block *> (block_a.get ()))
    {
        if (state->hashables.balance < previous_balance)
        {
            is_state_send_a = true;
        }
        pending_account_a = state->hashables.link;
    }
    if (auto send = dynamic_cast<sgns::send_block *> (block_a.get ()))
    {
        pending_account_a = send->hashables.destination;
    }
}

// void sgns::node::process_confirmed (sgns::election_status const & status_a, std::shared_ptr<sgns::election> const & election_a, uint8_t iteration_a)
// {
//  if (status_a.type == sgns::election_status_type::active_confirmed_quorum)
//  {
//      auto block_a (status_a.winner);
//      auto hash (block_a->hash ());
//      if (ledger.block_exists (block_a->type (), hash))
//      {
//          // Pausing to prevent this block being processed before adding to election winner details.
//          confirmation_height_processor.pause ();
//          confirmation_height_processor.add (hash);
//          {
//              active.add_election_winner_details (hash, election_a);
//          }
//          confirmation_height_processor.unpause ();
//      }
//      // Limit to 0.5 * 20 = 10 seconds (more than max block_processor::process_batch finish time)
//      else if (iteration_a < 20)
//      {
//          iteration_a++;
//          std::weak_ptr<sgns::node> node_w (shared ());
//          alarm.add (std::chrono::steady_clock::now () + network_params.node.process_confirmed_interval, [node_w, status_a, iteration_a, election_a]() {
//              if (auto node_l = node_w.lock ())
//              {
//                  node_l->process_confirmed (status_a, election_a, iteration_a);
//              }
//          });
//      }
//  }
// }
void sgns::node::stop ()
{
    if (!stopped.exchange (true))
    {
        // logger.always_log ("Node stopping");
        // write_database_queue.stop ();
        // Cancels ongoing work generation tasks, which may be blocking other threads
        // No tasks may wait for work generation in I/O threads, or termination signal capturing will be unable to call node::stop()
        // distributed_work.stop ();
        // block_processor.stop ();
        // if (block_processor_thread.joinable ())
        // {
        //  block_processor_thread.join ();
        // }
        // aggregator.stop ();
        // vote_processor.stop ();
        // active.stop ();
        // confirmation_height_processor.stop ();
        // network.stop ();
        // if (telemetry)
        // {
        //  telemetry->stop ();
        //  telemetry = nullptr;
        // }
        // if (websocket_server)
        // {
        //  websocket_server->stop ();
        // }
        // bootstrap_initiator.stop ();
        // bootstrap.stop ();
        // port_mapping.stop ();
        // checker.stop ();
        // wallets.stop ();
        // stats.stop ();
        // worker.stop ();
        // work pool is not stopped on purpose due to testing setup
    }
}
sgns::node_flags const & sgns::inactive_node_flag_defaults ()
{
    static sgns::node_flags node_flags;
    node_flags.inactive_node = true;
    node_flags.read_only = true;
    node_flags.generate_cache.reps = false;
    node_flags.generate_cache.cemented_count = false;
    node_flags.generate_cache.unchecked_count = false;
    node_flags.disable_bootstrap_listener = true;
    node_flags.disable_tcp_realtime = true;
    return node_flags;
}

sgns::inactive_node::inactive_node (boost::filesystem::path const & path_a, sgns::node_flags const & node_flags_a) /*:*/
// io_context (std::make_shared<boost::asio::io_context> ()),
// alarm (*io_context),
// work (1)
{
    boost::system::error_code error_chmod;

//  /*
//   * @warning May throw a filesystem exception
//   */
    boost::filesystem::create_directories (path_a);
    sgns::set_secure_perm_directory (path_a, error_chmod);
    // sgns::daemon_config daemon_config (path_a);
    // auto error = sgns::read_node_config_toml (path_a, daemon_config, node_flags_a.config_overrides);
    // if (error)
    // {
    //  std::cerr << "Error deserializing config file";
    //  if (!node_flags_a.config_overrides.empty ())
    //  {
    //      std::cerr << " or --config option";
    //  }
    //  std::cerr << "\n"
    //            << error.get_message () << std::endl;
    //  std::exit (1);
    // }

    // auto & node_config = daemon_config.node;
    // node_config.peering_port = sgns::get_available_port ();
    // node_config.logging.max_size = std::numeric_limits<std::uintmax_t>::max ();
    // node_config.logging.init (path_a);

    // node = std::make_shared<sgns::node> (alarm, node_config, work, node_flags_a);
    // node->active.stop ();
}

sgns::inactive_node::~inactive_node ()
{
    node->stop ();
}

std::unique_ptr<sgns::block_store> sgns::make_store ()
{
    return std::make_unique<sgns::ipfs_lite_store> ();
}

Updated on 2026-03-04 at 13:10:44 -0800