diff --git a/flake.nix b/flake.nix index 556887d..750dda3 100644 --- a/flake.nix +++ b/flake.nix @@ -80,6 +80,13 @@ "-DLOGOS_BLOCKCHAIN_INCLUDE=${logosBlockchainC}/include" ]; + # Logos Core Edge-case + # The current version of the (bundler)[https://github.com/logos-co/nix-bundle-dir] does not support + # directories other than `lib/` and `bin/` for bundling. + # Since the circuits' binaries are placed in `share/circuits/`, we need to add a special case so the bundler + # can find them and include them in the final bundle. + extraDirs = [ "share" ]; + postInstall = '' mkdir $out/share cp -r ${logosBlockchainC}/circuits $out/share diff --git a/src/logos_blockchain_module.cpp b/src/logos_blockchain_module.cpp index 54a0fa8..68932d8 100644 --- a/src/logos_blockchain_module.cpp +++ b/src/logos_blockchain_module.cpp @@ -26,6 +26,48 @@ namespace { } } // namespace +namespace environment { + constexpr auto LOGOS_BLOCKCHAIN_CIRCUITS = "LOGOS_BLOCKCHAIN_CIRCUITS"; + + // Checks the directory exists and ensures it contains at least one file to avoid an empty directory false positive + bool isCircuitsPathValid(const QString& path) { + const QDir directory(path); + return directory.exists() && !directory.entryList(QDir::Files | QDir::NoDotAndDotDot).isEmpty(); + } + + // Sets up the LOGOS_BLOCKCHAIN_CIRCUITS environment variable + // This has two side effects: + // - Modifies the environment variable LOGOS_BLOCKCHAIN_CIRCUITS. + // - Terminates the program if no valid circuits directory is found. + void setupCircuitsPath(const LogosAPI& logosApi) { + const QString modulePath = logosApi.property("modulePath").toString(); + const QDir moduleDir(modulePath); + + // Logos Core Edge-case + // Due to Logos Core requiring the circuits' path to be `modulePath/lib/share/circuits`, + // we add an ad-hoc check for this specific case. + const auto logosCorePath = moduleDir.filePath(QStringLiteral("share/circuits")); + if (isCircuitsPathValid(logosCorePath)) { + qputenv(LOGOS_BLOCKCHAIN_CIRCUITS, logosCorePath.toUtf8()); + qInfo() << "Detected Logos Core environment. LOGOS_BLOCKCHAIN_CIRCUITS set to:" << logosCorePath; + return; + } + + // Default + // Our default build system, Nix, packages circuits in a sibling directory to `lib`, + // which is where `modulePath` points to. + const auto defaultPath = moduleDir.filePath(QStringLiteral("../share/circuits")); + if (!isCircuitsPathValid(defaultPath)) { + qFatal() << "Could not find circuits in the default path (" + defaultPath + ")." << "Please set the" + << LOGOS_BLOCKCHAIN_CIRCUITS << "environment variable to a valid path containing the circuits."; + return; + } + + qputenv(LOGOS_BLOCKCHAIN_CIRCUITS, defaultPath.toUtf8()); + qInfo() << "Setting LOGOS_BLOCKCHAIN_CIRCUITS to the default path:" << defaultPath; + } +} // namespace environment + void LogosBlockchainModule::onNewBlockCallback(const char* block) { if (s_instance) { qInfo() << "Received new block: " << block; @@ -72,11 +114,12 @@ int LogosBlockchainModule::start(const QString& config_path, const QString& depl qWarning() << "Could not execute the operation: The node is already running."; return 1; } + if (!logosAPI) { + qCritical() << "LogosAPI instance is null, cannot start node."; + return 2; + } - // Set LOGOS_BLOCKCHAIN_CIRCUITS env variable (use QDir for correct path separator on all platforms) - QString circuits_path = QDir(logosAPI->property("modulePath").toString()).filePath(QStringLiteral("circuits")); - qputenv("LOGOS_BLOCKCHAIN_CIRCUITS", circuits_path.toUtf8()); - qInfo() << "LOGOS_BLOCKCHAIN_CIRCUITS set to:" << circuits_path; + environment::setupCircuitsPath(*logosAPI); QString effective_config_path = config_path; if (effective_config_path.isEmpty()) { @@ -86,7 +129,7 @@ int LogosBlockchainModule::start(const QString& config_path, const QString& depl qInfo() << "Using config from LB_CONFIG_PATH:" << effective_config_path; } else { qCritical() << "Config path was not specified and LB_CONFIG_PATH is not set."; - return 2; + return 3; } } @@ -103,7 +146,7 @@ int LogosBlockchainModule::start(const QString& config_path, const QString& depl qInfo() << "Start node returned with value and error."; if (!is_ok(&error)) { qCritical() << "Failed to start the node. Error:" << error; - return 3; + return 4; } node = value; @@ -112,7 +155,7 @@ int LogosBlockchainModule::start(const QString& config_path, const QString& depl // Subscribe to block events if (!node) { qWarning() << "Could not subcribe to block events: The node is not running."; - return 1; + return 5; } s_instance = this;