diff --git a/.gitignore b/.gitignore index 9fc50df80..5e45c2c9a 100644 --- a/.gitignore +++ b/.gitignore @@ -165,3 +165,12 @@ REGTEST_7776 src/cc/librogue.so src/cc/games/prices src/cc/games/tetris + +# Build artifacts +*~ +*.zip +release-win64/ +src/RandomX/build-linux/ +src/RandomX/build-win64/ +src/wallet-utility.exe +src/.build_target diff --git a/build.sh b/build.sh index d73119a08..2b92de678 100755 --- a/build.sh +++ b/build.sh @@ -5,13 +5,52 @@ set -eu -o pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_TARGET_FILE="$SCRIPT_DIR/src/.build_target" + +# Function to check and clean if target changed +check_and_clean_target() { + local new_target="$1" + local current_target="" + + if [[ -f "$BUILD_TARGET_FILE" ]]; then + current_target=$(cat "$BUILD_TARGET_FILE") + fi + + if [[ -n "$current_target" && "$current_target" != "$new_target" ]]; then + echo "Build target changed from '$current_target' to '$new_target'" + echo "Cleaning old build artifacts to prevent cross-compilation contamination..." + cd "$SCRIPT_DIR" + make distclean 2>/dev/null || true + # Clean leveldb separately as it often causes issues + if [[ -d src/leveldb ]]; then + make -C src/leveldb clean 2>/dev/null || true + fi + echo "Clean complete." + fi + + # Record the new target + echo "$new_target" > "$BUILD_TARGET_FILE" +} + +# Check for --win-release flag for cross-compilation +if [[ "${1:-}" == "--win-release" ]]; then + check_and_clean_target "windows" + shift + ./util/build-win.sh "$@" + exit $? +fi + # run correct build script for detected OS if [[ "$OSTYPE" == "linux-gnu"* ]]; then - ./util/build.sh --disable-tests $@ + check_and_clean_target "linux" + ./util/build.sh --disable-tests "$@" elif [[ "$OSTYPE" == "darwin"* ]]; then - ./util/build-mac.sh --disable-tests $@ + check_and_clean_target "macos" + ./util/build-mac.sh --disable-tests "$@" elif [[ "$OSTYPE" == "msys"* ]]; then - ./util/build-win.sh --disable-tests $@ + check_and_clean_target "windows" + ./util/build-win.sh --disable-tests "$@" #elif [[ "$OSTYPE" == "freebsd"* ]]; then # placeholder else diff --git a/depends/packages/libgmp.mk b/depends/packages/libgmp.mk index 4ec7cde16..296eb75cc 100644 --- a/depends/packages/libgmp.mk +++ b/depends/packages/libgmp.mk @@ -28,7 +28,7 @@ endif #endif define $(package)_config_cmds - $($(package)_autoconf) --host=$(host) --build=$(build) + CC_FOR_BUILD=gcc CXX_FOR_BUILD=g++ $($(package)_autoconf) --host=$(host) --build=$(build) endef ifeq ($(build_os),darwin) diff --git a/doc/CHANGELOG-randomx-optimization.md b/doc/CHANGELOG-randomx-optimization.md new file mode 100644 index 000000000..9361af85b --- /dev/null +++ b/doc/CHANGELOG-randomx-optimization.md @@ -0,0 +1,63 @@ +# Changelog: RandomX Mining Optimization + +## Summary + +Optimizes RandomX miner memory usage by replacing per-thread dataset/cache allocation with a shared `RandomXDatasetManager`. Reduces memory footprint from ~2.3GB × N threads to ~2.3GB total. + +## Problem + +The original RandomX miner implementation allocated a full RandomX dataset (~2GB) and cache (~256MB) for each mining thread. With multiple threads, this quickly exhausted available memory: + +- 4 threads: ~9.2GB +- 8 threads: ~18.4GB +- 16 threads: ~36.8GB + +## Solution + +Implemented a shared `RandomXDatasetManager` that allocates a single dataset and cache, shared by all miner threads via read-only access (explicitly supported by RandomX design). + +## Changes + +### `src/miner.cpp` + +- **Added `RandomXDatasetManager` class:** + - Manages a single shared RandomX cache and dataset. + - Thread-safe key updates using `boost::shared_mutex` (readers-writer lock). + - `Initialize(key)`: Allocates cache and dataset, initializes with key, builds dataset using all CPU cores. + - `UpdateKey(newKey)`: Acquires exclusive lock, reinitializes cache with new key, rebuilds dataset. + - `GetDataset()`: Returns pointer to shared dataset for VM creation. + - `AcquireSharedLock()` / `ReleaseSharedLock()`: Miner threads hold shared lock while hashing to prevent key updates mid-hash. + - `Shutdown()`: Releases all RandomX resources. + +- **Modified `GenerateBitcoins()`:** + - Initializes `RandomXDatasetManager` with initial key before spawning miner threads. + - Calls `Shutdown()` when mining stops. + +- **Modified `RandomXMiner()`:** + - Creates lightweight per-thread VM using shared dataset (`randomx_create_vm(..., manager.GetDataset())`). + - Acquires shared lock before hashing, releases after. + - On key rotation: releases shared lock, calls `manager.UpdateKey()`, reacquires shared lock, recreates VM. + - Cleanup only destroys thread's VM — dataset/cache owned by manager. + +## Memory Usage + +| Threads | Before | After | +|---------|--------|-------| +| 1 | ~2.3GB | ~2.3GB | +| 4 | ~9.2GB | ~2.3GB | +| 8 | ~18.4GB | ~2.3GB | +| 16 | ~36.8GB | ~2.3GB | + +## Thread Safety + +- RandomX dataset is read-only after initialization — safe to share across threads. +- `boost::shared_mutex` ensures: + - Multiple threads can hash concurrently (shared lock). + - Key updates are exclusive (exclusive lock blocks until all shared locks release). + - No thread hashes with stale dataset during key change. + +## Files Modified + +| File | Lines Added | Lines Removed | +|------|-------------|---------------| +| `src/miner.cpp` | ~80 | ~20 | diff --git a/doc/CHANGELOG-randomx-validation.md b/doc/CHANGELOG-randomx-validation.md new file mode 100644 index 000000000..190dde71e --- /dev/null +++ b/doc/CHANGELOG-randomx-validation.md @@ -0,0 +1,95 @@ +# Changelog: RandomX Validation Bug Fix + +## Summary + +Fixes a critical exploit allowing miners on RandomX-based Hush Arrakis Chains (HACs) to bypass RandomX proof-of-work validation entirely. Adds proper RandomX solution verification to the block validation pipeline, fixes the miner's RandomX input construction, and introduces per-chain activation heights. + +## Bug Description + +Three issues combined to allow the bypass: + +1. `CheckEquihashSolution()` returned `true` immediately for non-Equihash chains, never verifying the RandomX solution stored in `nSolution`. +2. `CheckProofOfWork()` checked the standard SHA-256d `GetHash()` against the difficulty target instead of a RandomX hash, allowing miners to brute-force the cheap hash. +3. The miner passed `&randomxInput, sizeof randomxInput` (the address and size of a `CDataStream` struct) to `randomx_calculate_hash()` instead of the actual serialized data, producing non-deterministic hashes. + +A malicious miner could put arbitrary bytes in `nSolution`, iterate nonces until the standard header hash met the target, and the block would pass all validation — completely bypassing RandomX CPU-hardness. + +## Changes + +### `src/primitives/block.h` + +- Added `CRandomXInput` class (modeled after `CEquihashInput`) that serializes the block header **including `nNonce`** but **excluding `nSolution`**, providing deterministic and reproducible input for RandomX hashing. + +### `src/hush_globals.h` + +- Added `int32_t ASSETCHAINS_RANDOMX_VALIDATION = -1` global variable to hold the per-chain activation height (`-1` = disabled). + +### `src/hush_defs.h` + +- Added `extern int32_t ASSETCHAINS_RANDOMX_VALIDATION` declaration. + +### `src/pow.h` + +- Added declaration for `bool CheckRandomXSolution(const CBlockHeader *pblock, int32_t height)`. +- Added declarations for `int GetRandomXInterval()` and `int GetRandomXBlockLag()` (moved from `miner.cpp`). + +### `src/pow.cpp` + +- Added `#include "RandomX/src/randomx.h"` and `#include `. +- Moved `GetRandomXInterval()` and `GetRandomXBlockLag()` definitions here from `miner.cpp` so they are accessible from both the miner and the validator. +- Implemented `CheckRandomXSolution()`: + - Returns `true` immediately for non-RandomX chains, pre-activation heights, and when `HUSH_LOADINGBLOCKS != 0`. + - Validates `nSolution` is exactly `RANDOMX_HASH_SIZE` (32) bytes. + - Derives the correct RandomX key for the given height (initial key from chain params, or block-hash key after rotation interval). + - Serializes the block header via `CRandomXInput` into a `CDataStream`. + - Calls `randomx_calculate_hash()` with the correct data pointer (`&ss[0]`) and size (`ss.size()`). + - Compares the computed hash against `pblock->nSolution`. + - Caches the RandomX VM and cache between calls (protected by mutex), re-initializing only when the key changes. + +### `src/main.cpp` + +- In `CheckBlockHeader()`: added `CheckRandomXSolution()` call inside the `fCheckPOW` block, after the existing `CheckEquihashSolution()` call. Invalid RandomX solutions are rejected with `DoS(100)`. + +### `src/hush_bitcoind.h` + +- Added `#include "pow.h"`. +- In `hush_checkPOW()`: added `CheckRandomXSolution()` call after the existing `CheckEquihashSolution()` call. + +### `src/miner.cpp` + +- Changed `GetRandomXInterval()` and `GetRandomXBlockLag()` from inline definitions to forward declarations (definitions moved to `pow.cpp`). +- Fixed RandomX input construction in `RandomXMiner()`: + - Uses `CRandomXInput` to serialize the block header without `nSolution` (instead of serializing the entire block). + - Passes `&randomxInput[0], randomxInput.size()` to `randomx_calculate_hash()` (instead of `&randomxInput, sizeof randomxInput`). +- Added `SetSkipRandomXValidation(true/false)` around `TestBlockValidity()` to avoid double-validation OOM. +- Added null-checks before `randomx_destroy_vm()` to prevent double-free crashes. + +### `src/hush_utils.h` + +- After `ASSETCHAINS_ALGO` and `SMART_CHAIN_SYMBOL` are set during chain initialization, sets `ASSETCHAINS_RANDOMX_VALIDATION` per chain: + - `DRAGONX`: `1` (TBD: set to coordinated upgrade height) + - `TUMIN`: `1` (TBD: set to coordinated upgrade height) + - All other RandomX HACs: `1` (enforced from height 1) + - Non-RandomX chains: remains `-1` (disabled) + +## Activation Heights + +| Chain | Height | Notes | +|-------|--------|-------| +| DRAGONX | TBD | Existing chain, needs coordinated upgrade | +| TUMIN | TBD | Existing chain, needs coordinated upgrade | +| All other RandomX HACs | 1 | Enforced from genesis+1 | + +## Files Modified + +| File | Lines Added | Lines Removed | +|------|-------------|---------------| +| `src/primitives/block.h` | ~20 | 0 | +| `src/hush_globals.h` | 1 | 0 | +| `src/hush_defs.h` | 1 | 0 | +| `src/pow.h` | 9 | 0 | +| `src/pow.cpp` | ~105 | 0 | +| `src/main.cpp` | 2 | 0 | +| `src/hush_bitcoind.h` | 6 | 0 | +| `src/miner.cpp` | 5 | 5 | +| `src/hush_utils.h` | 10 | 0 | diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 000000000..609cc5929 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +.build_target diff --git a/src/Makefile.am b/src/Makefile.am index d6ed7eb41..c5697ba3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,16 +38,7 @@ BITCOIN_INCLUDES += -I$(srcdir)/cc/includes BITCOIN_INCLUDES += -I$(srcdir)/univalue/include BITCOIN_INCLUDES += -I$(srcdir)/leveldb/include -if TARGET_WINDOWS -LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl -endif -if TARGET_DARWIN -LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl -endif -if TARGET_LINUX -LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl -endif - +LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a @@ -57,7 +48,11 @@ LIBSECP256K1=secp256k1/libsecp256k1.la LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a LIBHUSH=libhush.a -LIBRANDOMX=RandomX/build/librandomx.a +if TARGET_WINDOWS +LIBRANDOMX=RandomX/build-win64/librandomx.a +else +LIBRANDOMX=RandomX/build-linux/librandomx.a +endif if BUILD_BITCOIN_LIBS LIBZCASH_CONSENSUS=libzcashconsensus.la @@ -489,6 +484,13 @@ hushd_LDADD += \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) +if TARGET_WINDOWS +hushd_LDADD += -lcurl -lwldap32 +endif +if !TARGET_WINDOWS +hushd_LDADD += -lcurl +endif + if TARGET_DARWIN hushd_LDADD += libcc.dylib $(LIBSECP256K1) endif diff --git a/src/miner.cpp b/src/miner.cpp index 5f6abe654..ad08a1dcb 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -23,6 +23,7 @@ #include "pow/tromp/equi_miner.h" #endif +#include #include "amount.h" #include "chainparams.h" #include "consensus/consensus.h" @@ -1015,6 +1016,56 @@ enum RandomXSolverCancelCheck int GetRandomXInterval(); int GetRandomXBlockLag(); +#ifdef _WIN32 +#include +static void LogProcessMemory(const char* label) { + // Use K32GetProcessMemoryInfo from kernel32.dll (available on Win7+) + // to avoid linking psapi.lib + typedef struct { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; + } PMC_EX; + typedef BOOL (WINAPI *PFN)(HANDLE, PMC_EX*, DWORD); + static PFN pfn = (PFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "K32GetProcessMemoryInfo"); + if (pfn) { + PMC_EX pmc = {}; + pmc.cb = sizeof(pmc); + if (pfn(GetCurrentProcess(), &pmc, sizeof(pmc))) { + LogPrintf("MemDiag [%s]: WorkingSet=%.1fMB, PrivateUsage=%.1fMB, PagefileUsage=%.1fMB\n", + label, + pmc.WorkingSetSize / (1024.0 * 1024.0), + pmc.PrivateUsage / (1024.0 * 1024.0), + pmc.PagefileUsage / (1024.0 * 1024.0)); + } + } +} +#else +static void LogProcessMemory(const char* label) { + // Linux: read /proc/self/status + FILE *f = fopen("/proc/self/status", "r"); + if (f) { + char line[256]; + while (fgets(line, sizeof(line), f)) { + if (strncmp(line, "VmRSS:", 6) == 0 || strncmp(line, "VmSize:", 7) == 0) { + // Remove newline + line[strlen(line)-1] = '\0'; + LogPrintf("MemDiag [%s]: %s\n", label, line); + } + } + fclose(f); + } +} +#endif + // Shared RandomX dataset manager — all miner threads share a single ~2GB dataset // instead of each allocating their own. The dataset is read-only after initialization // and RandomX explicitly supports multiple VMs sharing one dataset. @@ -1036,6 +1087,12 @@ struct RandomXDatasetManager { if (initialized) return true; flags |= RANDOMX_FLAG_FULL_MEM; + LogPrintf("RandomXDatasetManager: flags=0x%x (JIT=%d, HARD_AES=%d, FULL_MEM=%d, LARGE_PAGES=%d)\n", + (int)flags, + !!(flags & RANDOMX_FLAG_JIT), !!(flags & RANDOMX_FLAG_HARD_AES), + !!(flags & RANDOMX_FLAG_FULL_MEM), !!(flags & RANDOMX_FLAG_LARGE_PAGES)); + + LogProcessMemory("before cache alloc"); cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_SECURE); if (cache == nullptr) { @@ -1043,25 +1100,39 @@ struct RandomXDatasetManager { cache = randomx_alloc_cache(flags | RANDOMX_FLAG_SECURE); if (cache == nullptr) { LogPrintf("RandomXDatasetManager: cache alloc failed with secure, trying basic...\n"); + cache = randomx_alloc_cache(flags); + if (cache == nullptr) { + LogPrintf("RandomXDatasetManager: cannot allocate cache!\n"); + return false; + } } - cache = randomx_alloc_cache(flags); - if (cache == nullptr) { - LogPrintf("RandomXDatasetManager: cannot allocate cache!\n"); + } + LogProcessMemory("after cache alloc"); + + // Try to allocate dataset with large pages first for better performance + dataset = randomx_alloc_dataset(flags | RANDOMX_FLAG_LARGE_PAGES); + if (dataset == nullptr) { + LogPrintf("RandomXDatasetManager: dataset alloc failed with large pages, trying without...\n"); + dataset = randomx_alloc_dataset(flags); + if (dataset == nullptr) { + LogPrintf("RandomXDatasetManager: cannot allocate dataset!\n"); + randomx_release_cache(cache); + cache = nullptr; return false; } } - dataset = randomx_alloc_dataset(flags); - if (dataset == nullptr) { - LogPrintf("RandomXDatasetManager: cannot allocate dataset!\n"); - randomx_release_cache(cache); - cache = nullptr; - return false; - } - datasetItemCount = randomx_dataset_item_count(); initialized = true; - LogPrintf("RandomXDatasetManager: allocated shared cache + dataset (%lu items)\n", datasetItemCount); + LogProcessMemory("after dataset alloc"); + // Log the actual memory addresses to help diagnose sharing issues + uint8_t *datasetMemory = (uint8_t*)randomx_get_dataset_memory(dataset); + size_t datasetSize = datasetItemCount * RANDOMX_DATASET_ITEM_SIZE; + LogPrintf("RandomXDatasetManager: allocated shared dataset:\n"); + LogPrintf(" - Dataset struct at: %p\n", (void*)dataset); + LogPrintf(" - Dataset memory at: %p (size: %.2f GB)\n", (void*)datasetMemory, datasetSize / (1024.0 * 1024.0 * 1024.0)); + LogPrintf(" - Items: %lu, Item size: %d bytes\n", datasetItemCount, RANDOMX_DATASET_ITEM_SIZE); + LogPrintf(" - Expected total process memory: ~%.2f GB + ~2MB per mining thread\n", datasetSize / (1024.0 * 1024.0 * 1024.0)); return true; } @@ -1104,12 +1175,24 @@ struct RandomXDatasetManager { randomx_init_dataset(dataset, cache, 0, datasetItemCount); } LogPrintf("RandomXDatasetManager: dataset rebuilt\n"); + LogProcessMemory("after dataset init"); } // Creates a per-thread VM using the shared dataset. // Caller must hold a shared lock on datasetMtx. + // The VM itself is small (~2MB scratchpad) - the 2GB dataset is shared via pointer. randomx_vm *CreateVM() { - return randomx_create_vm(flags, nullptr, dataset); + static std::atomic vmCount{0}; + LogProcessMemory("before CreateVM"); + randomx_vm *vm = randomx_create_vm(flags, nullptr, dataset); + if (vm != nullptr) { + int id = ++vmCount; + uint8_t *datasetMemory = (uint8_t*)randomx_get_dataset_memory(dataset); + LogPrintf("RandomXDatasetManager: VM #%d created - VM at %p, shared dataset memory at %p\n", + id, (void*)vm, (void*)datasetMemory); + LogProcessMemory("after CreateVM"); + } + return vm; } void Shutdown() { diff --git a/src/pow.cpp b/src/pow.cpp index e7ae2804b..8c637a213 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -339,6 +339,20 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead memset(zflags,0,sizeof(zflags)); if ( pindexLast != 0 ) height = (int32_t)pindexLast->GetHeight() + 1; + + // One-time difficulty reset after RandomX validation fix. + // The exploit inflated difficulty to ~40B using cheap SHA-256d hashes. + // Reset to minimum for nPowAveragingWindow blocks so the DAA can + // recalibrate based on real RandomX block times. + if (ASSETCHAINS_RANDOMX_VALIDATION > 0 && height > 0) { + int resetEnd = ASSETCHAINS_RANDOMX_VALIDATION + params.nPowAveragingWindow; + if (height >= ASSETCHAINS_RANDOMX_VALIDATION && height < resetEnd) { + LogPrintf("%s: RandomX difficulty reset at height %d (reset window %d to %d)\n", + __func__, height, ASSETCHAINS_RANDOMX_VALIDATION, resetEnd - 1); + return nProofOfWorkLimit; + } + } + if ( ASSETCHAINS_ADAPTIVEPOW > 0 && pindexFirst != 0 && pblock != 0 && height >= (int32_t)(sizeof(ct)/sizeof(*ct)) ) { tipdiff = (pblock->nTime - pindexFirst->nTime); diff --git a/util/build-win.sh b/util/build-win.sh index f3498530e..2f4b4809c 100755 --- a/util/build-win.sh +++ b/util/build-win.sh @@ -25,14 +25,14 @@ echo $PWD ./makecustom cd $WD -# Build RandomX +# Build RandomX for Windows cd src/RandomX -if [ -d "build" ] +if [ -f "build-win64/librandomx.a" ] then - ls -la build/librandomx* + ls -la build-win64/librandomx* else - mkdir build && cd build - CC="${CC} -g " CXX="${CXX} -g " cmake -DARCH=native .. + mkdir -p build-win64 && cd build-win64 + CC="${CC} -g " CXX="${CXX} -g " cmake -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++-posix -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc-posix -DARCH=native .. make fi @@ -41,3 +41,55 @@ cd $WD sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure cd src/ CC="${CC} -g " CXX="${CXX} -g " make V=1 hushd.exe hush-cli.exe hush-tx.exe + +# Create release package +cd $WD +echo "Creating Windows release package..." +VERSION=$(grep -oP 'define\(_CLIENT_VERSION.*?,\s*\K[0-9]+' configure.ac | head -4 | tr '\n' '.' | sed 's/\.$//') +VERSION=${VERSION:-3.10.4} +RELEASE_DIR="release-win64" +mkdir -p "$RELEASE_DIR" + +# Strip binaries +x86_64-w64-mingw32-strip -s src/hushd.exe src/hush-cli.exe src/hush-tx.exe + +# Copy binaries +cp src/hushd.exe src/hush-cli.exe src/hush-tx.exe "$RELEASE_DIR/" + +# Copy required data files +cp asmap.dat sapling-spend.params sapling-output.params "$RELEASE_DIR/" + +# Create DragonX batch files +cat > "$RELEASE_DIR/dragonxd.bat" << 'EOF' +@call :GET_CURRENT_DIR +@cd %THIS_DIR% +hushd.exe -ac_name=DRAGONX -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=36 -ac_private=1 -addnode=176.126.87.241 %* +@goto :EOF + +:GET_CURRENT_DIR +@pushd %~dp0 +@set THIS_DIR=%CD% +@popd +@goto :EOF +EOF +cat > "$RELEASE_DIR/dragonx-cli.bat" << 'EOF' +@call :GET_CURRENT_DIR +@cd %THIS_DIR% +hush-cli.exe -ac_name=DRAGONX %* +@goto :EOF + +:GET_CURRENT_DIR +@pushd %~dp0 +@set THIS_DIR=%CD% +@popd +@goto :EOF +EOF + +# Create ZIP +rm -f "$RELEASE_DIR/hush-${VERSION}-win64.zip" +cd "$RELEASE_DIR" +zip -9 "hush-${VERSION}-win64.zip" *.exe *.bat *.dat *.params +cd .. + +echo "Release package created: $RELEASE_DIR/hush-${VERSION}-win64.zip" +ls -lh "$RELEASE_DIR/hush-${VERSION}-win64.zip" diff --git a/util/build.sh b/util/build.sh index 6bf7a6d69..f48c6c729 100755 --- a/util/build.sh +++ b/util/build.sh @@ -139,13 +139,13 @@ echo $PWD ./makecustom cd $WD -# Build RandomX +# Build RandomX for Linux cd src/RandomX -if [ -d "build" ] +if [ -f "build-linux/librandomx.a" ] then - ls -la build/librandomx* + ls -la build-linux/librandomx* else - mkdir build && cd build + mkdir -p build-linux && cd build-linux cmake -DARCH=native .. make fi