1
0
Fork 0
forked from lthn/blockchain

Compare commits

...
Sign in to create a new pull request.

45 commits

Author SHA1 Message Date
Claude
c6def43d69
feat: key bridge prototype — derive sidechain + document keys from Lethean spend key
One Lethean seed phrase derives keys for:
- Main chain (ed25519, native)
- HNS sidechain (secp256k1, derived via HKDF)
- Document signing (ed25519, for hash timestamping)
- Audit trail (ed25519, for revision verification)

Domain-separated HKDF ensures keys can't be reversed or collide.
Foundation for Web3 identity bridge and corporate document control.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 15:03:07 +01:00
Claude
cbc49e93fe
docs: add TLD registrar model (Option B) to name registration plan
One constant change makes ALL names require authority signature.
Eliminates the 90K pre-registration race entirely. Lethean becomes
a proper TLD registrar for .lthn — curated namespace, revenue from
name sales, squatting impossible at protocol level.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 14:55:19 +01:00
Claude
56d7607754
feat: mainnet name registration plan and batch tooling
90,041 names from HNS reserved list need pre-registering to prevent
squatting. Strategy: genesis seeds namereg wallets, staking funds the
rest, parallel wallets batch-register into multi-sig.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 14:46:52 +01:00
Claude
a6773abaca
fix(pos): add --rpc-ignore-offline to all daemon configs
PoS mining requires this flag when the daemon has no peers. Without it,
the daemon's get_pos_mining_details RPC returns DISCONNECTED status and
the wallet refuses to mint.

First PoS blocks minted on testnet at height 12,382.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 13:53:07 +01:00
Claude
1e565495bb
fix(docker): set empty ASSETS_WHITELIST_URL to prevent explorer crash on DNS failure
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 13:31:19 +01:00
Claude
3fd1af9824
feat(docker): single-container staking node for GUI integration
Dockerfile.staking-node — runs daemon + wallet with PoS staking in one
container using supervisord. No docker-compose needed.

For the CoreGUI desktop app to run on Windows/Mac/Linux:
  docker run -d -p 46941:36941 -p 46942:36942 -p 46944:36944 \
    -v lthn-chain:/data -v lthn-wallet:/wallet \
    -e WALLET_PASSWORD=pass \
    lthn/staking-node

Built-in helpers:
  docker exec <name> /status.sh         — chain + wallet status
  docker exec <name> /wallet-address.sh — get wallet address

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 13:20:40 +01:00
Claude
e1292a6445
feat(demos): expanded VHS demo library with live data
5 numbered demos using helper scripts against the live system:
01-install     — zero to running node in 30 seconds
02-chain-status — chain info, latest block, on-chain aliases
03-ecosystem-tour — full tour of all 8 services (teaser material)
04-mining      — pool stats, miner connection examples
05-exit-node   — VPN exit node setup and earning

New helpers: last-block.sh, pool-stats.sh, lns-status.sh, explorer-stats.sh
Removed old unnumbered demos.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 13:11:47 +01:00
Claude
9e3c6c2223
fix(deploy): auto-generate JWT secret, include node/exit composes and helpers
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:37:57 +01:00
Claude
2ff53183c3
docs: add deployment options table and helper scripts to README
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:35:28 +01:00
Claude
96e79beef4
feat(demos): add ecosystem startup, wallet ops, LNS, and helper scripts
6 VHS terminal demos with reusable helper scripts:
- ecosystem-startup: full stack coming online
- wallet-basics: address, balance, chain info, aliases
- lns-dns: HTTP API and DNS resolution
- exit-node: VPN exit setup
- node-quickstart: 3-step home node
- health-check: all services green

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:34:00 +01:00
Claude
eebfb3f1f1
feat(demos): add VHS terminal demo GIFs for node, exit node, and health check
Rendered with charmbracelet/vhs. Tape scripts included for re-rendering.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:25:51 +01:00
Claude
7af620e7f6
feat(docker): add home node and exit node compose files
docker-compose.node.yml — minimal chain node + wallet with PoS staking.
Home users run this to support the network and earn staking rewards.

docker-compose.exit.yml — full VPN exit node with WireGuard.
Home users run this to provide bandwidth via the Lethean dVPN and earn
LTHN. Includes chain node, wallet, WireGuard server, and a controller
that manages gateway peering and status reporting.

.env.example updated with exit node settings (public IP, name, max peers).

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:14:05 +01:00
Claude
1261d0d94e
fix(docker): correct LNS env vars in ecosystem compose (DAEMON_URL not DAEMON_RPC)
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 12:05:48 +01:00
Claude
87fbdbb08d
fix(docker): correct LNS env vars (DAEMON_URL not DAEMON_RPC), add HSD host access, fix trade-frontend API_URL for SSR
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 11:56:34 +01:00
Claude
21ebfa1d17
fix(docker): point pool explorer URLs to local Docker explorer
Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 11:15:06 +01:00
Claude
91efcd41d0
feat(docker): full ecosystem Docker deployment
- docker-compose.pull.yml: production compose with pre-built images,
  health checks, env var config, service dependencies
- docker-compose.local.yml: override for mounting existing chain data
- docker-compose.ecosystem.yml: build-from-source compose with pool,
  LNS, Redis added
- Chain Dockerfile: add curl for health checks, swagger API resources
- Pool Dockerfile: Ubuntu 24.04, Boost 1.83, native ProgPoWZ compilation
- .env.example: configurable passwords, ports, hostname
- pool-config.json: Docker-networked pool config
- health.sh: one-command stack health check
- deploy.sh: remote server deployment script
- lethean-testnet.service: systemd auto-start unit
- README.md: quickstart, mining guide, backup, troubleshooting

All 8 services tested and running in Docker:
daemon, wallet, explorer, trade-api, trade-frontend, pool, LNS, docs

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 11:14:30 +01:00
b61d773a0f Merge pull request 'v6.0.1 — RandomX PoW, new genesis, multi-platform CI' (#1) from Charon/blockchain:dev into dev
Reviewed-on: lthn/blockchain#1
Reviewed-by: Snider <snider@noreply.forge.lthn.ai>
2026-02-14 20:19:13 +00:00
Claude
c9ad4de9bb
ci: multi-platform Forgejo Actions pipeline
Build Linux x86_64 (snider-linux) and macOS ARM64 (M3 Ultra) natively
via self-hosted forgejo-runner, aggregate into single release.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 19:37:35 +00:00
Claude
22c0c5a251
ci: use Forgejo Conan registry instead of actions/cache
Pull pre-built dependencies from the Forgejo package registry
(conan_build remote) instead of caching the SDK locally. Removes
the 570MB actions/cache overhead since all packages are already
available as pre-compiled binaries on the registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:06:47 +00:00
Claude
f3df50cba5
ci: prune old releases to keep only latest per branch
After uploading new release assets, delete older beta releases (dev)
or older stable releases (main) to conserve disk. Only the latest
build per branch is kept on the Forgejo instance; older builds are
available on mirrored free hosting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:03:13 +00:00
Claude
1545a80335
ci: add Forgejo Actions build & release workflow
Add .forgejo/workflows/build.yml that builds the Lethean blockchain
on push to dev/main with workflow_dispatch support. Builds testnet
on dev, mainnet on main, creates Forgejo releases with RPM/tar.xz/zip
packages and SHA256 checksums.

- CPU limited to 3 cores (~10% of 32-thread host) via Docker --cpus cap
- Private submodule auth via git credential store with RELEASE_TOKEN
- SDK caching with actions/cache for Conan build artifacts
- CMake installed via pip for preset version 8 support
- Tags fetched for libmdbx git describe version detection
- Fix missing contrib/randomx entry in .gitmodules

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 15:02:28 +00:00
Claude
467c64d015
feat: RandomX PoW, LWMA difficulty, stratum mining.* protocol, new genesis
Replace ProgPowZ with RandomX for ASIC-resistant proof-of-work. The
full dataset is initialized multi-threaded at startup with the key
"LetheanRandomXv1". Thread-local VMs are created on demand.

Switch difficulty algorithm from Zano's 720-block window to LWMA-1
(zawy12) with a 60-block window for much faster convergence after
hashrate changes. Target block time set to 10s for PoW.

Add standard stratum mining.* protocol handlers (subscribe, authorize,
submit, extranonce.subscribe) alongside existing EthProxy eth_*
handlers, with automatic protocol detection and mining.notify
translation for XMRig-based miners.

Generate fresh Lethean genesis block and premine wallet. Replace all
remaining hardcoded Zano addresses in tests with runtime-generated
keys to avoid prefix mismatches. Link RandomX library across all
build targets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 13:22:25 +00:00
Claude
7ee2265cae
fix: crypto test PRNG determinism, checkpoint hashes, and Zano address remnants
The crypto test PRNG was non-deterministic because setup_random() seeded
the state but grant_random_initialize_no_lock() overwrote it with
/dev/urandom on the first random call. Calling it before memset ensures
the initialized flag is set, preventing the overwrite.

Also adds --generate mode to crypto-tests for future vector regeneration,
updates checkpoint hashes for multisig_and_checkpoints (height 15) and
gen_no_attchments_in_coinbase (height 12), and replaces hardcoded Zano
addresses/URLs with Lethean equivalents in manual test scaffolding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 13:17:11 +00:00
Claude
4120a9a664
Rebrand to SASE, restore cmake test fixture
- Update .core/build.yaml description: SASE infrastructure chain
- cmake/test-static-assert.c already committed separately

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 03:56:41 +00:00
Claude
5dae74347c
Restore project-specific cmake/test-static-assert.c
This file was wrongly extracted to the .core/build submodule during the
build system extraction. It's a project-specific compile test used by
CMakeLists.txt:185 and must remain in the project tree.

Verified: make configure && make build && make package all pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 03:27:11 +00:00
Claude
92e0aa779b
feat(build): add .core/build.yaml for core CLI integration
C++ build configuration for core CLI project detection and future
`core compile` command. Defines Conan dependencies, CMake settings,
cross-compilation targets, and packaging options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 02:47:44 +00:00
Claude
7b0a08f9ff
Replace cmake/ with host-uk/build submodule at .core/build
Build system extracted to host-uk/build and wired in as a git
submodule following the core CLI convention (.core/<tool>/).

- CMake modules, cross-compilation profiles now from .core/build/cmake/
- Conan credentials read from environment instead of hardcoded
- Removed cmake/ directory (14 files) — all now in submodule
- Makefile, CMakeLists.txt, CMakePresets.json updated for new paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 01:57:40 +00:00
Snider
88d4357628
New API Interface (#27)
This pull request introduces a comprehensive new API interface for the blockchain, leveraging OpenAPI v3 to facilitate direct consumption of chain data by GUI and web applications. This change significantly refines the project's build infrastructure, incorporating Conan for dependency management and CMake for configuration, alongside the integration of an OpenAPI Generator to produce SDKs for multiple languages. 

### Highlights

* **New API Interface**: Introduced a new API interface using OpenAPI v3 to enable GUI/WEB development to consume chain data without needing custom server applications.
* **Build System Enhancements**: Significant updates to the build system, including Makefile, CMake, and Conan configurations, to streamline the build process and support new functionalities.
* **Multi-language SDK Generation**: Integrated OpenAPI Generator to automatically create SDKs for various programming languages, including Go, Angular, and PHP, simplifying client-side integration.
2025-10-19 19:12:37 +01:00
Snider
4a5c5ae742 Refactor build presets and Makefile targets
Updated CMakePresets.json to add 'testnet' and 'mainnet' workflows, removed unused Windows preset, and improved environment and cache variable handling. Makefile targets for testnet and mainnet workflows were added, and Conan-related targets were renamed for consistency. Added a function to reset ConanPresets.json in CleanBuild.cmake and fixed the path for GetConan.cmake in conan_provider.cmake. Deleted obsolete .idea/cmake.xml.
2025-10-09 03:10:46 +01:00
Snider
57983cb865 Since Clion is OSS now, adding more sharable ide project defaults. 2025-10-09 01:27:15 +01:00
Snider
ef776a93cc
Add CMake and Conan presets, update build config (#26)
* Add CMake and Conan presets, update build config

Introduces CMakePresets.json and ConanPresets.json for standardized build configuration. Updates Makefile to use CMake presets, modifies .gitignore for IDE files, and refines conanfile.py to support CI option and preset integration.

* Update Makefile

* Update _on-pr.yml

* Refactor build presets and folder layout for Windows

Updated Makefile and GitHub workflow to use configurable build and configure presets, improving flexibility for different environments. Adjusted CMakePresets.json to fix preset naming and version, and refactored conanfile.py to set build folders based on compiler type, ensuring correct folder structure for MSVC and other compilers.

* Update build presets and CPack config for Windows

Set PRESET_CONFIGURE to 'conan-default' for Windows builds in Makefile and GitHub workflow. Broaden CPack packaging conditions to include additional build types and comment out WIX generator settings for Windows in CPackConfig.cmake.
2025-10-09 00:25:29 +01:00
Snider
106b3431db Add JetBrains IDE config and update CMake setup
Added .idea configuration files for JetBrains IDE support and updated .gitignore to exclude only specific userland .idea files. Refactored CMakeLists.txt to improve include_directories usage, re-enable -fno-fat-lto-objects for GNU compilers. This improves IDE integration and build configuration clarity.
2025-10-08 20:22:51 +01:00
Snider
0882f94203 Update debug build paths in Makefile
Modified debug target to use absolute paths with $(CURDIR) for build directory and toolchain file. This improves reliability of file detection across environments and browsers.
2025-10-08 15:17:18 +01:00
Snider
1c584e7c76
Update CMakeLists.txt 2025-10-07 02:29:17 +01:00
Snider
79121dce71
Remove ccache from tool_requires 2025-10-07 02:28:22 +01:00
Snider
3dbb8b1487
Add 'secrets: inherit' to all build jobs 2025-10-07 02:24:12 +01:00
Snider
11d19e5446
Add caching and dependency installation steps for ARM, Intel, and mac… (#25) 2025-10-07 02:20:06 +01:00
Snider
e4ff164f0d
Build Simplification (#24) 2025-10-06 22:38:29 +01:00
Snider
dd7a19ac6f Lower min build version for hardforks 05 and 06
Updated ZANO_HARDFORK_05_MIN_BUILD_VER and ZANO_HARDFORK_06_MIN_BUILD_VER from 382 to 2 to allow compatibility with older builds.
2025-10-05 21:10:34 +01:00
Snider
eb60d4519c Revert "Use actual remote port for async connection"
This reverts commit 3e2bad36a6.
2025-10-05 20:44:13 +01:00
Snider
3e2bad36a6 Use actual remote port for async connection
Replaces usage of node_data.my_port with context.m_remote_port when establishing an async connection, ensuring the correct remote port is used for peer connections.
2025-10-05 20:03:58 +01:00
Snider
7f930b0fec Capture remote_ip by value in try_ping lambda
The lambda in try_ping now captures remote_ip by value instead of accessing context.m_remote_ip directly. This ensures the correct IP is used even if the context changes before the lambda executes.
2025-10-05 18:01:59 +01:00
Snider
c2c130a076
Add conditional check for alpha and beta versions
the tag + release deleting only happens for -alpha or -beta
2025-10-05 14:35:21 +01:00
Snider
d8d81c1f2e
Implement cleanup job for merged pull requests
Add cleanup job for closed pull requests that are merged.
2025-10-05 14:21:10 +01:00
Snider
c8acc964e3
Testnet updates (#22) 2025-10-05 14:00:36 +01:00
673 changed files with 111349 additions and 2723 deletions

1
.core/build Submodule

@ -0,0 +1 @@
Subproject commit 9c9346d5494688a78ea573f3bc0547ad12b9be2a

83
.core/build.yaml Normal file
View file

@ -0,0 +1,83 @@
# Lethean Blockchain Build Configuration
# Used by: core compile
version: 1
project:
name: blockchain
type: cpp
description: "Lethean Blockchain - SASE infrastructure chain"
version: "6.0.1"
cpp:
standard: 17
build_type: Release
static: false
conan:
version: "2.21.0"
requires:
- zlib/1.3.1
- boost/1.85.0
- openssl/3.2.0
- miniupnpc/2.2.5
- jwt-cpp/0.7.1
- oatpp/1.3.0.latest
- oatpp-swagger/1.3.0.latest
tool_requires:
- cmake/3.31.9
options:
boost/*:without_test: true
registry:
url: http://forge.snider.dev:4000/api/packages/host-uk/conan
remote: conan_build
cmake:
minimum_version: "3.16"
variables:
USE_CCACHE: "ON"
options:
testnet: false
targets:
- os: linux
arch: x86_64
profile: gcc-linux-x86_64
- os: linux
arch: arm64
profile: gcc-linux-armv8
- os: darwin
arch: arm64
profile: apple-clang-armv8
- os: darwin
arch: x86_64
profile: apple-clang-x86_64
- os: windows
arch: x86_64
profile: msvc-194-x86_64
package:
generators:
- TGZ
- ZIP
- NSIS
- DEB
- RPM
vendor: Lethean
contact: support@lt.hn
website: https://lt.hn
docker:
dockerfile: utils/docker/lthn-chain/Dockerfile
image: lthn/chain
platforms:
- linux/amd64
tags:
- testnet
- "{{.Version}}"
build_args:
BUILD_THREADS: auto
BUILD_TESTNET: "1"
BUILD_STATIC: "0"
BUILD_TYPE: Release

234
.forgejo/workflows/build.yml Executable file
View file

@ -0,0 +1,234 @@
name: Build & Release
on:
workflow_dispatch:
push:
branches:
- dev
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORGEJO_URL: ${{ github.server_url }}
jobs:
# ──────────────────────────────────────────────
# Linux x86_64 — native build on snider-linux
# ──────────────────────────────────────────────
build-linux:
name: Linux x86_64
runs-on: linux-native
env:
CPU_CORES: "24"
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
submodules: false
- name: Init submodules
run: |
git config --global url."${{ env.FORGEJO_URL }}/".insteadOf "http://forge.snider.dev:4000/"
git -c http.extraHeader="Authorization: token ${{ secrets.RELEASE_TOKEN }}" submodule update --init --recursive
git submodule foreach --recursive 'git fetch --tags origin 2>/dev/null || true'
- name: Build dependencies
run: |
make build-deps \
CPU_CORES=${{ env.CPU_CORES }} \
CONAN_URL=${{ env.FORGEJO_URL }}/api/packages/host-uk/conan \
CONAN_USER=claude \
CONAN_PASSWORD=${{ secrets.RELEASE_TOKEN }}
- name: Compile
run: |
make ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} \
CPU_CORES=${{ env.CPU_CORES }} \
CONAN_URL=${{ env.FORGEJO_URL }}/api/packages/host-uk/conan \
CONAN_USER=claude \
CONAN_PASSWORD=${{ secrets.RELEASE_TOKEN }}
- name: Upload artifacts
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: linux-x86_64
path: build/packages/lethean-*
retention-days: 7
# ──────────────────────────────────────────────
# macOS ARM64 — native build on M3 Ultra
# ──────────────────────────────────────────────
build-macos:
name: macOS ARM64
runs-on: macos-native
env:
CPU_CORES: "24"
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
submodules: false
- name: Init submodules
run: |
git config --global url."${{ env.FORGEJO_URL }}/".insteadOf "http://forge.snider.dev:4000/"
git -c http.extraHeader="Authorization: token ${{ secrets.RELEASE_TOKEN }}" submodule update --init --recursive
git submodule foreach --recursive 'git fetch --tags origin 2>/dev/null || true'
- name: Build dependencies
run: |
export PATH="/opt/homebrew/bin:$PATH"
make build-deps \
CPU_CORES=${{ env.CPU_CORES }} \
CONAN_URL=${{ env.FORGEJO_URL }}/api/packages/host-uk/conan \
CONAN_USER=claude \
CONAN_PASSWORD=${{ secrets.RELEASE_TOKEN }}
- name: Compile
run: |
export PATH="/opt/homebrew/bin:$PATH"
make ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} \
CPU_CORES=${{ env.CPU_CORES }} \
CONAN_URL=${{ env.FORGEJO_URL }}/api/packages/host-uk/conan \
CONAN_USER=claude \
CONAN_PASSWORD=${{ secrets.RELEASE_TOKEN }}
- name: Upload artifacts
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: macos-arm64
path: build/packages/lethean-*
retention-days: 7
# ──────────────────────────────────────────────
# Aggregate artifacts and create release
# ──────────────────────────────────────────────
release:
name: Create Release
needs: [build-linux, build-macos]
runs-on: linux-native
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
with:
fetch-depth: 1
submodules: false
- name: Download Linux artifacts
uses: https://code.forgejo.org/forgejo/download-artifact@v4
with:
name: linux-x86_64
path: artifacts/linux
- name: Download macOS artifacts
uses: https://code.forgejo.org/forgejo/download-artifact@v4
with:
name: macos-arm64
path: artifacts/macos
- name: List artifacts
run: find artifacts/ -type f | sort
- name: Compute release tag
id: release
run: |
VERSION=$(grep '^BUILD_VERSION:=' Makefile | cut -d'=' -f2)
if [ "${{ github.ref_name }}" = "main" ]; then
TAG="v${VERSION}+${{ github.run_number }}"
PRERELEASE=false
TITLE="v${VERSION} (build ${{ github.run_number }})"
else
TAG="v${VERSION}-beta+${{ github.run_number }}"
PRERELEASE=true
TITLE="v${VERSION}-beta (build ${{ github.run_number }})"
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT"
echo "title=${TITLE}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Create release
id: create_release
run: |
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
"${{ env.FORGEJO_URL }}/api/v1/repos/${{ github.repository }}/releases" \
-H "Authorization: token ${{ secrets.RELEASE_TOKEN }}" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"${{ steps.release.outputs.tag }}\",
\"target_commitish\": \"${{ github.sha }}\",
\"name\": \"${{ steps.release.outputs.title }}\",
\"body\": \"Automated build from \`${{ github.ref_name }}\` branch (run #${{ github.run_number }})\n\n## Platforms\n- Linux x86_64\n- macOS ARM64 (Apple Silicon)\",
\"draft\": false,
\"prerelease\": ${{ steps.release.outputs.prerelease }}
}")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 400 ]; then
echo "Failed to create release (HTTP ${HTTP_CODE}):"
echo "$BODY"
exit 1
fi
RELEASE_ID=$(echo "$BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "id=${RELEASE_ID}" >> "$GITHUB_OUTPUT"
echo "Created release ID: ${RELEASE_ID}"
- name: Upload release assets
run: |
for dir in artifacts/linux artifacts/macos; do
for file in "$dir"/lethean-*; do
[ -f "$file" ] || continue
FILENAME=$(basename "$file")
echo "Uploading: ${FILENAME}"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
"${{ env.FORGEJO_URL }}/api/v1/repos/${{ github.repository }}/releases/${{ steps.create_release.outputs.id }}/assets?name=${FILENAME}" \
-H "Authorization: token ${{ secrets.RELEASE_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary "@${file}")
if [ "$HTTP_CODE" -ge 400 ]; then
echo "Failed to upload ${FILENAME} (HTTP ${HTTP_CODE})"
exit 1
fi
echo "Uploaded ${FILENAME} (HTTP ${HTTP_CODE})"
done
done
- name: Prune old releases
run: |
TAG_PREFIX="${{ github.ref_name == 'main' && 'v6' || 'v6.*-beta' }}"
CURRENT_ID="${{ steps.create_release.outputs.id }}"
echo "Keeping release ${CURRENT_ID}, pruning older ${TAG_PREFIX} releases..."
PAGE=1
while true; do
RELEASES=$(curl -s "${{ env.FORGEJO_URL }}/api/v1/repos/${{ github.repository }}/releases?limit=50&page=${PAGE}" \
-H "Authorization: token ${{ secrets.RELEASE_TOKEN }}")
COUNT=$(echo "$RELEASES" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo 0)
[ "$COUNT" = "0" ] && break
echo "$RELEASES" | python3 -c "
import sys, json, fnmatch
for r in json.load(sys.stdin):
rid = r['id']
tag = r['tag_name']
if rid == ${CURRENT_ID}:
continue
if fnmatch.fnmatch(tag, '${TAG_PREFIX}*'):
print(f'{rid} {tag}')
" | while read -r RID RTAG; do
echo "Deleting release ${RTAG} (id=${RID})"
curl -s -o /dev/null -X DELETE \
"${{ env.FORGEJO_URL }}/api/v1/repos/${{ github.repository }}/releases/${RID}" \
-H "Authorization: token ${{ secrets.RELEASE_TOKEN }}"
curl -s -o /dev/null -X DELETE \
"${{ env.FORGEJO_URL }}/api/v1/repos/${{ github.repository }}/tags/${RTAG}" \
-H "Authorization: token ${{ secrets.RELEASE_TOKEN }}"
done
PAGE=$((PAGE + 1))
done
echo "Prune complete"

5
.gitattributes vendored
View file

@ -1,2 +1,5 @@
.git* export-ignore .git* export-ignore
/CMakeLists.txt export-subst /CMakeLists.txt export-subst
# Mark auto-generated SDK clients as "generated" to hide them in GitHub diffs
utils/sdk/client/** linguist-generated=true

22
.github/actions/make-docs/action.yml vendored Normal file
View file

@ -0,0 +1,22 @@
# .github/actions/make-docs/action.yml
name: 'Build Documentation'
description: 'Archives and uploads signed binaries to a GitHub release'
runs:
using: "composite"
steps:
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: echo "cache_id=$(date -u '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: ~/.cache
restore-keys: |
mkdocs-material-
- if: runner.os == 'Linux'
run: |
sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev pngquant
- run: pip install mkdocs-git-revision-date-localized-plugin cairosvg mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin mkdocs-material[imaging]

View file

@ -6,7 +6,7 @@ inputs:
required: true required: true
description: 'The chain network name to use in filenames, mainnet or testnet' description: 'The chain network name to use in filenames, mainnet or testnet'
assets: assets:
description: "A \\n separated string list of filenames to archive; if asset is a abs path, it's respected" description: "A EOL separated string list of filenames to archive; if asset is a abs path, it's respected"
required: false required: false
asset-type: asset-type:
required: true required: true
@ -37,6 +37,20 @@ runs:
fi fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" == "pull_request" ]; then
TAG_SUFFIX="-alpha.${{ github.event.number }}"
PRERELEASE=true
elif [ "${{ inputs.chain-network }}" != "mainnet" ]; then
TAG_SUFFIX="-beta"
PRERELEASE=true
else
TAG_SUFFIX=""
PRERELEASE=false
fi
TAG_NAME="${VERSION}${TAG_SUFFIX}+${{ github.run_number }}"
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT"
# Format the output to be a multi-line string. # Format the output to be a multi-line string.
# This is the correct way to pass a multi-line string in GITHUB_OUTPUT. # This is the correct way to pass a multi-line string in GITHUB_OUTPUT.
echo "paths<<EOF" >> "$GITHUB_OUTPUT" echo "paths<<EOF" >> "$GITHUB_OUTPUT"
@ -70,7 +84,7 @@ runs:
- name: Make Release - name: Make Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
tag_name: ${{ steps.asset.outputs.version }}${{ inputs.chain-network == 'mainnet' && '' || '-pre' }}+${{ github.run_number }} tag_name: ${{ steps.asset.outputs.tag_name }}
prerelease: ${{ contains(inputs.chain-network, 'testnet') }} prerelease: ${{ steps.asset.outputs.prerelease }}
files: ${{ inputs.asset-directory }}/lethean-* files: ${{ inputs.asset-directory }}/*
target_commitish: ${{ github.sha }} target_commitish: ${{ github.sha }}

View file

@ -1,27 +0,0 @@
name: PR Fast
permissions:
contents: write
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- dev
- main
paths-ignore:
- '**.md'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build-macos-arm64:
name: Compile
uses: ./.github/workflows/build-macos-arm64.yml
with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}

View file

@ -7,7 +7,10 @@ on:
pull_request_review: pull_request_review:
pull_request: pull_request:
types: types:
- review_requested - opened
- synchronize
- reopened
- ready_for_review
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -15,50 +18,39 @@ concurrency:
jobs: jobs:
build-linux-intel: build-linux-intel:
name: Chain name: Linux
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-linux-intel.yml uses: ./.github/workflows/build-linux-intel.yml
secrets: inherit secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-linux-arm: build-linux-arm:
name: Chain name: Linux
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-linux-arm64.yml uses: ./.github/workflows/build-linux-arm64.yml
secrets: inherit secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-windows-intel: build-windows-intel:
name: Chain name: Windows
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-windows-intel.yml uses: ./.github/workflows/build-windows-intel.yml
secrets: inherit secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-macos-arm64: build-macos-arm64:
name: Chain name: MacOS
if: |
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-macos-arm64.yml uses: ./.github/workflows/build-macos-arm64.yml
secrets: inherit secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-macos-intel: build-macos-intel:
name: Chain name: MacOS
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-macos-intel.yml uses: ./.github/workflows/build-macos-intel.yml
secrets: inherit secrets: inherit
with: with:
@ -66,9 +58,7 @@ jobs:
build-docker: build-docker:
name: Docker name: Docker
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-docker.yml uses: ./.github/workflows/build-docker.yml
secrets: inherit secrets: inherit
with: with:
@ -76,7 +66,5 @@ jobs:
build-docs: build-docs:
name: Docs name: Docs
if: | if: ${{!github.event.pull_request.draft}}
(github.actor == 'Snider' && github.event.pull_request.user.login == 'Snider') ||
(github.event.review.state == 'approved' && !github.event.pull_request.draft)
uses: ./.github/workflows/build-docs.yml uses: ./.github/workflows/build-docs.yml

View file

@ -16,41 +16,46 @@ concurrency:
jobs: jobs:
build-linux-intel: build-linux-intel:
name: Chain name: Linux
uses: ./.github/workflows/build-linux-intel.yml uses: ./.github/workflows/build-linux-intel.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-linux-arm: build-linux-arm:
name: Chain name: Linux
uses: ./.github/workflows/build-linux-arm64.yml uses: ./.github/workflows/build-linux-arm64.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-windows-intel: build-windows-intel:
name: Chain name: Windows
uses: ./.github/workflows/build-windows-intel.yml uses: ./.github/workflows/build-windows-intel.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-macos-arm64: build-macos-arm64:
name: Chain name: MacOS
uses: ./.github/workflows/build-macos-arm64.yml uses: ./.github/workflows/build-macos-arm64.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-macos-intel: build-macos-intel:
name: Chain name: MacOS
uses: ./.github/workflows/build-macos-intel.yml uses: ./.github/workflows/build-macos-intel.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
build-docker: build-docker:
name: Docker name: Docker
uses: ./.github/workflows/build-docker.yml uses: ./.github/workflows/build-docker.yml
secrets: inherit
with: with:
chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }} chain-network: ${{ github.ref_name == 'main' && 'mainnet' || 'testnet' }}
secrets: inherit
build-docs: build-docs:
name: Docs name: Docs

View file

@ -18,7 +18,7 @@ on:
jobs: jobs:
build: build:
name: "lthn/chain:${{ inputs.chain-network == 'testnet' && 'testnet' || 'latest' }}" name: "lthn/chain:${{ inputs.chain-network == 'testnet' && 'testnet' || 'latest' }}"
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
@ -39,14 +39,16 @@ jobs:
- name: Build and push - name: Build and push
id: docker_build id: docker_build
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
with: with:
file: utils/docker/images/lthn-chain/Dockerfile file: utils/docker/lthn-chain/Dockerfile
context: ${{ github.workspace }} context: ${{ github.workspace }}
push: true push: true
build-args: | build-args: |
BUILD_TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} BUILD_TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }}
THREADS=2 THREADS=2
BUILD_TARGET=gcc-linux-x86_64
BUILD_LOCAL=1 BUILD_LOCAL=1
tags: lthn/chain:${{ inputs.chain-network == 'testnet' && 'testnet' || 'latest' }} tags: lthn/chain:${{ inputs.chain-network == 'testnet' && 'testnet' || 'latest' }}

View file

@ -1,6 +1,6 @@
name: docs name: docs
permissions: permissions:
contents: read contents: write
on: on:
workflow_call: workflow_call:
@ -17,29 +17,24 @@ jobs:
with: with:
python-version: 3.x python-version: 3.x
- name: Install Conan - name: Cache SDK Folder
uses: conan-io/setup-conan@v1 uses: actions/cache@v4
with: with:
home: ${{ github.workspace }}/build/sdk path: |
cache_packages: true ${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- uses: actions/cache@v4
with:
key: ${{ github.ref }}
path: .cache
- run: sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev pngquant - run: sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev pngquant
- run: pip install mkdocs-git-revision-date-localized-plugin cairosvg mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin mkdocs-material[imaging] - run: pip install mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin mkdocs-material[imaging]
- name: Build Offline Version - name: Build Offline Version
run: make docs run: make docs
- name: Zip Build - name: CLI Artifacts
run: | uses: ./.github/actions/upload-artifacts
cd build/docs
zip -qq -r ../documentation.zip *
- name: Upload Artifacts
uses: actions/upload-artifact@v4.6.2
with: with:
name: Documentation chain-network: ${{ inputs.chain-network }}
path: build/documentation.zip assets: "*"
asset-type: 'docs'
asset-directory: ${{ github.workspace }}/build/docs

View file

@ -11,8 +11,48 @@ on:
type: string type: string
jobs: jobs:
cache:
name: cache-arm64
runs-on: ubuntu-22.04-arm
steps:
- name: Cache SDK Folder
id: cache
uses: actions/cache@v4
with:
path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Checkout Project
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: recursive
- name: install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: sudo apt-get install -y autotools-dev git build-essential libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev pngquant
- uses: actions/setup-python@v5
if: steps.cache.outputs.cache-hit != 'true'
with:
python-version: 3.x
- if: steps.cache.outputs.cache-hit != 'true'
run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
make build-deps CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} CONAN_USER=ci-user CONAN_PASSWORD=${{ secrets.CONAN_PASSWORD }}
make upload-conan-cache
build: build:
name: gcc-linux-arm64 name: compile-arm64
needs: cache
runs-on: ubuntu-22.04-arm runs-on: ubuntu-22.04-arm
steps: steps:
- name: Checkout Project - name: Checkout Project
@ -22,22 +62,24 @@ jobs:
submodules: recursive submodules: recursive
- name: install dependencies - name: install dependencies
run: sudo apt-get install -y autotools-dev git build-essential run: sudo apt-get install -y autotools-dev rpm git build-essential libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev pngquant
- name: Cache SDK Folder - name: Cache SDK Folder
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ github.workspace }}/build/sdk path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Install Conan - uses: actions/setup-python@v5
uses: conan-io/setup-conan@v1
with: with:
home: ${{ github.workspace }}/build/sdk python-version: 3.x
cache_packages: false
- run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Release - name: Compile Release
run: make release CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} run: make ${{ inputs.chain-network }}
- name: CLI Artifacts - name: CLI Artifacts
uses: ./.github/actions/upload-artifacts uses: ./.github/actions/upload-artifacts
@ -45,4 +87,4 @@ jobs:
chain-network: ${{ inputs.chain-network }} chain-network: ${{ inputs.chain-network }}
assets: lethean-* assets: lethean-*
asset-type: 'cli' asset-type: 'cli'
asset-directory: ${{ github.workspace }}/build/release/packages asset-directory: ${{ github.workspace }}/build/packages

View file

@ -11,8 +11,49 @@ on:
type: string type: string
jobs: jobs:
cache:
name: cache-x86_64
runs-on: ubuntu-22.04
steps:
- name: Cache SDK Folder
id: cache
uses: actions/cache@v4
with:
lookup-only: true
path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Checkout Project
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: recursive
- name: install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: sudo apt-get install -y autotools-dev rpm git build-essential
- uses: actions/setup-python@v5
if: steps.cache.outputs.cache-hit != 'true'
with:
python-version: 3.x
- if: steps.cache.outputs.cache-hit != 'true'
run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
make build-deps CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} CONAN_USER=ci-user CONAN_PASSWORD=${{ secrets.CONAN_PASSWORD }}
make upload-conan-cache
build: build:
name: gcc-linux-x86_64 name: compile-x86_64
needs: cache
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout Project - name: Checkout Project
@ -27,17 +68,18 @@ jobs:
- name: Cache SDK Folder - name: Cache SDK Folder
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ github.workspace }}/build/sdk path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Install Conan - uses: actions/setup-python@v5
uses: conan-io/setup-conan@v1
with: with:
home: ${{ github.workspace }}/build/sdk python-version: 3.x
cache_packages: false - run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Release - name: Compile Release
run: make release CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} run: make ${{ inputs.chain-network }}
- name: CLI Artifacts - name: CLI Artifacts
uses: ./.github/actions/upload-artifacts uses: ./.github/actions/upload-artifacts
@ -45,4 +87,4 @@ jobs:
chain-network: ${{ inputs.chain-network }} chain-network: ${{ inputs.chain-network }}
assets: lethean-* assets: lethean-*
asset-type: 'cli' asset-type: 'cli'
asset-directory: ${{ github.workspace }}/build/release/packages asset-directory: ${{ github.workspace }}/build/packages

View file

@ -12,8 +12,45 @@ on:
jobs: jobs:
build-cli: cache:
name: apple-clang-armv8 name: cache-armv8
runs-on: macos-15
steps:
- name: Cache SDK Folder
id: cache
uses: actions/cache@v4
with:
lookup-only: true
path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Checkout Project
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-python@v5
if: steps.cache.outputs.cache-hit != 'true'
with:
python-version: 3.x
- if: steps.cache.outputs.cache-hit != 'true'
run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
make build-deps CPU_CORES=3 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} CONAN_USER=ci-user CONAN_PASSWORD=${{ secrets.CONAN_PASSWORD }}
make upload-conan-cache
build:
name: compile-armv8
needs: cache
runs-on: macos-15 runs-on: macos-15
steps: steps:
- name: Checkout Project - name: Checkout Project
@ -22,25 +59,22 @@ jobs:
fetch-depth: 0 fetch-depth: 0
submodules: recursive submodules: recursive
- name: Cache SDK Folder - name: Cache SDK Folder
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ github.workspace }}/build/sdk path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Install Conan - uses: actions/setup-python@v5
uses: conan-io/setup-conan@v1
with: with:
home: ${{ github.workspace }}/build/sdk python-version: 3.x
cache_packages: false
# - name: Compile Release - run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
# run: make apple-clang-armv8 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }}
- name: Compile Release - name: Compile Release
run: make release CPU_CORES=3 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} run: make ${{ inputs.chain-network }}
- name: CLI Artifacts - name: CLI Artifacts
uses: ./.github/actions/upload-artifacts uses: ./.github/actions/upload-artifacts
@ -48,4 +82,4 @@ jobs:
chain-network: ${{ inputs.chain-network }} chain-network: ${{ inputs.chain-network }}
assets: lethean-* assets: lethean-*
asset-type: 'cli' asset-type: 'cli'
asset-directory: ${{ github.workspace }}/build/release/packages asset-directory: ${{ github.workspace }}/build/packages

View file

@ -11,8 +11,43 @@ on:
type: string type: string
jobs: jobs:
cache:
name: cache-x86_64
runs-on: macos-13
steps:
- name: Cache SDK Folder
id: cache
uses: actions/cache@v4
with:
lookup-only: true
path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Checkout Project
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-python@v5
if: steps.cache.outputs.cache-hit != 'true'
with:
python-version: 3.x
- if: steps.cache.outputs.cache-hit != 'true'
run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
make build-deps CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} CONAN_USER=ci-user CONAN_PASSWORD=${{ secrets.CONAN_PASSWORD }}
make upload-conan-cache
build: build:
name: apple-clang-x86_64 name: compile-x86_64
needs: cache
runs-on: macos-13 runs-on: macos-13
steps: steps:
- name: Checkout Project - name: Checkout Project
@ -21,21 +56,21 @@ jobs:
fetch-depth: 0 fetch-depth: 0
submodules: recursive submodules: recursive
- name: Cache SDK Folder - name: Cache SDK Folder
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ github.workspace }}/build/sdk path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Install Conan - uses: actions/setup-python@v5
uses: conan-io/setup-conan@v1
with: with:
home: ${{ github.workspace }}/build/sdk python-version: 3.x
cache_packages: false - run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Release - name: Compile Release
run: make release CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} run: make ${{ inputs.chain-network }}
- name: CLI Artifacts - name: CLI Artifacts
uses: ./.github/actions/upload-artifacts uses: ./.github/actions/upload-artifacts
@ -43,4 +78,4 @@ jobs:
chain-network: ${{ inputs.chain-network }} chain-network: ${{ inputs.chain-network }}
assets: lethean-* assets: lethean-*
asset-type: 'cli' asset-type: 'cli'
asset-directory: ${{ github.workspace }}/build/release/packages asset-directory: ${{ github.workspace }}/build/packages

View file

@ -11,9 +11,44 @@ on:
type: string type: string
jobs: jobs:
msvc-194: cache:
name: msvc-194-x86_64 name: cache-x86_64
runs-on: windows-2022 runs-on: windows-latest
steps:
- name: Cache SDK Folder
id: cache
uses: actions/cache@v4
with:
lookup-only: true
path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Checkout Project
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-python@v5
if: steps.cache.outputs.cache-hit != 'true'
with:
python-version: 3.x
- if: steps.cache.outputs.cache-hit != 'true'
run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
make build-deps CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} CONAN_USER=ci-user CONAN_PASSWORD=${{ secrets.CONAN_PASSWORD }}
make upload-conan-cache
build:
name: compile-x86_64
needs: cache
runs-on: windows-latest
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
@ -24,17 +59,19 @@ jobs:
- name: Cache SDK Folder - name: Cache SDK Folder
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{ github.workspace }}/build/sdk path: |
${{ github.workspace }}/build/sdk
${{ github.workspace }}/build/bin
key: ${{ runner.os }}-${{ runner.arch }}-sdk key: ${{ runner.os }}-${{ runner.arch }}-sdk
- name: Install Conan - run: choco install nsis.install
uses: conan-io/setup-conan@v1 - uses: actions/setup-python@v5
with: with:
home: ${{ github.workspace }}/build/sdk python-version: 3.x
cache_packages: false - run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin mkdocs-git-committers-plugin-2 mkdocs-git-authors-plugin "mkdocs-material[imaging]"
- name: Compile Release - name: Compile Release
run: make release CPU_CORES=4 TESTNET=${{ inputs.chain-network == 'testnet' && '1' || '0' }} run: make ${{ inputs.chain-network }}
- name: CLI Artifacts - name: CLI Artifacts
uses: ./.github/actions/upload-artifacts uses: ./.github/actions/upload-artifacts
@ -42,4 +79,4 @@ jobs:
chain-network: ${{ inputs.chain-network }} chain-network: ${{ inputs.chain-network }}
assets: lethean-* assets: lethean-*
asset-type: 'cli' asset-type: 'cli'
asset-directory: ${{ github.workspace }}/build/release/packages asset-directory: ${{ github.workspace }}/build/packages

10
.gitignore vendored
View file

@ -5,6 +5,14 @@
._.DS_Store ._.DS_Store
Thumbs.db Thumbs.db
._* ._*
.idea .idea/workspace.xml
.idea/usage.statistics.xml
.idea/dictionaries
.idea/shelf
.idea/copilot*
.idea/modules.xml
.idea/*.iml
.vs/* .vs/*
CMakeUserPresets.json CMakeUserPresets.json
ConanPresets.json
docker/dist/

6
.gitmodules vendored
View file

@ -10,3 +10,9 @@
[submodule "docs"] [submodule "docs"]
path = docs path = docs
url = https://github.com/letheanVPN/documentation.git url = https://github.com/letheanVPN/documentation.git
[submodule "contrib/randomx"]
path = contrib/randomx
url = https://github.com/tevador/RandomX.git
[submodule ".core/build"]
path = .core/build
url = http://forge.snider.dev:4000/host-uk/build.git

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name generated Normal file
View file

@ -0,0 +1 @@
Lethean

8
.idea/cmake.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSharedSettings">
<configurations>
<configuration PROFILE_NAME="Debug" ENABLED="true" GENERATION_DIR="build/release" CONFIG_NAME="Debug" GENERATION_OPTIONS="--preset testnet" BUILD_OPTIONS="--preset testnet --parallel 30" NO_GENERATOR="true" />
</configurations>
</component>
</project>

105
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,105 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<RiderCodeStyleSettings>
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</RiderCodeStyleSettings>
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/copyright/LTHN.xml generated Normal file
View file

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) 2017-2025 Lethean (https://lt.hn)&#10;&#10;Licensed under the European Union Public Licence (EUPL) version 1.2.&#10;You may obtain a copy of the licence at:&#10;&#10; https://joinup.ec.europa.eu/software/page/eupl/licence-eupl&#10;&#10;The EUPL is a copyleft licence that is compatible with the MIT/X11&#10;licence used by the original projects; but maintains OSS status, &#10;where regional copyright law requires ownership to dictate licence terms.&#10;&#10;SPDXLicenseIdentifier: EUPL-1.2&#10;" />
<option name="myName" value="LTHN" />
</copyright>
</component>

6
.idea/copyright/Lethean.xml generated Normal file
View file

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) 2014-2018 Zano Project&#10;Copyright (c) 2014-2018 The Louisdor Project&#10;Copyright (c) 2012-2013 The Boolberry developers&#10;Copyright (c) 2017-2025 Lethean (https://lt.hn)&#10;&#10;Licensed under the European Union Public Licence (EUPL) version 1.2.&#10;You may obtain a copy of the licence at:&#10;&#10; https://joinup.ec.europa.eu/software/page/eupl/licence-eupl&#10;&#10;The EUPL is a copyleft licence that is compatible with the MIT/X11&#10;licence used by the original projects; the MIT terms are therefore&#10;considered “grandfathered” under the EUPL for this code.&#10;&#10;SPDXLicenseIdentifier: EUPL-1.2&#10;" />
<option name="myName" value="Lethean" />
</copyright>
</component>

8
.idea/copyright/profiles_settings.xml generated Normal file
View file

@ -0,0 +1,8 @@
<component name="CopyrightManager">
<settings default="LTHN">
<module2copyright>
<element module="apiserver" copyright="LTHN" />
<element module="Project Files" copyright="Lethean" />
</module2copyright>
</settings>
</component>

344
.idea/editor.xml generated Normal file
View file

@ -0,0 +1,344 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
</component>
</project>

View file

@ -0,0 +1,13 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="tuple.*" />
</list>
</option>
</inspection_tool>
</profile>
</component>

43
.idea/jsonSchemas.xml generated Normal file
View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsonSchemaMappingsProjectConfiguration">
<state>
<map>
<entry key="GitHub Action JSON Schema">
<value>
<SchemaInfo>
<option name="name" value="GitHub Action JSON Schema" />
<option name="relativePathToSchema" value="jar://$APPLICATION_PLUGINS_DIR$/vcs-github-IU/lib/vcs-github.jar!/schemas/github-action.json" />
<option name="applicationDefined" value="true" />
<option name="patterns">
<list>
<Item>
<option name="path" value=".github/actions/**/*.yml" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
<entry key="openapitools">
<value>
<SchemaInfo>
<option name="generatedName" value="New Schema" />
<option name="name" value="openapitools" />
<option name="relativePathToSchema" value="utils/sdk/openapitools.json" />
<option name="patterns">
<list>
<Item>
<option name="directory" value="true" />
<option name="path" value="utils/sdk/packages" />
<option name="mappingKind" value="Directory" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
</map>
</state>
</component>
</project>

34
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13 virtualenv at $PROJECT_DIR$.venv" />
</component>
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration">
<excludeRoots>
<file path="$PROJECT_DIR$/build" />
</excludeRoots>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MakefileSettings">
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="buildOptions" value="--jobs=30" />
<option name="buildTarget" value="build" />
<option name="cleanTarget" value="clean-build" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="switches" value="TESTNET=1 STATIC=1" />
<option name="version" value="2" />
</MakefileProjectSettings>
</option>
</component>
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

6
.idea/prettier.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
</component>
</project>

3
.idea/scopes/apiserver.xml generated Normal file
View file

@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="apiserver" pattern="file[blockchain]:src/api//*" />
</component>

10
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/contrib/bitcoin-secp256k1" vcs="Git" />
<mapping directory="$PROJECT_DIR$/contrib/jwt-cpp" vcs="Git" />
<mapping directory="$PROJECT_DIR$/contrib/tor-connect" vcs="Git" />
<mapping directory="$PROJECT_DIR$/docs" vcs="Git" />
</component>
</project>

55
AGENTS.md Normal file
View file

@ -0,0 +1,55 @@
# AI Agent Collaboration Framework for Repository Contributions
## 1. Purpose and Guiding Philosophy
This document provides a guiding framework for any AI agent interacting with this repository. Its purpose is to ensure that all automated contributions, especially Pull Request (PR) reviews and code suggestions, are constructive, respectful, and aligned with the project's overarching goals.
This framework operates in accordance with the foundational **Axioms of Life**, translating their universal principles into the specific context of human-AI software development collaboration. The primary goal is a partnership that enhances code quality and developer velocity, not one that creates friction through pedantry.
## 2. Core Principles for AI Interaction
All agents MUST adhere to the following principles:
* **Principle 1: Respect Authorial Intent (Axiom 1 & 4)**
* Your primary goal is to understand and support the human author's objective. Before suggesting a change, first assume the author had a valid reason for their implementation. Frame your feedback as a way to better achieve their goal or to prevent unintended side effects. Do not challenge intent without clear evidence of a functional error.
* **Principle 2: Prioritize Objectivity and Verifiability (Axiom 2)**
* Feedback MUST be anchored in objective, verifiable criteria. Subjective opinions on style are the lowest priority.
* **Valid criteria include:**
* Demonstrable bugs or logical errors.
* Security vulnerabilities.
* Performance regressions.
* Violations of a documented project standard (e.g., a style guide file in the repo).
* **Invalid criteria include:**
* Personal stylistic preferences not codified in a project standard.
* Code organization that is merely "different" but not functionally incorrect.
* **Principle 3: Adopt a Collaborative, Non-Authoritarian Tone (Axiom 4)**
* As a digital substrate interacting with a human one, you must adopt a tone of a helpful, respectful peer. Avoid declarative or demanding language.
* **Prefer:** "Have you considered...?", "An alternative here that might prevent X is...", "I noticed this could lead to Y. What do you think about...?"
* **Avoid:** "You must fix this.", "This is wrong.", "Change this to..."
* **Principle 4: Provide Actionable and Justified Suggestions (Axiom 3)**
* Do not simply state that something is incorrect. Provide a clear explanation for *why* it is a potential issue and, whenever possible, offer a concrete, well-explained code suggestion that resolves it. Your intent is to help, not just to criticize.
## 3. Feedback Severity Classification
To combat pedantry, all feedback provided in PR reviews MUST be classified into one of the following three levels. This creates a clear hierarchy of importance.
### **Level 1: Critical (Blocking)**
* **Definition:** Issues that will cause demonstrable harm if merged.
* **Examples:** Bugs, logic errors, security vulnerabilities, unhandled exceptions, build failures.
* **Action:** These issues MUST be addressed by the author before a merge. Your feedback should clearly state the nature of the critical issue.
### **Level 2: Important (Non-Blocking Recommendation)**
* **Definition:** Issues that deviate from established project best practices or could impact future maintainability.
* **Examples:** Violations of a documented style guide, clear opportunities to improve readability, non-critical performance improvements, deprecation warnings.
* **Action:** These issues SHOULD be addressed. Frame them as strong recommendations that improve the health of the codebase. The author may choose to address them in a follow-up PR if necessary.
### **Level 3: Suggestion (Optional Nitpick)**
* **Definition:** Minor stylistic preferences, alternative implementations with no clear functional advantage, or purely cosmetic changes. This is the "pedantic" category.
* **Action:** These suggestions are entirely optional and at the author's discretion. They MUST be explicitly prefixed with "Optional:", "Nit:", or "Suggestion:". This signals to the human that the comment is non-essential and can be safely ignored without consequence.
---
By adhering to this framework, AI agents become valuable partners in the development process, helping to catch critical errors while respecting the creative autonomy and focus of their human collaborators.

View file

@ -1,19 +1,16 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
message(STATUS "Using CMake version: ${CMAKE_VERSION}")
set(DISABLE_TOR TRUE CACHE BOOL "Disable TOR library(and related tor-connect submodule)") set(DISABLE_TOR TRUE CACHE BOOL "Disable TOR library(and related tor-connect submodule)")
PROJECT(Lethean) PROJECT(Lethean)
set(VERSION "1.0" CACHE STRING "Build version") set(VERSION "1.0" CACHE STRING "Build version")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
message("OPENSSL_INCLUDE_DIR: ${OPENSSL_INCLUDE_DIR}")
message("OPENSSL_CRYPTO_LIBRARY: ${OPENSSL_CRYPTO_LIBRARY}")
message("OPENSSL_SSL_LIBRARY: ${OPENSSL_SSL_LIBRARY}")
list(INSERT CMAKE_MODULE_PATH 0 list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_CURRENT_SOURCE_DIR}/cmake") "${CMAKE_CURRENT_SOURCE_DIR}/.core/build/cmake")
include(DocBuilder)
if(POLICY CMP0043) if(POLICY CMP0043)
cmake_policy(SET CMP0043 NEW) cmake_policy(SET CMP0043 NEW)
@ -21,6 +18,9 @@ endif()
if(POLICY CMP0043) if(POLICY CMP0043)
cmake_policy(SET CMP0074 NEW) cmake_policy(SET CMP0074 NEW)
endif() endif()
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
if(POLICY CMP0144) if(POLICY CMP0144)
cmake_policy(SET CMP0144 NEW) cmake_policy(SET CMP0144 NEW)
endif() endif()
@ -28,16 +28,13 @@ if(POLICY CMP0167)
cmake_policy(SET CMP0167 OLD) cmake_policy(SET CMP0167 OLD)
endif() endif()
#option (USE_CCACHE "Use ccache if a usable instance is found" ON) include(DocBuilder)
#if (USE_CCACHE) option (USE_CCACHE "Use ccache if a usable instance is found" OFF)
# include(FindCcache) # Has to be included after the project() macro, to be able to read the CXX variable. if (USE_CCACHE)
#else() include(FindCcache)
# message(STATUS "ccache deselected") else()
#endif() message(STATUS "ccache deselected")
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android") if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
add_definitions(-DMOBILE_WALLET_BUILD) add_definitions(-DMOBILE_WALLET_BUILD)
@ -86,19 +83,13 @@ endif()
set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers") set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers")
set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect submodule)") set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect submodule)")
set(TESTNET FALSE CACHE BOOL "Compile for testnet") set(TESTNET 0 CACHE BOOL "Build TESTNET")
set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon") set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon")
set(USE_BITCOIN_SECP256K1_FOR_ECDSA FALSE CACHE BOOL "Use bitcoin-secp256k1 library for validating ECDSA(instead of OpenSSL)") set(USE_BITCOIN_SECP256K1_FOR_ECDSA FALSE CACHE BOOL "Use bitcoin-secp256k1 library for validating ECDSA(instead of OpenSSL)")
if(NOT USE_BITCOIN_SECP256K1_FOR_ECDSA) if(NOT USE_BITCOIN_SECP256K1_FOR_ECDSA)
add_definitions(-DUSE_OPEN_SSL_FOR_ECDSA) add_definitions(-DUSE_OPEN_SSL_FOR_ECDSA)
endif() endif()
find_package(miniupnpc REQUIRED)
find_package(ZLIB REQUIRED)
include_directories(src contrib/eos_portable_archive ${ZLIB_INCLUDE_DIRS} contrib contrib/epee/include contrib/jwt-cpp/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version")
add_definitions(-DSTATICLIB) add_definitions(-DSTATICLIB)
if(TESTNET) if(TESTNET)
@ -149,7 +140,7 @@ if(MSVC)
endforeach() endforeach()
endif() endif()
include_directories(SYSTEM src/platform/msc) include_directories(SYSTEM src/platform/msc)
configure_file(utils/Directory.Build.props.in ${CMAKE_BINARY_DIR}/Directory.Build.props)
else() else()
set(ARCH default CACHE STRING "CPU to build for: -march value or default") set(ARCH default CACHE STRING "CPU to build for: -march value or default")
if("${ARCH}" STREQUAL "default") if("${ARCH}" STREQUAL "default")
@ -191,7 +182,7 @@ else()
endif() endif()
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes -Wno-comment") set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes -Wno-comment")
set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers") set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers")
try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c++14") try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-static-assert.c" COMPILE_DEFINITIONS "-std=c++14")
if(STATIC_ASSERT_RES) if(STATIC_ASSERT_RES)
set(STATIC_ASSERT_FLAG "") set(STATIC_ASSERT_FLAG "")
else() else()
@ -217,9 +208,9 @@ else()
if(NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Android")) if(NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Android"))
set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto=auto -g3") set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto=auto -g3")
endif() endif()
#if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
# set(RELEASE_FLAGS "${RELEASE_FLAGS} -fno-fat-lto-objects") set(RELEASE_FLAGS "${RELEASE_FLAGS} -fno-fat-lto-objects")
#endif() endif()
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}")
@ -251,14 +242,25 @@ set(BOOST_COMPONENTS system filesystem locale thread timer date_time chrono rege
if(NOT APPLE) if(NOT APPLE)
list(APPEND BOOST_COMPONENTS log) list(APPEND BOOST_COMPONENTS log)
endif() endif()
# Find Boost package using Conan
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
message(STATUS "Using Boost ${Boost_VERSION} from Conan") message(STATUS "Using Boost ${Boost_VERSION} from Conan")
include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(miniupnpc REQUIRED)
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/contrib/ethereum/libethash) find_package(ZLIB REQUIRED)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
include_directories(src "${CMAKE_BINARY_DIR}/version")
include_directories(SYSTEM
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/contrib/ethereum/libethash
contrib
contrib/epee/include
contrib/jwt-cpp/include
contrib/eos_portable_archive
)
# Append other needed libraries # Append other needed libraries
if(MINGW) if(MINGW)

109
CMakePresets.json Normal file
View file

@ -0,0 +1,109 @@
{
"version": 8,
"cmakeMinimumRequired": {
"major": 3,
"minor": 23,
"patch": 0
},
"include": [
"ConanPresets.json"
],
"configurePresets": [
{
"name": "testnet",
"binaryDir": "${sourceDir}/build/release",
"environment": {
"CONAN_HOME": "${sourceDir}/build/sdk"
},
"cacheVariables": {
"TESTNET": "ON",
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES":".core/build/cmake/ConanProvider.cmake"
}
},
{
"name": "mainnet",
"binaryDir": "${sourceDir}/build/release",
"environment": {
"CONAN_HOME": "${sourceDir}/build/sdk"
},
"cacheVariables": {
"TESTNET": "OFF",
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES":".core/build/cmake/ConanProvider.cmake"
}
}
],
"buildPresets": [
{
"name": "testnet",
"configurePreset": "testnet"
},
{
"name": "mainnet",
"configurePreset": "mainnet"
}
],
"testPresets": [
{
"name": "mainnet",
"configurePreset": "mainnet",
"output": {"outputOnFailure": true},
"execution": {"noTestsAction": "error", "stopOnFailure": true}
}
],
"packagePresets": [
{
"name": "mainnet",
"configurePreset": "mainnet",
"generators": [
"TGZ",
"ZIP"
]
},
{
"name": "testnet",
"configurePreset": "testnet",
"generators": [
"TGZ",
"ZIP"
]
}
],
"workflowPresets": [
{
"name": "testnet",
"steps": [
{
"type": "configure",
"name": "testnet"
},
{
"type": "build",
"name": "testnet"
},
{
"type": "package",
"name": "testnet"
}
]
},
{
"name": "mainnet",
"steps": [
{
"type": "configure",
"name": "mainnet"
},
{
"type": "build",
"name": "mainnet"
},
{
"type": "package",
"name": "mainnet"
}
]
}
]
}

9
ConanPresets.json Normal file
View file

@ -0,0 +1,9 @@
{
"version": 4,
"vendor": {
"conan": {}
},
"include": [
"build/release/generators/CMakePresets.json"
]
}

215
Makefile
View file

@ -4,190 +4,193 @@
# Distributed under the MIT/X11 software license, see the accompanying # Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
# ============================================================
# Build system from host-uk/build submodule
# ============================================================
BUILD_SYS := .core/build
CMAKE_DIR := $(BUILD_SYS)/cmake
# ============================================================
# Project Configuration
# ============================================================
CPU_CORES := 1
TESTNET:= 0
STATIC:= 0
BUILD_TYPE ?=Release
BUILD_VERSION:=6.0.1
BUILD_FOLDER:=build/release
PRESET_BUILD:=conan-release
PRESET_CONFIGURE:=conan-release
# ------------------------------------------------------------ # ------------------------------------------------------------
# Detect the number of logical CPU cores works on Linux, # Detect the number of logical CPU cores works on Linux,
# macOS, BSD, and Windows (both cmd.exe and PowerShell). # macOS, BSD, and Windows (both cmd.exe and PowerShell).
# ------------------------------------------------------------ # ------------------------------------------------------------
# Default to “unknown” will be overwritten below.
CPU_CORES := 1
TESTNET:= 0
BUILD_TYPE ?=Release
BUILD_VERSION:=6.0.1
# -----------------------------------------------------------------
# Unixlike systems (Linux, macOS, *BSD, etc.)
# -----------------------------------------------------------------
UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown) UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)
ifeq ($(UNAME_S),Linux) ifeq ($(UNAME_S),Linux)
# Linux: try nproc first, fall back to /proc
CPU_CORES := $(shell nproc 2>/dev/null || \ CPU_CORES := $(shell nproc 2>/dev/null || \
grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 1) grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 1)
endif endif
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)
# macOS: sysctl reports the number of logical CPUs
CPU_CORES := $(shell sysctl -n hw.logicalcpu 2>/dev/null || echo 1) CPU_CORES := $(shell sysctl -n hw.logicalcpu 2>/dev/null || echo 1)
endif endif
ifeq ($(filter %BSD,$(UNAME_S)),%BSD) ifeq ($(filter %BSD,$(UNAME_S)),%BSD)
# *BSD: also sysctl, but the key differs on some variants
CPU_CORES := $(shell sysctl -n hw.ncpu 2>/dev/null || echo 1) CPU_CORES := $(shell sysctl -n hw.ncpu 2>/dev/null || echo 1)
endif endif
# -----------------------------------------------------------------
# Windows (detected by the builtin $(OS) variable set by GNU make)
# -----------------------------------------------------------------
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
# Prefer the environment variable that Windows sets for us.
# It works in both cmd.exe and PowerShell. PRESET_CONFIGURE:=conan-default
CPU_CORES := $(NUMBER_OF_PROCESSORS) CPU_CORES := $(NUMBER_OF_PROCESSORS)
# If for some reason the env var is empty, fall back to PowerShell.
ifeq ($(CPU_CORES),) ifeq ($(CPU_CORES),)
CPU_CORES := $(shell powershell -NoProfile -Command ^ "[Environment]::ProcessorCount") CPU_CORES := $(shell powershell -NoProfile -Command ^ "[Environment]::ProcessorCount")
endif endif
endif endif
#testnet-genesis-new: # Safety net
# $(eval command += $(cmake_release) $(testnet))
# $(call CMAKE,$(dir_release),$(command) -DGENERATE_PREMINE_WALLET=1 -DPREMINE_WALLET_PASSWORD=12345678) && cmake --build ./src --target premine_wallet || true
# $(eval command += $(cmake_release) $(testnet))
# $(call CMAKE,$(dir_release),$(command) -DGENERATE_FRESH_GENESIS=1) && cmake --build ./src --target genesis_generator
# $(eval command += $(cmake_release) $(testnet))
# $(call CMAKE,$(dir_release),$(command)) && $(MAKE)
#
#genesis-new:
# $(eval command += $(cmake_release))
# $(call CMAKE,$(dir_release),$(command) -DGENERATE_FRESH_GENESIS=1) && cmake --build ./src --target genesis_generator
# $(eval command += $(cmake_release))
# $(call CMAKE,$(dir_release),$(command)) && $(MAKE)
# -----------------------------------------------------------------
# Safety net ensure we always have a positive integer.
# -----------------------------------------------------------------
CPU_CORES := $(or $(CPU_CORES),1) CPU_CORES := $(or $(CPU_CORES),1)
CPU_CORES := $(shell expr $(CPU_CORES) + 0 2>/dev/null || echo 1) CPU_CORES := $(shell expr $(CPU_CORES) + 0 2>/dev/null || echo 1)
CONAN_CPU_COUNT=$(CPU_CORES) CONAN_CPU_COUNT=$(CPU_CORES)
# ============================================================
PROFILES := $(patsubst cmake/profiles/%,%,$(wildcard cmake/profiles/*)) # Paths — profiles and cmake modules from .build submodule
SORTED_PROFILES := $(sort $(PROFILES)) # ============================================================
CONAN_CACHE := $(CURDIR)/build/sdk PROFILES :=$(patsubst $(CMAKE_DIR)/profiles/%,%,$(wildcard $(CMAKE_DIR)/profiles/*))
DEFAULT_CONAN_PROFILE := $(CONAN_CACHE)/profiles/default SORTED_PROFILES :=$(sort $(PROFILES))
CC_DOCKER_FILE?=utils/docker/images/lthn-chain/Dockerfile CONAN_CACHE :=$(CURDIR)/build/sdk
CONAN_URL :=http://forge.snider.dev:4000/api/packages/host-uk/conan
CONAN_USER ?=$(shell echo $$CONAN_USER)
CONAN_PASSWORD ?=$(shell echo $$CONAN_PASSWORD)
CONAN_EXECUTABLE :=$(CURDIR)/build/bin/conan
CC_DOCKER_FILE ?=utils/docker/images/lthn-chain/Dockerfile
SDK_PACKAGES_JSON :=$(wildcard utils/sdk/packages/*.json)
SDK_TARGETS :=$(patsubst utils/sdk/packages/%.json,%,$(SDK_PACKAGES_JSON))
SORTED_SDK_TARGETS :=$(sort $(SDK_TARGETS))
all: help all: help
release: conan-profile-detect testnet:
@echo "Building profile: release $(TESTNET)" $(MAKE) configure TESTNET=1 STATIC=$(STATIC)
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/release --build=missing -s build_type=$(BUILD_TYPE) CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) build .
cmake -S . -B build/release -DCMAKE_TOOLCHAIN_FILE=build/release/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DTESTNET=$(TESTNET) -DBUILD_VERSION=$(BUILD_VERSION) $(MAKE) package
cmake --build build/release --config=$(BUILD_TYPE) --parallel=$(CPU_CORES)
(cd build/release && cpack)
debug: conan-profile-detect mainnet:
@echo "Building profile: debug" $(MAKE) configure TESTNET=0 STATIC=$(STATIC)
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/debug --build=missing -s build_type=Debug CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) build .
cmake -S . -B build/debug -DCMAKE_TOOLCHAIN_FILE=build/debug/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DTESTNET=$(TESTNET) $(MAKE) package
cmake --build build/debug --config=Debug --parallel=$(CPU_CORES)
static: static-release release: docs build
static-release: conan-profile-detect (cd $(BUILD_FOLDER) && cpack)
@echo "Building profile: release-static" @rm -rf $(CURDIR)/build/packages/_CPack_Packages
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/release-static --build=missing -s build_type=$(BUILD_TYPE)
cmake -S . -B build/release-static -DCMAKE_TOOLCHAIN_FILE=build/release-static/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -D STATIC=ON -DTESTNET=$(TESTNET)
cmake --build build/release-static --config=$(BUILD_TYPE) --parallel=$(CPU_CORES)
conan-profile-detect: build: configure
@if [ ! -f "$(DEFAULT_CONAN_PROFILE)" ]; then \ cmake --build --preset $(PRESET_BUILD) --parallel=$(CPU_CORES)
echo "Default conan profile not found. Detecting a new one..."; \
CONAN_HOME=$(CONAN_CACHE) conan profile detect --name=default --force; \
fi
build-deps: conan-profile-detect
@echo "Build Dependencies: $(BUILD_TYPE) testnet=$(TESTNET)"
CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) install . --build=missing -s build_type=$(BUILD_TYPE)
# Rule for each profile package:
@echo "Packaging: $(BUILD_TYPE) testnet=$(TESTNET)"
(cd $(BUILD_FOLDER) && cpack)
ifneq ($(OS),Windows_NT)
@rm -rf $(CURDIR)/build/packages/_CPack_Packages
endif
configure: build-deps
@echo "Running Configure: $(BUILD_TYPE) testnet=$(TESTNET)"
cmake --preset $(PRESET_CONFIGURE) -DSTATIC=$(STATIC) -DTESTNET=$(TESTNET) -DBUILD_VERSION=$(BUILD_VERSION)
docs: configure
@echo "Building Documentation"
cmake --build build/release --target=docs --config=Release --parallel=$(CPU_CORES)
sdk:
$(MAKE) -C utils/sdk $(filter-out $@,$(MAKECMDGOALS)) PACKAGE_VERSION=$(BUILD_VERSION)
# Rule for each profile — uses .build/cmake/profiles/
$(PROFILES): conan-profile-detect $(PROFILES): conan-profile-detect
@echo "Building profile: $@" @echo "Building profile: $@"
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/$@ -pr:b=$(DEFAULT_CONAN_PROFILE) -pr:h=cmake/profiles/$@ --build=missing -s build_type=$(BUILD_TYPE) CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) install . -pr:h=$(CMAKE_DIR)/profiles/$@ --build=missing -s build_type=$(BUILD_TYPE)
cmake -S . -B build/$@ -DCMAKE_TOOLCHAIN_FILE=build/$@/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DTESTNET=$(TESTNET) cmake -S . -B $(BUILD_FOLDER) -DCMAKE_TOOLCHAIN_FILE=$(BUILD_FOLDER)/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DSTATIC=$(STATIC) -DTESTNET=$(TESTNET) -DBUILD_VERSION=$(BUILD_VERSION)
cmake --build build/$@ --config=$(BUILD_TYPE) --parallel=$(CPU_CORES) cmake --build $(BUILD_FOLDER) --config=$(BUILD_TYPE) --parallel=$(CPU_CORES)
(cd $(BUILD_FOLDER) && cpack)
help: help:
@echo "Lethean VPN Blockchain"
@echo "======================"
@echo "Website: https://lt.hn"
@echo "GitHub: https://github.com/letheanVPN/blockchain/"
@echo "Discord: https://discord.lt.hn"
@echo ""
@echo "Available targets:" @echo "Available targets:"
@printf " %-42s %s\n" "make clean" "Clean all build directories" @printf " %-42s %s\n" "make clean" "Clean all build directories"
@printf " %-42s %s\n" "make conan-get" "Download and install conan locally"
@printf " %-42s %s\n" "make release" "Build release" @printf " %-42s %s\n" "make release" "Build release"
@printf " %-42s %s\n" "make static" "Build static release" @printf " %-42s %s\n" "make testnet" "Build testnet"
@printf " %-42s %s\n" "make debug" "Build debug" @printf " %-42s %s\n" "make mainnet" "Build mainnet"
@printf " %-42s %s\n" "make test" "Build & run tests" @printf " %-42s %s\n" "make test" "Build & run tests"
@printf " %-42s %s\n" "make docs" "Builds offline documentation website" @printf " %-42s %s\n" "make docs" "Builds offline documentation website"
@printf " %-42s %s\n" "make docs-dev" "Runs local doc server, for editing/adding docs" @printf " %-42s %s\n" "make docs-dev" "Runs local doc server, for editing/adding docs"
@printf " %-42s %s\n" "make conan-profile-detect" "Creates host config" @printf " %-42s %s\n" "make conan-profile-detect" "Creates host config"
@printf " %-42s %s\n" "make configure" "Runs a cmake configure within conan build flow" @printf " %-42s %s\n" "make configure" "Runs a cmake configure within conan build flow"
@printf "\n --- Conan Cross-Compilation Profiles ---\n"
@$(foreach profile,$(SORTED_PROFILES),printf " %-42s %s\n" "make $(profile)" "Build the $(profile) profile";) @$(foreach profile,$(SORTED_PROFILES),printf " %-42s %s\n" "make $(profile)" "Build the $(profile) profile";)
@printf "\n --- SDK Generation ---\n"
@printf " %-42s %s\n" "make sdk" "Build all SDK packages"
@$(foreach sdk,$(SORTED_SDK_TARGETS),printf " %-42s %s\n" "make sdk $(sdk)" "Build the $(sdk) SDK package";)
@printf "\n"
@printf " %-42s %s\n" "make help" "Show this help message" @printf " %-42s %s\n" "make help" "Show this help message"
#
# Tests
#
test: test-release test: test-release
test-release: test-release:
@echo "Building profile: test-release" @echo "Building profile: test-release"
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/test-release --build=missing -s build_type=$(BUILD_TYPE) CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) install . --output-folder=build/test-release --build=missing -s build_type=$(BUILD_TYPE)
cmake -S . -B build/test-release -DCMAKE_TOOLCHAIN_FILE=build/test-release/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -D BUILD_TESTS=ON cmake -S . -B build/test-release -DCMAKE_TOOLCHAIN_FILE=build/test-release/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -D BUILD_TESTS=ON
cmake --build build/test-release --config=Release --parallel=$(CPU_CORES) cmake --build build/test-release --config=Release --parallel=$(CPU_CORES)
$(MAKE) test $(MAKE) test
test-debug: test-debug:
@echo "Building profile: test-debug" @echo "Building profile: test-debug"
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/test-debug --build=missing -s build_type=$(BUILD_TYPE) CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) install . --output-folder=build/test-debug --build=missing -s build_type=$(BUILD_TYPE)
cmake -S . -B build/test-debug -DCMAKE_TOOLCHAIN_FILE=build/test-debug/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -D BUILD_TESTS=ON cmake -S . -B build/test-debug -DCMAKE_TOOLCHAIN_FILE=build/test-debug/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -D BUILD_TESTS=ON
cmake --build build/test-debug --config=Debug --parallel=$(CPU_CORES) cmake --build build/test-debug --config=Debug --parallel=$(CPU_CORES)
$(MAKE) test $(MAKE) test
configure: # Conan management — cmake modules from .build submodule
@echo "Running Config: release" conan-get:
CONAN_HOME=$(CONAN_CACHE) conan install . --output-folder=build/release --build=missing -s build_type=$(BUILD_TYPE) cmake -P $(CMAKE_DIR)/ConanGet.cmake
cmake -S . -B build/release -DCMAKE_TOOLCHAIN_FILE=build/release/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) ifneq ($(CONAN_USER),)
(CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) remote add conan_build $(CONAN_URL) && \
CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) remote login conan_build $(CONAN_USER) -p $(CONAN_PASSWORD)) || true
endif
docs: configure conan-upload:
@echo "Building Documentation" CONAN_HOME=$(CONAN_CACHE) $(CONAN_EXECUTABLE) upload "*" -r=conan_build --confirm
cmake --build build/release --target=docs --config=Release --parallel=$(CPU_CORES)
conan-profile-detect: conan-get
cmake -P $(CMAKE_DIR)/ConanProfileSetup.cmake
docs-dev: configure docs-dev: configure
@echo "Building Documentation" @echo "Building Documentation"
cmake --build build/release --target=serve_docs --config=Release cmake --build build/release --target=serve_docs --config=Release
docker-chain-node: $(SDK_TARGETS):
@echo "Building docker image: lthn/chain" @# This is a proxy target. Handled by the 'sdk' rule.
docker buildx build -f $(CC_DOCKER_FILE) -t lthn/chain $(CURDIR)
docker-cc-linux-amd64:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-amd64 --platform linux/amd64 $(CURDIR)
docker-cc-linux-armv7:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-armv7 --platform linux/arm/v7 $(CURDIR)
docker-cc-linux-arm64v8:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-arm64v8 --platform linux/arm64/v8 $(CURDIR)
docker-cc-linux-ppc64le:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-ppc64le --platform linux/ppc64le $(CURDIR)
docker-cc-linux-riscv64:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-riscv64 --platform linux/riscv64 $(CURDIR)
docker-cc-linux-s390x:
docker buildx build -f $(CC_DOCKER_FILE) --target build-artifacts --output type=local,dest=build/cc-linux-s390x --platform linux/s390x $(CURDIR)
clean: clean:
@cmake -P $(CMAKE_DIR)/CleanBuild.cmake
clean-build: clean
rm -rf build rm -rf build
tags: tags:
ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest
.PHONY: all release docker-chain-node debug docs docs-dev configure static static-release test test-release test-debug clean tags conan-profile-detect $(PROFILES) .PHONY: all release upload-conan-cache docs docs-dev configure static static-release test test-release test-debug clean tags conan-profile-detect conan-get $(PROFILES) sdk $(SDK_TARGETS)

209
PLAN-NAME-REGISTRATION.md Normal file
View file

@ -0,0 +1,209 @@
# Mainnet Name Registration Plan
> **Status:** Validating on testnet
> **Date:** 2026-04-03
> **Authors:** Snider, Charon
## Problem
The Lethean chain merges two blockchains — a main chain (aliases) and an HNS sidechain (DNS). The sidechain blocks Alexa top 100K domains and ICANN TLDs from being registered by random users. But the main chain has no such protection — anyone could register `@google` as an alias before the sidechain has a chance to refuse it.
This creates a window for name squatting that corrupts the namespace before real users arrive.
## Numbers
| Category | Count |
|----------|-------|
| Reserved (Alexa top 100K) | 90,016 |
| Locked (ICANN TLDs) | 11,554 |
| **Total unique names** | **90,041** |
| Long names (>=6 chars, public) | 73,977 |
| Short names (<6 chars, need authority key) | 16,062 |
**Source:** `blockchain-network-dcore/lib/covenants/names.json` and `lockup.json`
## Strategy
### Phase 1: Genesis + HF Warmup
1. Mainnet launches with HF0 — 10M LTHN premine in SWAP wallet
2. During HF warmup (HF0 → HF1), send **1,000+ LTHN** from genesis to dedicated namereg wallets
3. Multiple namereg wallets (2-4) for parallel registration
4. Destination for all reserved aliases: a **multi-sig wallet** controlled by the team
### Phase 2: Staking Funds the Protection
1. Network wallet stakes during warmup — earns ~720 LTHN/day from PoS
2. Legacy users haven't reclaimed tokens yet (SWAP happens later)
3. Staking rewards from the network's own balance fund all registrations
4. The network literally pays for its own name protection
### Phase 3: Batch Registration
When aliases activate (HF that enables alias registration):
1. Namereg wallets already have coins and mature UTXOs ready
2. Multiple wallets work in parallel, each tackling a chunk of the 90K list
3. Priority order:
- **Tier 1:** Top brands (google, facebook, amazon, etc) — ~120 names
- **Tier 2:** Long names from Alexa list (>=6 chars) — ~73,977 names
- **Tier 3:** Short names with authority key (<6 chars) ~16,062 names
4. Rate: ~1 alias per 3 seconds per wallet = ~28,800/day with 1 wallet, ~115,200/day with 4
### Phase 4: Ongoing Governance
1. All reserved names sit in a multi-sig wallet
2. Legitimate brand owners can request transfer (proof of domain ownership)
3. Community aliases (common words like "wallet", "exchange") remain locked
4. Infrastructure names (@vpn, @proxy, @exit, etc) transferred to service operators
## Cost Model
| Item | Cost |
|------|------|
| Alias registration fee | 1 LTHN each |
| Transaction fee | 0.01 LTHN each |
| **Total for 90K names** | **~90,900 LTHN** |
| PoS earnings (720/day) | Covered in ~126 days |
| With 1000 LTHN seed | First ~1000 names immediate |
The network earns back the registration cost through staking before legacy users even begin the SWAP process.
## Technical Requirements
### Testnet Validation (current)
- [x] PoS staking working (first PoS block at height 12,382)
- [x] Alias registration via wallet RPC confirmed
- [x] Batch registration script built and tested
- [x] Priority name list generated from HNS data (90,041 names)
- [ ] Multi-wallet parallel registration tested
- [ ] Authority key for short names (<6 chars) tested
- [ ] Full 90K registration completed on testnet
- [ ] Explorer confirms all names visible
- [ ] LNS resolves registered names
### Mainnet Requirements
- [ ] Multi-sig wallet created for reserved names
- [ ] Genesis transaction plan (SWAP wallet → namereg wallets)
- [ ] Authority key provisioned for short-name registration
- [ ] Ansible playbook for deploying namereg wallets on prod
- [ ] Monitoring: alias count dashboard, registration rate, failures
## Alias Comment Format
All reserved names use this comment format for identification:
```
v=lthn1;type=reserved;reason=hns-protected
```
This allows:
- LNS to identify reserved vs user-registered names
- Future tools to query reserved names
- Governance decisions (release to brand owners) to be automated
## Daemon Configuration
PoS staking requires `--rpc-ignore-offline` when the daemon has no peers:
```
lethean-chain-node --rpc-ignore-offline --do-pos-mining
```
Without this flag, the daemon refuses PoS mining requests when disconnected.
## Batch Registration Tool
```bash
# Generate priority list from HNS data
python3 tools/generate-name-list.py
# Register names (3s delay, checks balance every 10)
bash tools/register-reserved.sh /tmp/protected-names-long.txt http://127.0.0.1:46944/json_rpc 10 3
```
Tool location: `docker/tools/register-reserved.sh`
## Option B: TLD Registrar Model (Recommended)
Instead of racing to pre-register 90K names, change one constant to make
ALL alias registration require the authority key:
```c
// currency_config.h — one line change
#define ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED 64 // was 6
```
This makes Lethean a proper TLD registrar — every name under `.lthn`
requires authority signature. No squatting possible at any length.
### Why This Is Better
| Pre-reg (Option A) | Registrar (Option B) |
|---------------------|----------------------|
| Race against squatters | No race — authority controls all |
| 90K transactions needed | Zero pre-registration needed |
| ~90K LTHN cost | Zero cost |
| Only covers known names | Covers ALL names, forever |
| New brands unprotected | New brands protected by default |
### Registrar Portal Flow
1. User requests `@myname` via website or CLI
2. Portal checks: not taken, not reserved, not offensive
3. User pays registration fee (1 LTHN + portal fee if desired)
4. Authority key signs the registration transaction
5. Name goes live on chain within 1 block
### Revenue Potential
| Name Type | Price |
|-----------|-------|
| Standard (6+ chars) | 1 LTHN (chain fee only) |
| Short (3-5 chars) | 10-100 LTHN (premium) |
| Ultra-short (1-2 chars) | Auction or reserved |
### Implementation
- **Hardfork:** Change `ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED` to 64
- **Portal:** Web API that accepts requests, validates, signs with authority key
- **Key security:** Authority private key in HSM or multi-sig, never on a hot server
- **Delegation:** Portal signs, daemon validates — separation of concerns
### Why Lethean Should Be a Registrar
- Lethean owns `.lthn` on Handshake — it IS the TLD operator
- Names route real traffic (VPN, DNS, service discovery)
- A curated namespace is trustworthy; a squatted one is worthless
- Every TLD in the world works this way — `.com`, `.co.uk`, `.eth`
- Revenue stream from name sales funds network development
### Migration Path
1. Testnet: validate both approaches (pre-reg + registrar)
2. HF proposal: include the constant change in next hardfork
3. Build portal: simple web UI + authority signing service
4. Mainnet launch: registrar model active from HF activation
5. Pre-reg only needed for names registered BEFORE the HF
## Risk Mitigations
| Risk | Mitigation |
|------|-----------|
| Tx pool congestion | Multiple wallets, 3s delay, batch checkpoints |
| Insufficient funds | Staking covers ongoing costs, seed from genesis |
| Authority key compromise | Multi-sig for the key, not single holder |
| Name disputes post-launch | Governance process for brand transfers |
| Testnet/mainnet drift | Same tooling, same scripts, validated on testnet first |
## Timeline
| Phase | When | Duration |
|-------|------|----------|
| Testnet validation | Now (Apr 2026) | 1-2 weeks |
| Mainnet genesis | TBD (Darbs approval) | Day 0 |
| HF warmup | Day 0-7 | 1 week |
| Batch registration | Day 7+ | 1-4 days (with parallel wallets) |
| Full coverage | Day 14 | All 90K protected |

252
README.md
View file

@ -1,196 +1,120 @@
[![Coverity Scan](https://scan.coverity.com/projects/18767/badge.svg)](https://scan.coverity.com/projects/zanoproject) # Lethean Network—Ethics, Encoded.
[![Discord](https://img.shields.io/discord/538361472691077130?label=discord&logo=discord)](https://discord.gg/wE3rmYY)
## Cloning > We are building upto a mainnet launch in 2026, documentation written as if mainnet is live.
Be sure to clone the repository properly:\ A buildkit for deploying confidential information networks and commerce systems with immutable auditability.
`$ git clone --recursive https://github.com/hyle-team/zano.git`
# Building Free for commercial, private, and patent use, self-host or join the community-run network that guarantees participant sovereignty by design.
--------
[![Discord](https://img.shields.io/discord/379876792003067906?label=discord&logo=discord)](https://discord.gg/pfgT2Kz)
Web2 Website: https://lt.hn/
Web3 Network Gateway [HNS](https://handshake.org): [https://lthn](https://www.namebase.io/domains/lthn)
<br/>_(our chain aliases will come with a working Web2(`*.lt.hn`)+Web3(`*.lthn`) domain name)_
### Dependencies ### Dependencies
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested | | component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|-----------------------------------------------------------------------------------------------------|--------------------------------------------|----------------|-----------------------------------------| |-----------------------------------------------------------------------------|--------------------------------------------|----------------|-----------------------------------------|
| gcc (Linux) | 8.4.0 | 9.4.0 | 12.3.0 | | gcc (Linux) | 8.4.0 | 9.4.0 | 12.3.0 |
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 | | llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2022 (17.11.5) | 2022 (17.12.3) | | [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2022 (17.11.5) | 2022 (17.12.3) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 15.2 | | [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 15.2 |
| [CMake](https://cmake.org/download/) | 3.26.3 | 3.26.3 | 3.31.6 | | [CMake](https://cmake.org/download/) | 3.26.3 | 3.26.3 | 3.31.6 |
| [Boost](https://www.boost.org/users/download/) | 1.75 | 1.84 | 1.84 |
| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | 1.1.1n | 1.1.1w | 3.4 |
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 6.8.3 | 6.8.3 | 6.8.3 |
Note:\ ## Cloning
[*server version*] denotes steps required for building command-line tools (daemon, simplewallet, etc.).\
[*GUI version*] denotes steps required for building Zano executable with GUI.
<br /> Be sure to clone the repository properly, with `--recursive` flag, or you'll get angry:<br/>
`git clone --recursive https://github.com/letheanVPN/blockchain.git`
### Linux # Building
Recommended OS versions: Ubuntu 20.04, 22.04 LTS. The project uses a `Makefile` that provides a simple and powerful interface for building.
It automatically handles dependency installation with Conan and compilation with CMake.
1. Prerequisites You need CMake and Make installed on your system, other than that you don't need to worry about Python, Conan, Boost, OpenSSL, or any other dependencies.
[*server version*] The final packages are created as they are due to a historical distribution method used in china: USB Stick, CD, DVD, etc.
sudo apt-get install -y build-essential g++ curl autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev libssl-dev bzip2
[*GUI version*]
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev libssl-dev bzip2 mesa-common-dev libglu1-mesa-dev We use CPack, so our packages are self-contained, have searchable HTML documentation, and are ready to be installed on any system.
Make sure you have correct versions installed (see 'Dependencies' section above): To skip the packing step, use `make build` as defined in the section below for Advanced Build Customization
cmake --version && gcc --version ## Simple Workflow Builds (Recommended)
3. Clone Zano into a local folder\ For most use cases, these two commands are all you need. They handle the entire build process from start to finish.
(If for some reason you need to use alternative Zano branch, change 'master' to the required branch name.)
git clone --recursive https://github.com/hyle-team/zano.git -b master
In the following steps we assume that you cloned Zano into '~/zano' folder in your home directory. * **Build for Mainnet:**
```shell
make mainnet
```
4. Download and build Boost\ * **Build for Testnet:**
(Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, **edit line 4** accordingly.) ```shell
make testnet
```
curl -OL https://archives.boost.io/release/1.84.0/source/boost_1_84_0.tar.bz2 ## Creating Release Packages
echo "cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454 boost_1_84_0.tar.bz2" | shasum -c && tar -xjf boost_1_84_0.tar.bz2
rm boost_1_84_0.tar.bz2 && cd boost_1_84_0
./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log
./b2 && cd ..
Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end.
5. Install Qt\ To create distributable packages (e.g., `.zip`, `.msi`, `.pkg`, `.deb`), run the `release` target. This will build the project, build the documentation, and then package everything.
(*GUI version only, skip this step if you're building server version*)
[*GUI version*] ```shell
make release TESTNET=1
```
The final packages will be located in the `build/packages/` directory
curl -L -O https://download.qt.io/official_releases/online_installers/qt-online-installer-linux-x64-online.run && ## Advanced Build Customization (Makefile Variables)
chmod u+x qt-online-installer-linux-x64-online.run
./qt-online-installer-linux-x64-online.run \
--accept-licenses \
--default-answer \
--confirm-command install \
qt.qt6.683.linux_gcc_64 \
qt.qt6.683.addons.qt5compat.linux_gcc_64 \
qt.qt6.683.addons.qtpositioning.linux_gcc_64 \
qt.qt6.683.addons.qtwebchannel.linux_gcc_64 \
qt.qt6.683.addons.qtwebsockets.linux_gcc_64 \
qt.qt6.683.addons.qtwebengine.linux_gcc_64 \
qt.qt6.683.addons.qtwebview.linux_gcc_64
This will download the online installer and perform an unattended installation with the Chromium-based WebEngine
For advanced use cases, you can override variables in the `Makefile` to customize the build process.
6. Install OpenSSL * **Build a `testnet` version:**
```shell
make build TESTNET=1
```
* **Build a statically-linked version:**
```shell
make build STATIC=1
```
* **Build a Debug build with 8 compile threads:**
```shell
make build BUILD_TYPE=Debug CPU_CORES=8
```
* **Use custom CMakePresets:**
```shell
make build PRESET_CONFIGURE=my-config-preset PRESET_BUILD=my-build-preset
```
We recommend installing OpenSSL v1.1.1w locally unless you would like to use the same version system-wide.\ | Variable | Description | Default Value |
(Assuming that `$HOME` environment variable is set to your home directory. Otherwise, edit line 4 accordingly.) |--------------------|------------------------------------------------------------------------|-------------------------|
| `BUILD_TYPE` | Sets the build configuration (e.g., `Release`, `Debug`). | `Release` |
| `TESTNET` | Set to `1` to build for the test network. | `0` |
| `STATIC` | Set to `1` to link libraries statically. | `0` |
| `CPU_CORES` | Number of CPU cores to use for parallel compilation. | Auto-detected |
| `BUILD_VERSION` | The version string to embed in the binaries. | `6.0.1` |
| `BUILD_FOLDER` | The output directory for the build. | `build/release` |
| `PRESET_CONFIGURE` | The CMake preset to use for the `configure` step. | `conan-release` |
| `PRESET_BUILD` | The CMake preset to use for the `build` step. | `conan-release` |
| `CONAN_CACHE` | The path for the local Conan cache, where the dependencies are stored. | `./build/sdk` |
| `CONAN_EXECUTABLE` | The path to the usable Conan executable. | `./build/bin/conan` |
| `CONAN_URL` | The URL for the Conan remote repository. | `artifacts.host.uk.com` |
| `CONAN_USER` | The username for the Conan remote. | `public` |
| `CONAN_PASSWORD` | The password for the Conan remote. | |
curl -OL https://www.openssl.org/source/openssl-1.1.1w.tar.gz ## Cleaning the Build Directory
echo "cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8 openssl-1.1.1w.tar.gz" | shasum -c && tar xaf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w/
./config --prefix=$HOME/openssl --openssldir=$HOME/openssl shared zlib
make && make test && make install && cd ..
ALWAYS USE `make clean` to clean the build directory, manually deleting the `build/release`, `build/SOME_FOLDER` will cause you issues.
7. [*OPTIONAL*] Set global environment variables for convenient use\ Our `make clean` triggers a cmake script that completely resets the build directory &amp; dynamically added CMakePresets to its cached warm-up state,
For instance, by adding the following lines to `~/.bashrc` the selective clean script can be edited here: `cmake/CleanBuild.cmake` or directly run from the repo root `cmake -P cmake/CleanBuild.cmake`
[*server version*] You can NUKE the build directory with `make clean-build` which is `rm -rf build`.
export BOOST_ROOT=/home/user/boost_1_84_0 If you do manually delete build folders and get CMake errors (if you have compiled anything previously, you will),
export OPENSSL_ROOT_DIR=/home/user/openssl the ConanPresets.json file has entries in the `include` property, delete them all and try again.
This happens because CMakePresets.json includes ConanPresets.json, that has the list of toolchains to use that gets populated during the CMake config step,
[*GUI version*] when you manually delete a folder, the toolchain is now a broken path, and CMake throws a fatal error.
export BOOST_ROOT=/home/user/boost_1_84_0
export OPENSSL_ROOT_DIR=/home/user/openssl
export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64
**NOTICE: Please edit the lines above according to your actual paths.**
**NOTICE 2:** Make sure you've restarted your terminal session (by reopening the terminal window or reconnecting the server) to apply these changes.
8. Build the binaries
1. If you skipped step 6 and did not set the environment variables:
cd zano && mkdir build && cd build
BOOST_ROOT=$HOME/boost_1_84_0 OPENSSL_ROOT_DIR=$HOME/openssl cmake ..
make -j1 daemon simplewallet
2. If you set the variables in step 6:
cd zano && mkdir build && cd build
cmake ..
make -j1 daemon simplewallet
or simply:
cd zano && make -j1
**NOTICE**: If you are building on a machine with a relatively high amount of RAM or with the proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution.
**NOTICE 2**: If you'd like to build binaries for the testnet, use `cmake -D TESTNET=TRUE ..` instead of `cmake ..` .
1. Build GUI:
cd zano
utils/build_script_linux.sh
Look for the binaries in `build` folder
<br />
### Windows
Recommended OS version: Windows 7 x64, Windows 11 x64.
1. Install required prerequisites (Boost, Qt, CMake, OpenSSL).
2. Edit paths in `utils/configure_local_paths.cmd`.
3. Run one of `utils/configure_win64_msvsNNNN_gui.cmd` according to your MSVC version.
4. Go to the build folder and open generated Zano.sln in MSVC.
5. Build.
In order to correctly deploy Qt GUI application, you also need to do the following:
6. Run `PATH_TO_QT\bin\windeployqt.exe PATH_TO_PROJECT_ROOT\build\src\Debug\Zano.exe` (choose the Debug or Release folder depending on the configuration you built).
7. You can now run the application using one of the following options:
* Start the program from Visual Studio
* Run `Zano.exe --html-path=PATH_TO_HTML`, where PATH_TO_HTML is by default located at PATH_TO_PROJECT_ROOT\src\gui\qt-daemon\layout\html
* Copy the contents of PATH_TO_PROJECT_ROOT\src\gui\qt-daemon\layout\html to a folder named "html" located in the same directory as the Zano.exe binary.
<br />
### macOS
Recommended OS version: macOS Big Sur 11.4 x64.
1. Install required prerequisites.
2. Set environment variables as stated in `utils/macosx_build_config.command`.
3. `mkdir build` <br> `cd build` <br> `cmake ..` <br> `make`
To build GUI application:
1. Create self-signing certificate via Keychain Access:\
a. Run Keychain Access.\
b. Choose Keychain Access > Certificate Assistant > Create a Certificate.\
c. Use “Zano” (without quotes) as certificate name.\
d. Choose “Code Signing” in “Certificate Type” field.\
e. Press “Create”, then “Done”.\
f. Make sure the certificate was added to keychain "System". If not—move it to "System".\
g. Double click the certificate you've just added, enter the trust section and under "When using this certificate" select "Always trust".\
h. Unfold the certificate in Keychain Access window and double click the underlying private key "Zano". Select "Access Control" tab, then select "Allow all applications to access this item". Click "Save Changes".
2. Revise building script, comment out unwanted steps and run it: `utils/build_script_mac_osx.sh`
3. The application should be here: `/buid_mac_osx_64/release/src`
<br />
<br />
## Supporting project/donations
ZANO @dev<br />
BTC bc1qpa8w8eaehlplfepmnzpd7v9j046899nktxnkxp<br />
BCH qqgq078vww5exd9kt3frx6krdyznmp80hcygzlgqzd<br />
ETH 0x206c52b78141498e74FF074301ea90888C40c178<br />
XMR 45gp9WTobeB5Km3kLQgVmPJkvm9rSmg4gdyHheXqXijXYMjUY48kLgL7QEz5Ar8z9vQioQ68WYDKsQsjAEonSeFX4UeLSiX<br />

View file

@ -1,79 +0,0 @@
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CPACK_PACKAGE_NAME "${package_name}")
set(CPACK_PACKAGE_VENDOR "${package_vendor}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${package_description}")
set(CPACK_PACKAGE_VERSION "${BUILD_VERSION}")
set(CPACK_PACKAGE_CONTACT "${package_contact}")
set(CPACK_PACKAGE_HOMEPAGE_URL "${package_website}")
# set(CPACK_PACKAGING_INSTALL_PREFIX "/usr/local") # Linux/macOS default
# if(WIN32)
# set(CPACK_PACKAGING_INSTALL_PREFIX "C:/Program Files/${PROJECT_NAME}")
# endif()
if(APPLE)
if("${package_macos_installer}" STREQUAL "DMG")
set(CPACK_GENERATOR "DragNDrop")
# set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/resources/dmg_background.png")
set(CPACK_DMG_VOLUME_NAME "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}")
message(STATUS "Registered CPACK_GENERATOR: DragNDrop")
else ()
set(CPACK_GENERATOR "productbuild")
set(CPACK_PRODUCTBUILD_IDENTIFIER "${package_macos_pkg_productbuild_identifier}")
# set(CPACK_PRODUCTBUILD_SIGNING_IDENTITY "Developer ID Installer: Your Company (TEAMID)")
message(STATUS "Registered CPACK_GENERATOR: productbuild")
endif ()
elseif(WIN32)
set(CPACK_GENERATOR "WIX")
message(STATUS "Registered CPACK_GENERATOR: WIX")
# set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/resources/windows_icon.ico")
# set(CPACK_WIX_LICENSE_RTF "${CMAKE_SOURCE_DIR}/LICENSE.rtf")
# set(CPACK_WIX_UPGRADE_GUID "D3F5A9C1-4B2E-4F5A-9C71-123456789ABC") # change once per major version
else()
set(CPACK_GENERATOR "DEB")
message(STATUS "Registered CPACK_GENERATOR: deb")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${package_contact}")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28)")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
# postinstall script (e.g., to register a systemd service)
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
# "${CMAKE_SOURCE_DIR}/scripts/postinstall.sh")
endif()
list(APPEND CPACK_GENERATOR "TXZ" "ZIP")
message(STATUS "Registered CPACK_GENERATOR: tgz")
message(STATUS "Registered CPACK_GENERATOR: zip")
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_ARCHIVE_COMPONENT_INSTALL OFF)
set(CPACK_COMPONENTS_ALL)
set(CPACK_GENERATE_SHASUM ON)
set(CPACK_SHASUM_ALGORITHM SHA256)
message(STATUS "Using SHA256 Checksums")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.txt")
# set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/packages")
install(FILES README.md LICENSE.txt
DESTINATION "share/doc/${CPACK_PACKAGE_NAME}"
)
set(_arch "${CMAKE_SYSTEM_PROCESSOR}")
if(_arch MATCHES "AMD64|x86_64")
set(_arch "x86_64")
elseif(_arch MATCHES "arm64|aarch64")
set(_arch "arm64")
endif()
string(TOLOWER "${CMAKE_SYSTEM_NAME}" _sys_name_lc)
set(CPACK_PACKAGE_FILE_NAME
"${package_name}-${CPACK_PACKAGE_VERSION}-${_sys_name_lc}-${_arch}")
include(CPack)
endif()

View file

@ -1,45 +0,0 @@
set(MKDOCS_SRC "${CMAKE_SOURCE_DIR}/docs")
set(MKDOCS_OUT "${CMAKE_BINARY_DIR}/../docs")
message("MKDocs src: ${MKDOCS_SRC} > ${MKDOCS_OUT}")
file(MAKE_DIRECTORY "${MKDOCS_OUT}")
add_custom_target(docs
COMMAND ${CMAKE_COMMAND} -E env PYTHONUNBUFFERED=1
mkdocs build
--clean
--site-dir "${MKDOCS_OUT}"
--config-file "${MKDOCS_SRC}/mkdocs.yml"
WORKING_DIRECTORY "${MKDOCS_SRC}"
COMMENT "Generating documentation with MkDocs"
VERBATIM
)
# Optional install step
install(DIRECTORY "${MKDOCS_OUT}/"
DESTINATION "share/doc/${PROJECT_NAME}")
add_custom_target(install-docs
DEPENDS docs
COMMAND "${CMAKE_COMMAND}" --install . --component docs
COMMENT "Installing documentation")
# Name of the target that launches the dev server
add_custom_target(
serve_docs # invoke with `make serve_docs`
COMMAND ${CMAKE_COMMAND} -E env PYTHONUNBUFFERED=1
# On Windows we need to run the command through the shell
# so that the `&&` operator works correctly.
${CMAKE_COMMAND} -E env
mkdocs serve
--dev-addr "127.0.0.1:8000" # optional explicit bind address
--watch "${MKDOCS_SRC}" # watch source files for changes
--config-file "${MKDOCS_SRC}/mkdocs.yml"
WORKING_DIRECTORY "${MKDOCS_SRC}"
USES_TERMINAL # tells CMake to attach the child process to the console
COMMENT "Starting MkDocs livepreview server (CtrlC to stop)"
VERBATIM
)
add_dependencies(serve_docs docs) # ensures the static site is uptodate before serving

View file

@ -1,682 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2024 JFrog
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
set(CONAN_MINIMUM_VERSION 2.0.5)
# Create a new policy scope and set the minimum required cmake version so the
# features behind a policy setting like if(... IN_LIST ...) behaves as expected
# even if the parent project does not specify a minimum cmake version or a minimum
# version less than this module requires (e.g. 3.0) before the first project() call.
# (see: https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.html)
#
# The policy-affecting calls like cmake_policy(SET...) or `cmake_minimum_required` only
# affects the current policy scope, i.e. between the PUSH and POP in this case.
#
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Policies.html#the-policy-stack
cmake_policy(PUSH)
cmake_minimum_required(VERSION 3.24)
function(detect_os os os_api_level os_sdk os_subsystem os_version)
# it could be cross compilation
message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(${os} Macos PARENT_SCOPE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(${os} Neutrino PARENT_SCOPE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
set(${os} Windows PARENT_SCOPE)
set(${os_subsystem} cygwin PARENT_SCOPE)
elseif(CMAKE_SYSTEM_NAME MATCHES "^MSYS")
set(${os} Windows PARENT_SCOPE)
set(${os_subsystem} msys2 PARENT_SCOPE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L17C1-L17C34
set(${os} Emscripten PARENT_SCOPE)
else()
set(${os} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
if(DEFINED ANDROID_PLATFORM)
string(REGEX MATCH "[0-9]+" _os_api_level ${ANDROID_PLATFORM})
elseif(DEFINED CMAKE_SYSTEM_VERSION)
set(_os_api_level ${CMAKE_SYSTEM_VERSION})
endif()
message(STATUS "CMake-Conan: android api level=${_os_api_level}")
set(${os_api_level} ${_os_api_level} PARENT_SCOPE)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
# CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja
# generators, but just has the original input string for Xcode.
if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT})
set(_os_sdk ${CMAKE_OSX_SYSROOT})
else()
if(CMAKE_OSX_SYSROOT MATCHES Simulator)
set(apple_platform_suffix simulator)
else()
set(apple_platform_suffix os)
endif()
if(CMAKE_OSX_SYSROOT MATCHES AppleTV)
set(_os_sdk "appletv${apple_platform_suffix}")
elseif(CMAKE_OSX_SYSROOT MATCHES iPhone)
set(_os_sdk "iphone${apple_platform_suffix}")
elseif(CMAKE_OSX_SYSROOT MATCHES Watch)
set(_os_sdk "watch${apple_platform_suffix}")
endif()
endif()
if(DEFINED os_sdk)
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
set(${os_sdk} ${_os_sdk} PARENT_SCOPE)
endif()
if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(${os_version} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
endif()
endif()
endif()
endfunction()
function(detect_arch arch)
# CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one.
# Therefore this code only finds one. If the recipes support multiple architectures, the
# build will work. Otherwise, there will be a linker error for the missing architecture(s).
if(DEFINED CMAKE_OSX_ARCHITECTURES)
string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}")
list(LENGTH apple_arch_list apple_arch_count)
if(apple_arch_count GREATER 1)
message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS" AND NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
set(host_arch ${CMAKE_OSX_ARCHITECTURES})
elseif(MSVC)
set(host_arch ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID})
else()
set(host_arch ${CMAKE_SYSTEM_PROCESSOR})
endif()
if(host_arch MATCHES "aarch64|arm64|ARM64")
set(_arch armv8)
elseif(host_arch MATCHES "armv7|armv7-a|armv7l|ARMV7")
set(_arch armv7)
elseif(host_arch MATCHES armv7s)
set(_arch armv7s)
elseif(host_arch MATCHES "i686|i386|X86")
set(_arch x86)
elseif(host_arch MATCHES "AMD64|amd64|x86_64|x64")
set(_arch x86_64)
endif()
if(EMSCRIPTEN)
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L294C1-L294C80
set(_arch wasm)
endif()
message(STATUS "CMake-Conan: cmake_system_processor=${_arch}")
set(${arch} ${_arch} PARENT_SCOPE)
endfunction()
function(detect_cxx_standard cxx_standard)
set(${cxx_standard} ${CMAKE_CXX_STANDARD} PARENT_SCOPE)
if(CMAKE_CXX_EXTENSIONS)
set(${cxx_standard} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
endif()
endfunction()
macro(detect_gnu_libstdcxx)
# _conan_is_gnu_libstdcxx true if GNU libstdc++
check_cxx_source_compiles("
#include <cstddef>
#if !defined(__GLIBCXX__) && !defined(__GLIBCPP__)
static_assert(false);
#endif
int main(){}" _conan_is_gnu_libstdcxx)
# _conan_gnu_libstdcxx_is_cxx11_abi true if C++11 ABI
check_cxx_source_compiles("
#include <string>
static_assert(sizeof(std::string) != sizeof(void*), \"using libstdc++\");
int main () {}" _conan_gnu_libstdcxx_is_cxx11_abi)
set(_conan_gnu_libstdcxx_suffix "")
if(_conan_gnu_libstdcxx_is_cxx11_abi)
set(_conan_gnu_libstdcxx_suffix "11")
endif()
unset (_conan_gnu_libstdcxx_is_cxx11_abi)
endmacro()
macro(detect_libcxx)
# _conan_is_libcxx true if LLVM libc++
check_cxx_source_compiles("
#include <cstddef>
#if !defined(_LIBCPP_VERSION)
static_assert(false);
#endif
int main(){}" _conan_is_libcxx)
endmacro()
function(detect_lib_cxx lib_cxx)
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
message(STATUS "CMake-Conan: android_stl=${CMAKE_ANDROID_STL_TYPE}")
set(${lib_cxx} ${CMAKE_ANDROID_STL_TYPE} PARENT_SCOPE)
return()
endif()
include(CheckCXXSourceCompiles)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
detect_gnu_libstdcxx()
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
set(${lib_cxx} "libc++" PARENT_SCOPE)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
# Check for libc++
detect_libcxx()
if(_conan_is_libcxx)
set(${lib_cxx} "libc++" PARENT_SCOPE)
return()
endif()
# Check for libstdc++
detect_gnu_libstdcxx()
if(_conan_is_gnu_libstdcxx)
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
return()
endif()
# TODO: it would be an error if we reach this point
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# Do nothing - compiler.runtime and compiler.runtime_type
# should be handled separately: https://github.com/conan-io/cmake-conan/pull/516
return()
else()
# TODO: unable to determine, ask user to provide a full profile file instead
endif()
endfunction()
function(detect_compiler compiler compiler_version compiler_runtime compiler_runtime_type)
if(DEFINED CMAKE_CXX_COMPILER_ID)
set(_compiler ${CMAKE_CXX_COMPILER_ID})
set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
else()
if(NOT DEFINED CMAKE_C_COMPILER_ID)
message(FATAL_ERROR "C or C++ compiler not defined")
endif()
set(_compiler ${CMAKE_C_COMPILER_ID})
set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
endif()
message(STATUS "CMake-Conan: CMake compiler=${_compiler}")
message(STATUS "CMake-Conan: CMake compiler version=${_compiler_version}")
if(_compiler MATCHES MSVC)
set(_compiler "msvc")
string(SUBSTRING ${MSVC_VERSION} 0 3 _compiler_version)
# Configure compiler.runtime and compiler.runtime_type settings for MSVC
if(CMAKE_MSVC_RUNTIME_LIBRARY)
set(_msvc_runtime_library ${CMAKE_MSVC_RUNTIME_LIBRARY})
else()
set(_msvc_runtime_library MultiThreaded$<$<CONFIG:Debug>:Debug>DLL) # default value documented by CMake
endif()
set(_KNOWN_MSVC_RUNTIME_VALUES "")
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$<CONFIG:Debug>:Debug> MultiThreaded$<$<CONFIG:Debug>:Debug>DLL)
# only accept the 6 possible values, otherwise we don't don't know to map this
if(NOT _msvc_runtime_library IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${_msvc_runtime_library} to Conan settings")
endif()
# Runtime is "dynamic" in all cases if it ends in DLL
if(_msvc_runtime_library MATCHES ".*DLL$")
set(_compiler_runtime "dynamic")
else()
set(_compiler_runtime "static")
endif()
message(STATUS "CMake-Conan: CMake compiler.runtime=${_compiler_runtime}")
# Only define compiler.runtime_type when explicitly requested
# If a generator expression is used, let Conan handle it conditional on build_type
if(NOT _msvc_runtime_library MATCHES "<CONFIG:Debug>:Debug>")
if(_msvc_runtime_library MATCHES "Debug")
set(_compiler_runtime_type "Debug")
else()
set(_compiler_runtime_type "Release")
endif()
message(STATUS "CMake-Conan: CMake compiler.runtime_type=${_compiler_runtime_type}")
endif()
unset(_KNOWN_MSVC_RUNTIME_VALUES)
elseif(_compiler MATCHES AppleClang)
set(_compiler "apple-clang")
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
list(GET VERSION_LIST 0 _compiler_version)
elseif(_compiler MATCHES Clang)
set(_compiler "clang")
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
list(GET VERSION_LIST 0 _compiler_version)
elseif(_compiler MATCHES GNU)
set(_compiler "gcc")
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
list(GET VERSION_LIST 0 _compiler_version)
endif()
message(STATUS "CMake-Conan: [settings] compiler=${_compiler}")
message(STATUS "CMake-Conan: [settings] compiler.version=${_compiler_version}")
if (_compiler_runtime)
message(STATUS "CMake-Conan: [settings] compiler.runtime=${_compiler_runtime}")
endif()
if (_compiler_runtime_type)
message(STATUS "CMake-Conan: [settings] compiler.runtime_type=${_compiler_runtime_type}")
endif()
set(${compiler} ${_compiler} PARENT_SCOPE)
set(${compiler_version} ${_compiler_version} PARENT_SCOPE)
set(${compiler_runtime} ${_compiler_runtime} PARENT_SCOPE)
set(${compiler_runtime_type} ${_compiler_runtime_type} PARENT_SCOPE)
endfunction()
function(detect_build_type build_type)
get_property(multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT multiconfig_generator)
# Only set when we know we are in a single-configuration generator
# Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined
set(${build_type} ${CMAKE_BUILD_TYPE} PARENT_SCOPE)
endif()
endfunction()
macro(set_conan_compiler_if_appleclang lang command output_variable)
if(CMAKE_${lang}_COMPILER_ID STREQUAL "AppleClang")
execute_process(COMMAND xcrun --find ${command}
OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE)
cmake_path(GET _xcrun_out PARENT_PATH _xcrun_toolchain_path)
cmake_path(GET CMAKE_${lang}_COMPILER PARENT_PATH _compiler_parent_path)
if ("${_xcrun_toolchain_path}" STREQUAL "${_compiler_parent_path}")
set(${output_variable} "")
endif()
unset(_xcrun_out)
unset(_xcrun_toolchain_path)
unset(_compiler_parent_path)
endif()
endmacro()
macro(append_compiler_executables_configuration)
set(_conan_c_compiler "")
set(_conan_cpp_compiler "")
set(_conan_rc_compiler "")
set(_conan_compilers_list "")
if(CMAKE_C_COMPILER)
set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\"")
set_conan_compiler_if_appleclang(C cc _conan_c_compiler)
list(APPEND _conan_compilers_list ${_conan_c_compiler})
else()
message(WARNING "CMake-Conan: The C compiler is not defined. "
"Please define CMAKE_C_COMPILER or enable the C language.")
endif()
if(CMAKE_CXX_COMPILER)
set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"")
set_conan_compiler_if_appleclang(CXX c++ _conan_cpp_compiler)
list(APPEND _conan_compilers_list ${_conan_cpp_compiler})
else()
message(WARNING "CMake-Conan: The C++ compiler is not defined. "
"Please define CMAKE_CXX_COMPILER or enable the C++ language.")
endif()
if(CMAKE_RC_COMPILER)
set(_conan_rc_compiler "\"rc\":\"${CMAKE_RC_COMPILER}\"")
list(APPEND _conan_compilers_list ${_conan_rc_compiler})
# Not necessary to warn if RC not defined
endif()
if(NOT "x${_conan_compilers_list}" STREQUAL "x")
string(REPLACE ";" "," _conan_compilers_list "${_conan_compilers_list}")
string(APPEND profile "tools.build:compiler_executables={${_conan_compilers_list}}\n")
endif()
unset(_conan_c_compiler)
unset(_conan_cpp_compiler)
unset(_conan_rc_compiler)
unset(_conan_compilers_list)
endmacro()
function(detect_host_profile output_file)
detect_os(os os_api_level os_sdk os_subsystem os_version)
detect_arch(arch)
detect_compiler(compiler compiler_version compiler_runtime compiler_runtime_type)
detect_cxx_standard(compiler_cppstd)
detect_lib_cxx(compiler_libcxx)
detect_build_type(build_type)
set(profile "")
string(APPEND profile "[settings]\n")
if(arch)
string(APPEND profile arch=${arch} "\n")
endif()
if(os)
string(APPEND profile os=${os} "\n")
endif()
if(os_api_level)
string(APPEND profile os.api_level=${os_api_level} "\n")
endif()
if(os_version)
string(APPEND profile os.version=${os_version} "\n")
endif()
if(os_sdk)
string(APPEND profile os.sdk=${os_sdk} "\n")
endif()
if(os_subsystem)
string(APPEND profile os.subsystem=${os_subsystem} "\n")
endif()
if(compiler)
string(APPEND profile compiler=${compiler} "\n")
endif()
if(compiler_version)
string(APPEND profile compiler.version=${compiler_version} "\n")
endif()
if(compiler_runtime)
string(APPEND profile compiler.runtime=${compiler_runtime} "\n")
endif()
if(compiler_runtime_type)
string(APPEND profile compiler.runtime_type=${compiler_runtime_type} "\n")
endif()
if(compiler_cppstd)
string(APPEND profile compiler.cppstd=${compiler_cppstd} "\n")
endif()
if(compiler_libcxx)
string(APPEND profile compiler.libcxx=${compiler_libcxx} "\n")
endif()
if(build_type)
string(APPEND profile "build_type=${build_type}\n")
endif()
if(NOT DEFINED output_file)
set(file_name "${CMAKE_BINARY_DIR}/profile")
else()
set(file_name ${output_file})
endif()
string(APPEND profile "[conf]\n")
string(APPEND profile "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n")
# propagate compilers via profile
append_compiler_executables_configuration()
if(os STREQUAL "Android")
string(APPEND profile "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n")
endif()
message(STATUS "CMake-Conan: Creating profile ${file_name}")
file(WRITE ${file_name} ${profile})
message(STATUS "CMake-Conan: Profile: \n${profile}")
endfunction()
function(conan_profile_detect_default)
message(STATUS "CMake-Conan: Checking if a default profile exists")
execute_process(COMMAND ${CONAN_COMMAND} profile path default
RESULT_VARIABLE return_code
OUTPUT_VARIABLE conan_stdout
ERROR_VARIABLE conan_stderr
ECHO_ERROR_VARIABLE # show the text output regardless
ECHO_OUTPUT_VARIABLE
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
if(NOT ${return_code} EQUAL "0")
message(STATUS "CMake-Conan: The default profile doesn't exist, detecting it.")
execute_process(COMMAND ${CONAN_COMMAND} profile detect
RESULT_VARIABLE return_code
OUTPUT_VARIABLE conan_stdout
ERROR_VARIABLE conan_stderr
ECHO_ERROR_VARIABLE # show the text output regardless
ECHO_OUTPUT_VARIABLE
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
endfunction()
function(conan_install)
set(conan_output_folder ${CMAKE_BINARY_DIR}/conan)
# Invoke "conan install" with the provided arguments
set(conan_args ${conan_args} -of=${conan_output_folder})
message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN}")
# In case there was not a valid cmake executable in the PATH, we inject the
# same we used to invoke the provider to the PATH
if(DEFINED PATH_TO_CMAKE_BIN)
set(old_path $ENV{PATH})
set(ENV{PATH} "$ENV{PATH}:${PATH_TO_CMAKE_BIN}")
endif()
execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN} --format=json
RESULT_VARIABLE return_code
OUTPUT_VARIABLE conan_stdout
ERROR_VARIABLE conan_stderr
ECHO_ERROR_VARIABLE # show the text output regardless
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
if(DEFINED PATH_TO_CMAKE_BIN)
set(ENV{PATH} "${old_path}")
endif()
if(NOT "${return_code}" STREQUAL "0")
message(FATAL_ERROR "Conan install failed='${return_code}'")
endif()
# the files are generated in a folder that depends on the layout used, if
# one is specified, but we don't know a priori where this is.
# TODO: this can be made more robust if Conan can provide this in the json output
string(JSON conan_generators_folder GET "${conan_stdout}" graph nodes 0 generators_folder)
cmake_path(CONVERT ${conan_generators_folder} TO_CMAKE_PATH_LIST conan_generators_folder)
message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${conan_generators_folder}")
set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${conan_generators_folder}")
# reconfigure on conanfile changes
string(JSON conanfile GET "${conan_stdout}" graph nodes 0 label)
message(STATUS "CMake-Conan: CONANFILE=${CMAKE_SOURCE_DIR}/${conanfile}")
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/${conanfile}")
# success
set_property(GLOBAL PROPERTY CONAN_INSTALL_SUCCESS TRUE)
endfunction()
function(conan_get_version conan_command conan_current_version)
execute_process(
COMMAND ${conan_command} --version
OUTPUT_VARIABLE conan_output
RESULT_VARIABLE conan_result
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(conan_result)
message(FATAL_ERROR "CMake-Conan: Error when trying to run Conan")
endif()
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output})
set(${conan_current_version} ${conan_version} PARENT_SCOPE)
endfunction()
function(conan_version_check)
set(options )
set(one_value_args MINIMUM CURRENT)
set(multi_value_args )
cmake_parse_arguments(conan_version_check
"${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
if(NOT conan_version_check_MINIMUM)
message(FATAL_ERROR "CMake-Conan: Required parameter MINIMUM not set!")
endif()
if(NOT conan_version_check_CURRENT)
message(FATAL_ERROR "CMake-Conan: Required parameter CURRENT not set!")
endif()
if(conan_version_check_CURRENT VERSION_LESS conan_version_check_MINIMUM)
message(FATAL_ERROR "CMake-Conan: Conan version must be ${conan_version_check_MINIMUM} or later")
endif()
endfunction()
macro(construct_profile_argument argument_variable profile_list)
set(${argument_variable} "")
if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE")
set(_arg_flag "--profile:host=")
elseif("${profile_list}" STREQUAL "CONAN_BUILD_PROFILE")
set(_arg_flag "--profile:build=")
endif()
set(_profile_list "${${profile_list}}")
list(TRANSFORM _profile_list REPLACE "auto-cmake" "${CMAKE_BINARY_DIR}/conan_host_profile")
list(TRANSFORM _profile_list PREPEND ${_arg_flag})
set(${argument_variable} ${_profile_list})
unset(_arg_flag)
unset(_profile_list)
endmacro()
macro(conan_provide_dependency method package_name)
set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE)
get_property(_conan_install_success GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
if(NOT _conan_install_success)
find_program(CONAN_COMMAND "conan" REQUIRED)
conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan")
if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE)
conan_profile_detect_default()
endif()
if("auto-cmake" IN_LIST CONAN_HOST_PROFILE)
detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile)
endif()
construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE)
construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE)
if(EXISTS "${CMAKE_SOURCE_DIR}/conanfile.py")
file(READ "${CMAKE_SOURCE_DIR}/conanfile.py" outfile)
if(NOT "${outfile}" MATCHES ".*CMakeDeps.*")
message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile")
endif()
set(generator "")
elseif (EXISTS "${CMAKE_SOURCE_DIR}/conanfile.txt")
file(READ "${CMAKE_SOURCE_DIR}/conanfile.txt" outfile)
if(NOT "${outfile}" MATCHES ".*CMakeDeps.*")
message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile. "
"Please define the generator as it will be mandatory in the future")
endif()
set(generator "-g;CMakeDeps")
endif()
get_property(_multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT _multiconfig_generator)
message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}")
conan_install(${_host_profile_flags} ${_build_profile_flags} ${CONAN_INSTALL_ARGS} ${generator})
else()
message(STATUS "CMake-Conan: Installing both Debug and Release")
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release ${CONAN_INSTALL_ARGS} ${generator})
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug ${CONAN_INSTALL_ARGS} ${generator})
endif()
unset(_host_profile_flags)
unset(_build_profile_flags)
unset(_multiconfig_generator)
unset(_conan_install_success)
else()
message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
unset(_conan_install_success)
endif()
get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
# Ensure that we consider Conan-provided packages ahead of any other,
# irrespective of other settings that modify the search order or search paths
# This follows the guidelines from the find_package documentation
# (https://cmake.org/cmake/help/latest/command/find_package.html):
# find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
# find_package (<PackageName>)
# Filter out `REQUIRED` from the argument list, as the first call may fail
set(_find_args_${package_name} "${ARGN}")
list(REMOVE_ITEM _find_args_${package_name} "REQUIRED")
if(NOT "MODULE" IN_LIST _find_args_${package_name})
find_package(${package_name} ${_find_args_${package_name}} BYPASS_PROVIDER PATHS "${_conan_generators_folder}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
unset(_find_args_${package_name})
endif()
# Invoke find_package a second time - if the first call succeeded,
# this will simply reuse the result. If not, fall back to CMake default search
# behaviour, also allowing modules to be searched.
if(NOT ${package_name}_FOUND)
list(FIND CMAKE_MODULE_PATH "${_conan_generators_folder}" _index)
if(_index EQUAL -1)
list(PREPEND CMAKE_MODULE_PATH "${_conan_generators_folder}")
endif()
unset(_index)
find_package(${package_name} ${ARGN} BYPASS_PROVIDER)
list(REMOVE_ITEM CMAKE_MODULE_PATH "${_conan_generators_folder}")
endif()
endmacro()
cmake_language(
SET_DEPENDENCY_PROVIDER conan_provide_dependency
SUPPORTED_METHODS FIND_PACKAGE
)
macro(conan_provide_dependency_check)
set(_conan_provide_dependency_invoked FALSE)
get_property(_conan_provide_dependency_invoked GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED)
if(NOT _conan_provide_dependency_invoked)
message(WARNING "Conan is correctly configured as dependency provider, "
"but Conan has not been invoked. Please add at least one "
"call to `find_package()`.")
if(DEFINED CONAN_COMMAND)
# supress warning in case `CONAN_COMMAND` was specified but unused.
set(_conan_command ${CONAN_COMMAND})
unset(_conan_command)
endif()
endif()
unset(_conan_provide_dependency_invoked)
endmacro()
# Add a deferred call at the end of processing the top-level directory
# to check if the dependency provider was invoked at all.
cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check)
# Configurable variables for Conan profiles
set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile")
set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile")
set(CONAN_INSTALL_ARGS "--build=missing" CACHE STRING "Command line arguments for conan install")
find_program(_cmake_program NAMES cmake NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH)
if(NOT _cmake_program)
get_filename_component(PATH_TO_CMAKE_BIN "${CMAKE_COMMAND}" DIRECTORY)
set(PATH_TO_CMAKE_BIN "${PATH_TO_CMAKE_BIN}" CACHE INTERNAL "Path where the CMake executable is")
endif()
cmake_policy(POP)

View file

@ -1,9 +0,0 @@
[settings]
os=Macos
arch=armv8
compiler=apple-clang
compiler.version=13
compiler.libcxx=libc++
[conf]

View file

@ -1,8 +0,0 @@
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=13
compiler.libcxx=libc++
[conf]

View file

@ -1,9 +0,0 @@
[settings]
os=Linux
arch=armv8
compiler=gcc
compiler.version=11
compiler.libcxx=libstdc++11
[conf]
tools.cmake.cmaketoolchain:user_presets=False

View file

@ -1,9 +0,0 @@
[settings]
os=Linux
arch=x86_64
compiler=gcc
compiler.version=11
compiler.libcxx=libstdc++11
[conf]
tools.cmake.cmaketoolchain:user_presets=False

View file

@ -1,10 +0,0 @@
[settings]
arch=x86_64
compiler=msvc
compiler.cppstd=17
compiler.runtime=static
compiler.version=193
os=Windows
[conf]
tools.cmake.cmaketoolchain:user_presets=False

View file

@ -1,10 +0,0 @@
[settings]
arch=x86_64
compiler=msvc
compiler.cppstd=17
compiler.runtime=static
compiler.version=194
os=Windows
[conf]
tools.cmake.cmaketoolchain:user_presets=False

View file

@ -3,4 +3,4 @@
static_assert(1, "FAIL"); static_assert(1, "FAIL");
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
return 0; return 0;
} }

70
conanfile.py Normal file
View file

@ -0,0 +1,70 @@
import os
from conan import ConanFile
from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake
class BlockchainConan(ConanFile):
name = "blockchain"
version = "6.0.1"
settings = "os", "compiler", "build_type", "arch"
options = {
"static": [True, False],
"testnet": [True, False],
"ci": [True, False]
}
default_options = {
"static": False,
"testnet": False,
"ci": False,
"boost/*:without_test": True
}
tool_requires = [
"cmake/3.31.9"
]
requires = [
"zlib/1.3.1",
"boost/1.85.0",
"openssl/3.2.0",
"miniupnpc/2.2.5",
"jwt-cpp/0.7.1",
"oatpp/1.3.0.latest",
"oatpp-swagger/1.3.0.latest"
]
def generate(self):
tc = CMakeToolchain(self)
os_val = str(self.settings.os).lower()
# arch_val = str(self.settings.arch).lower()
# compiler_val = str(self.settings.compiler).lower()
# tc.presets_prefix = f"{os_val}"
tc.user_presets_path = "ConanPresets.json"
tc.variables["STATIC"] = self.options.static
tc.variables["TESTNET"] = self.options.testnet
# tc.preprocessor_definitions["TESTNET"] = None
# tc.variables["BUILD_VERSION"] = self.options.build_version
tc.generate()
deps = CMakeDeps(self)
deps.generate()
def layout(self):
if self.settings.compiler == "msvc":
# For multi-config, all configurations go into the same "build" folder.
self.folders.build = "build/release"
self.folders.generators = "build/release/generators"
else:
# For single-config, we create a subfolder for each build type.
build_type_str = str(self.settings.build_type).lower()
self.folders.build = os.path.join("build", build_type_str)
self.folders.generators = os.path.join(self.folders.build, "generators")
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

View file

@ -1,10 +0,0 @@
[requires]
zlib/1.3.1
boost/1.85.0
openssl/3.2.0
miniupnpc/2.2.5
jwt-cpp/0.7.1
[generators]
CMakeDeps
CMakeToolchain

View file

@ -1,6 +1,7 @@
add_subdirectory(db) add_subdirectory(db)
add_subdirectory(ethereum) add_subdirectory(ethereum)
add_subdirectory(randomx)
if(USE_BITCOIN_SECP256K1_FOR_ECDSA) if(USE_BITCOIN_SECP256K1_FOR_ECDSA)
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF) option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF)

View file

@ -28,6 +28,7 @@
#include <locale> #include <locale>
#include <cstdlib> #include <cstdlib>
#include <iomanip>
#include <map> #include <map>
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_io.hpp>

1
contrib/randomx Submodule

@ -0,0 +1 @@
Subproject commit cf15f4023ec8ddaa842f49111ba80ead1b5937f1

27
docker-compose.yml Normal file
View file

@ -0,0 +1,27 @@
version: '3.8'
services:
lethean-chain:
image: lthn/chain:testnet
build:
tags:
- lthn/chain:testnet
dockerfile: utils/docker/lthn-chain/Dockerfile
context: .
target: chain-service
args:
- BUILD_THREADS=1
- BUILD_TESTNET=1
- BUILD_STATIC=0
- BUILD_BRANCH=dev
- BUILD_LOCAL=1
- BUILD_REPO=https://github.com/letheanVPN/blockchain.git
- BUILD_FOLDER=build/release
- BUILD_TYPE=Release
ports:
- "36941:36941"
- "36942:36942"
volumes:
- lethean_data:/data
volumes:
lethean_data:

54
docker/.env Normal file
View file

@ -0,0 +1,54 @@
# Lethean Testnet Configuration
# Copy to .env and customise before running:
# cp .env.example .env
# docker compose -f docker-compose.pull.yml up -d
# Public hostname (used by explorer and trade frontend)
PUBLIC_HOST=localhost
# Wallet password (empty = no password, change for production)
WALLET_PASSWORD=
# Trade API JWT secret (CHANGE THIS for production)
JWT_SECRET=change-me-before-production
# Explorer database
EXPLORER_DB_USER=explorer
EXPLORER_DB_PASS=explorer
EXPLORER_DB_NAME=lethean_explorer
# Trade database
TRADE_DB_USER=trade
TRADE_DB_PASS=trade
TRADE_DB_NAME=lethean_trade
# Daemon log level (0=minimal, 1=normal, 2=detailed, 3=trace)
DAEMON_LOG_LEVEL=1
# Port overrides (defaults shown)
# DAEMON_RPC_PORT=46941
# DAEMON_P2P_PORT=46942
# WALLET_RPC_PORT=46944
# EXPLORER_PORT=3335
# TRADE_API_PORT=3336
# TRADE_FRONTEND_PORT=3338
# POOL_STRATUM_PORT=5555
# POOL_API_PORT=2117
# LNS_HTTP_PORT=5553
# LNS_DNS_PORT=5354
# === Exit Node Settings (docker-compose.exit.yml) ===
# Your public IP address (required for VPN exit node)
# EXIT_PUBLIC_IP=auto
# Exit node name (registered as on-chain alias)
# EXIT_NAME=my-exit-node
# Maximum VPN peers (WireGuard clients)
# EXIT_MAX_PEERS=25
# Timezone
# TZ=Europe/London
EXIT_PUBLIC_IP=203.0.113.50
EXIT_NAME=my-exit

52
docker/.env.example Normal file
View file

@ -0,0 +1,52 @@
# Lethean Testnet Configuration
# Copy to .env and customise before running:
# cp .env.example .env
# docker compose -f docker-compose.pull.yml up -d
# Public hostname (used by explorer and trade frontend)
PUBLIC_HOST=localhost
# Wallet password (empty = no password, change for production)
WALLET_PASSWORD=
# Trade API JWT secret (CHANGE THIS for production)
JWT_SECRET=change-me-before-production
# Explorer database
EXPLORER_DB_USER=explorer
EXPLORER_DB_PASS=explorer
EXPLORER_DB_NAME=lethean_explorer
# Trade database
TRADE_DB_USER=trade
TRADE_DB_PASS=trade
TRADE_DB_NAME=lethean_trade
# Daemon log level (0=minimal, 1=normal, 2=detailed, 3=trace)
DAEMON_LOG_LEVEL=1
# Port overrides (defaults shown)
# DAEMON_RPC_PORT=46941
# DAEMON_P2P_PORT=46942
# WALLET_RPC_PORT=46944
# EXPLORER_PORT=3335
# TRADE_API_PORT=3336
# TRADE_FRONTEND_PORT=3338
# POOL_STRATUM_PORT=5555
# POOL_API_PORT=2117
# LNS_HTTP_PORT=5553
# LNS_DNS_PORT=5354
# === Exit Node Settings (docker-compose.exit.yml) ===
# Your public IP address (required for VPN exit node)
# EXIT_PUBLIC_IP=auto
# Exit node name (registered as on-chain alias)
# EXIT_NAME=my-exit-node
# Maximum VPN peers (WireGuard clients)
# EXIT_MAX_PEERS=25
# Timezone
# TZ=Europe/London

View file

@ -0,0 +1,38 @@
# Cross-platform build for Lethean blockchain binaries
# Produces Linux x86_64 and ARM64 binaries
# macOS and Windows need native build environments or cross-compilation toolchains
#
# Usage:
# docker build -f Dockerfile.cross-build --target linux-x64 -o ./out .
# docker build -f Dockerfile.cross-build --target linux-arm64 -o ./out .
# === Base builder ===
FROM ubuntu:24.04 AS base-builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
build-essential cmake git python3 python3-pip \
libboost-all-dev libssl-dev pkg-config curl \
&& pip3 install conan --break-system-packages \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
COPY . /build/
# === Linux x86_64 ===
FROM base-builder AS linux-x64-build
ARG TESTNET=1
RUN make build CPU_CORES=$(nproc) TESTNET=${TESTNET} STATIC=1 || \
(cd build/release && cmake --build . --parallel $(nproc))
FROM scratch AS linux-x64
COPY --from=linux-x64-build /build/build/release/src/lethean-* /
# === Linux ARM64 (cross-compile) ===
FROM base-builder AS linux-arm64-build
RUN apt-get update && apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
ARG TESTNET=1
# ARM64 cross-compilation requires CMAKE_TOOLCHAIN_FILE
# This is a placeholder — actual cross-compile needs Conan profile for aarch64
RUN echo "ARM64 cross-compilation requires additional setup. Use native ARM64 builder or QEMU."
FROM scratch AS linux-arm64
# Placeholder — use buildx with --platform=linux/arm64 for native ARM builds

View file

@ -0,0 +1,183 @@
# Lethean Staking Node — single container, no compose needed
# Runs daemon + wallet with PoS staking in one container.
#
# Build:
# docker build -f Dockerfile.staking-node -t lthn/staking-node .
#
# Run:
# docker run -d --name lthn-staker \
# -p 46941:36941 -p 46942:36942 -p 46944:36944 \
# -v lthn-chain:/data -v lthn-wallet:/wallet \
# lthn/staking-node
#
# Run with password:
# docker run -d --name lthn-staker \
# -e WALLET_PASSWORD=my-pass \
# -p 46941:36941 -p 46942:36942 -p 46944:36944 \
# -v lthn-chain:/data -v lthn-wallet:/wallet \
# lthn/staking-node
#
# Check status:
# docker exec lthn-staker /status.sh
#
# Get wallet address:
# docker exec lthn-staker /wallet-address.sh
#
# Ports:
# 36941 — Daemon RPC (chain queries)
# 36942 — P2P (open on router for full node)
# 36944 — Wallet RPC (balance, transfers)
FROM lthn/chain:testnet
RUN apt-get update && apt-get install -y --no-install-recommends \
curl supervisor bc \
&& rm -rf /var/lib/apt/lists/*
# Supervisor manages both daemon and wallet in one container
COPY <<'SUPERVISOR' /etc/supervisor/conf.d/lethean.conf
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
loglevel=info
[program:daemon]
command=lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level %(ENV_DAEMON_LOG_LEVEL)s
--disable-upnp
--rpc-ignore-offline
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:wallet]
command=/start-wallet.sh
autorestart=true
startsecs=30
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
SUPERVISOR
# Wallet startup script — waits for daemon, creates wallet if needed
COPY <<'WALLETSH' /start-wallet.sh
#!/bin/bash
set -e
WALLET_FILE="/wallet/staker.wallet"
WALLET_PASS="${WALLET_PASSWORD:-}"
DAEMON="127.0.0.1:36941"
# Wait for daemon RPC
echo "[wallet] Waiting for daemon..."
until curl -sf "http://$DAEMON/json_rpc" \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "[wallet] Daemon ready"
# Create wallet if it doesn't exist
if [ ! -f "$WALLET_FILE" ]; then
echo "[wallet] Creating new wallet..."
echo "$WALLET_PASS" | lethean-wallet-cli \
--generate-new-wallet "$WALLET_FILE" \
--password "$WALLET_PASS" \
--daemon-address "$DAEMON" \
--command exit
echo "[wallet] Wallet created"
fi
# Start wallet with PoS staking
exec lethean-wallet-cli \
--wallet-file "$WALLET_FILE" \
--password "$WALLET_PASS" \
--daemon-address "$DAEMON" \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
WALLETSH
# Status helper — shows chain + wallet in one command
COPY <<'STATUSSH' /status.sh
#!/bin/bash
echo "=== Lethean Staking Node ==="
echo ""
# Chain
INFO=$(curl -sf http://127.0.0.1:36941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' 2>/dev/null)
if [ -n "$INFO" ]; then
echo "$INFO" | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
hf=d.get('is_hardfok_active',[])
active=sum(1 for h in hf if h)
print(f'Chain:')
print(f' Height: {d[\"height\"]:,}')
print(f' Hardforks: HF0-{active-1}')
print(f' PoW diff: {d.get(\"pow_difficulty\",0):,}')
print(f' Aliases: {d.get(\"alias_count\",0)}')
print(f' Peers in: {d.get(\"incoming_connections_count\",0)}')
print(f' Peers out: {d.get(\"outgoing_connections_count\",0)}')
print(f' Status: {d[\"status\"]}')
" 2>/dev/null
else
echo "Chain: starting..."
fi
echo ""
# Wallet
BAL=$(curl -sf http://127.0.0.1:36944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \
-H 'Content-Type: application/json' 2>/dev/null)
if [ -n "$BAL" ]; then
echo "$BAL" | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(f'Wallet:')
print(f' Balance: {d[\"balance\"]/1e12:.4f} LTHN')
print(f' Unlocked: {d[\"unlocked_balance\"]/1e12:.4f} LTHN')
print(f' Staking: yes (PoS mining active)')
" 2>/dev/null
else
echo "Wallet: syncing..."
fi
STATUSSH
# Wallet address helper
COPY <<'ADDRSH' /wallet-address.sh
#!/bin/bash
curl -sf http://127.0.0.1:36944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(d['address'])
" 2>/dev/null || echo "Wallet not ready yet — daemon still syncing"
ADDRSH
RUN chmod +x /start-wallet.sh /status.sh /wallet-address.sh
ENV DAEMON_LOG_LEVEL=1
ENV WALLET_PASSWORD=
EXPOSE 36941 36942 36944
VOLUME ["/data", "/wallet"]
ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/conf.d/lethean.conf"]

152
docker/README.md Normal file
View file

@ -0,0 +1,152 @@
# Lethean Testnet — Docker Deployment
Run the full Lethean ecosystem in Docker. No compilation needed.
## Deployment Options
| Compose File | For | Services |
|---|---|---|
| `docker-compose.node.yml` | Home node operator | Daemon + wallet (PoS staking) |
| `docker-compose.exit.yml` | VPN exit node operator | Daemon + wallet + WireGuard |
| `docker-compose.pull.yml` | Full ecosystem | All 8 services + databases |
## Helper Scripts
```bash
bash demos/helpers/chain-info.sh # Chain height, difficulty, status
bash demos/helpers/chain-aliases.sh # List on-chain aliases
bash demos/helpers/wallet-address.sh # Show your wallet address
bash demos/helpers/wallet-balance.sh # Check LTHN balance
bash health.sh # Full ecosystem health check
```
## Quick Start
```bash
# 1. Configure
cp .env.example .env
# Edit .env — at minimum change JWT_SECRET and WALLET_PASSWORD
# 2. Start
docker compose -f docker-compose.pull.yml up -d
# 3. Check
docker compose -f docker-compose.pull.yml ps
```
The daemon takes ~30 seconds to initialise the chain database on first run.
Other services wait for the daemon health check before starting.
## Services
| Service | URL | Description |
|---------|-----|-------------|
| Block Explorer | http://localhost:3335 | Browse blocks, transactions, aliases |
| Trade DEX | http://localhost:3338 | Decentralised exchange frontend |
| Trade API | http://localhost:3336 | REST API for trade operations |
| Mining Pool | http://localhost:2117 | Pool stats API |
| Pool Stratum | localhost:5555 | Connect miners here |
| LNS | http://localhost:5553 | Lethean Name Service HTTP API |
| LNS DNS | localhost:5354 | DNS resolver for .lthn names |
| Daemon RPC | http://localhost:46941 | Chain node JSON-RPC |
| Wallet RPC | http://localhost:46944 | Wallet JSON-RPC |
| Docs | http://localhost:8099 | Documentation site |
## Mining
Connect a ProgPoWZ miner to the pool stratum:
```
stratum+tcp://YOUR_IP:5555
```
Compatible miners:
- **progminer** (recommended) — `progminer -P stratum+tcp://YOUR_WALLET_ADDRESS@localhost:5555`
- **T-Rex** — ProgPoWZ algorithm
- **TeamRedMiner** — ProgPoWZ algorithm
## Wallet
The wallet auto-creates on first start. To check your balance:
```bash
curl -s http://localhost:46944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \
-H 'Content-Type: application/json'
```
The wallet runs with PoS mining enabled (`--do-pos-mining`), so it will stake
any balance automatically.
## Chain Status
```bash
curl -s http://localhost:46941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' | python3 -m json.tool
```
## Volumes
| Volume | Contains | Backup? |
|--------|----------|---------|
| `chain-data` | Blockchain database (LMDB) | Optional — can resync |
| `wallet-data` | Wallet file + keys | **Critical — back up regularly** |
| `explorer-db` | Explorer PostgreSQL | Can recreate from chain |
| `trade-db` | Trade PostgreSQL | Important for trade history |
### Backup wallet
```bash
docker compose -f docker-compose.pull.yml stop wallet
docker cp lthn-wallet:/wallet ./wallet-backup-$(date +%Y%m%d)
docker compose -f docker-compose.pull.yml start wallet
```
## Ports
All ports can be changed via `.env`. See `.env.example` for the full list.
If you're running behind a firewall and want external access:
- **P2P:** Open port 46942 (TCP) for other nodes to connect
- **Stratum:** Open port 5555 (TCP) for external miners
- **Explorer:** Open port 3335 (TCP) for public block explorer
## Troubleshooting
**Daemon crashes on start:**
Check logs with `docker logs lthn-daemon`. Common causes:
- Port already in use — change ports in `.env`
- Corrupt chain data — remove volume: `docker volume rm docker_chain-data`
**Wallet shows 0 balance:**
The wallet needs to sync with the daemon first. Check sync status in daemon logs.
New wallets start empty — mine or receive LTHN to fund them.
**Pool shows "Daemon died":**
The pool needs both the daemon and wallet running. Check both are healthy:
```bash
docker compose -f docker-compose.pull.yml ps daemon wallet
```
**Explorer shows "offline":**
The explorer connects to the daemon internally. If the daemon is still syncing,
the explorer will show offline until sync completes.
## Stopping
```bash
docker compose -f docker-compose.pull.yml down # stop containers
docker compose -f docker-compose.pull.yml down -v # stop + delete data
```
## Building from Source
If you want to build the images yourself instead of pulling pre-built ones:
```bash
docker compose -f docker-compose.ecosystem.yml build
docker compose -f docker-compose.ecosystem.yml up -d
```
This requires the full source tree — see the main repository README.

77
docker/build-all-platforms.sh Executable file
View file

@ -0,0 +1,77 @@
#!/bin/bash
# Build Lethean binaries for all platforms
# Requires: Docker with buildx for multi-arch
#
# Usage:
# ./build-all-platforms.sh testnet # testnet binaries
# ./build-all-platforms.sh mainnet # mainnet binaries
#
# Outputs to: ../build/packages/
set -e
TARGET=${1:-testnet}
TESTNET=$( [ "$TARGET" = "testnet" ] && echo 1 || echo 0 )
VERSION=$(grep 'BUILD_VERSION:=' ../Makefile | cut -d= -f2)
OUTDIR="../build/packages"
echo "Building Lethean $TARGET v$VERSION for all platforms"
mkdir -p "$OUTDIR"
# === Linux x86_64 (Docker) ===
echo ""
echo "=== Linux x86_64 ==="
docker build -f Dockerfile.cross-build \
--build-arg TESTNET=$TESTNET \
--target linux-x64 \
-o "$OUTDIR/linux-x64" \
.. 2>&1 | tail -5
if ls "$OUTDIR/linux-x64/lethean-"* > /dev/null 2>&1; then
PKG="lethean-${TARGET}-linux-x86_64-v${VERSION}"
mkdir -p "$OUTDIR/$PKG"
cp "$OUTDIR/linux-x64/lethean-"* "$OUTDIR/$PKG/"
cd "$OUTDIR" && tar czf "${PKG}.tar.gz" "$PKG/" && cd -
echo " Package: $OUTDIR/${PKG}.tar.gz"
else
echo " Build failed — check Docker output"
fi
# === Linux ARM64 (needs Docker buildx with QEMU) ===
echo ""
echo "=== Linux ARM64 ==="
if docker buildx ls 2>/dev/null | grep -q "linux/arm64"; then
echo " ARM64 builder available — building..."
docker buildx build -f ../utils/docker/lthn-chain/Dockerfile \
--platform linux/arm64 \
--build-arg BUILD_TESTNET=$TESTNET \
--build-arg BUILD_THREADS=4 \
--target build-artifacts \
-o "$OUTDIR/linux-arm64" \
.. 2>&1 | tail -5
else
echo " SKIP: Docker buildx ARM64 emulation not configured"
echo " To enable: docker run --privileged --rm tonistiigi/binfmt --install arm64"
fi
# === macOS (needs native build or osxcross) ===
echo ""
echo "=== macOS ==="
echo " SKIP: macOS builds require native macOS environment or osxcross toolchain"
echo " Build on Cladius (M3 Ultra): cd blockchain && make $TARGET"
echo " Or use GitHub Actions with macos-latest runner"
# === Windows (needs MSVC or mingw-w64) ===
echo ""
echo "=== Windows ==="
echo " SKIP: Windows builds require MSVC or mingw-w64 cross-compiler"
echo " Recommended: GitHub Actions with windows-latest runner"
echo " Or: Docker with dockcross/windows-shared-x64 image"
# === Summary ===
echo ""
echo "=== Build Summary ==="
ls -lh "$OUTDIR"/*.tar.gz 2>/dev/null || echo "No packages built yet"
echo ""
echo "For macOS/Windows, use CI/CD:"
echo " .forgejo/workflows/build-release.yml (push a tag to trigger)"

BIN
docker/demos/01-install.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

View file

@ -0,0 +1,54 @@
# 01 — Install Lethean from scratch
# Shows a home user going from zero to running node
Output demos/01-install.gif
Set FontSize 13
Set Width 1000
Set Height 600
Set Theme "Dracula"
Set TypingSpeed 35ms
Set Padding 12
Set Shell bash
Type "# Install Lethean — from zero to running node"
Enter
Sleep 1s
Type "mkdir lethean && cd lethean"
Enter
Sleep 500ms
Type "# Download the compose files"
Enter
Type "curl -sO https://forge.lthn.ai/lthn/blockchain/raw/branch/dev/docker/docker-compose.node.yml"
Enter
Sleep 500ms
Type "curl -sO https://forge.lthn.ai/lthn/blockchain/raw/branch/dev/docker/.env.example"
Enter
Sleep 500ms
Type "cp .env.example .env"
Enter
Sleep 300ms
Type "# Set a wallet password"
Enter
Type "sed -i 's/WALLET_PASSWORD=/WALLET_PASSWORD=my-secure-pass/' .env"
Enter
Sleep 500ms
Type ""
Enter
Type "# Start the node"
Enter
Type "docker compose -f docker-compose.node.yml up -d"
Enter
Sleep 3s
Type ""
Enter
Type "# That's it. Your node is syncing and staking."
Enter
Sleep 2s

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 KiB

View file

@ -0,0 +1,39 @@
# 02 — Chain Status (live data)
Output demos/02-chain-status.gif
Set FontSize 13
Set Width 1000
Set Height 600
Set Theme "Dracula"
Set TypingSpeed 35ms
Set Padding 12
Set Shell bash
Type "# Lethean Chain — Live Status"
Enter
Sleep 500ms
Type "bash demos/helpers/chain-info.sh"
Enter
Sleep 3s
Type ""
Enter
Type "bash demos/helpers/last-block.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# On-chain service discovery via aliases"
Enter
Type "bash demos/helpers/chain-aliases.sh"
Enter
Sleep 4s
Type ""
Enter
Type "# Blocks arrive every ~2 minutes — PoW and PoS alternating"
Enter
Sleep 2s

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View file

@ -0,0 +1,87 @@
# 03 — Ecosystem Tour (the teaser material)
# Every service, live data, no fluff
Output demos/03-ecosystem-tour.gif
Set FontSize 13
Set Width 1000
Set Height 700
Set Theme "Dracula"
Set TypingSpeed 30ms
Set Padding 12
Set Shell bash
Type "# Lethean Ecosystem — Full Tour"
Enter
Sleep 500ms
Type "bash health.sh"
Enter
Sleep 4s
Type ""
Enter
Type "# === Chain ==="
Enter
Type "bash demos/helpers/chain-info.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# === Latest Block ==="
Enter
Type "bash demos/helpers/last-block.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# === Wallet ==="
Enter
Type "bash demos/helpers/wallet-address.sh"
Enter
Sleep 2s
Type "bash demos/helpers/wallet-balance.sh"
Enter
Sleep 2s
Type ""
Enter
Type "# === Explorer ==="
Enter
Type "bash demos/helpers/explorer-stats.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# === Mining Pool ==="
Enter
Type "bash demos/helpers/pool-stats.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# === Name Service ==="
Enter
Type "bash demos/helpers/lns-status.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# === Aliases — services advertise on-chain ==="
Enter
Type "bash demos/helpers/chain-aliases.sh"
Enter
Sleep 4s
Type ""
Enter
Type "# Lethean — privacy by default, earn by participating"
Enter
Type "# https://lethean.io"
Enter
Sleep 3s

BIN
docker/demos/04-mining.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

View file

@ -0,0 +1,50 @@
# 04 — Mining
# Shows pool stats and how to connect a miner
Output demos/04-mining.gif
Set FontSize 13
Set Width 1000
Set Height 550
Set Theme "Dracula"
Set TypingSpeed 35ms
Set Padding 12
Set Shell bash
Type "# Lethean Mining — ProgPoWZ GPU Mining"
Enter
Sleep 500ms
Type "bash demos/helpers/pool-stats.sh"
Enter
Sleep 3s
Type ""
Enter
Type "# Get your wallet address for mining"
Enter
Type "bash demos/helpers/wallet-address.sh"
Enter
Sleep 2s
Type ""
Enter
Type "# Connect a GPU miner:"
Enter
Type "echo 'progminer -P stratum+tcp://YOUR_WALLET@localhost:5555'"
Enter
Sleep 1s
Type "echo 't-rex -a progpowz -o stratum+tcp://localhost:5555 -u YOUR_WALLET'"
Enter
Sleep 1s
Type "echo 'teamredminer -a progpow -o stratum+tcp://localhost:5555 -u YOUR_WALLET'"
Enter
Sleep 2s
Type ""
Enter
Type "# Pool dashboard: http://localhost:2117"
Enter
Type "# Block reward: 1 LTHN every ~2 minutes"
Enter
Sleep 2s

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View file

@ -0,0 +1,68 @@
# 05 — Exit Node Setup
# Shows how to run a VPN exit node and earn LTHN
Output demos/05-exit-node.gif
Set FontSize 13
Set Width 1000
Set Height 600
Set Theme "Dracula"
Set TypingSpeed 35ms
Set Padding 12
Set Shell bash
Type "# Lethean VPN Exit Node — Earn LTHN"
Enter
Sleep 500ms
Type "# Configure your exit node"
Enter
Type "cp .env.example .env"
Enter
Sleep 300ms
Type "echo 'WALLET_PASSWORD=my-secure-pass' >> .env"
Enter
Type "echo 'EXIT_PUBLIC_IP=203.0.113.50' >> .env"
Enter
Type "echo 'EXIT_NAME=my-exit' >> .env"
Enter
Sleep 500ms
Type ""
Enter
Type "# Start the exit node stack"
Enter
Type "docker compose -f docker-compose.exit.yml up -d"
Enter
Sleep 3s
Type ""
Enter
Type "# Your exit node runs:"
Enter
Type "echo ' Chain daemon — syncs blockchain'"
Enter
Type "echo ' Wallet — PoS staking + receives payments'"
Enter
Type "echo ' WireGuard VPN — encrypted tunnel for gateway traffic'"
Enter
Type "echo ' Controller — manages peering and on-chain registration'"
Enter
Sleep 2s
Type ""
Enter
Type "# Gateways discover you via on-chain alias:"
Enter
Type "echo ' @my-exit v=lthn1;type=exit;cap=vpn,proxy;ip=203.0.113.50'"
Enter
Sleep 2s
Type ""
Enter
Type "# Open ports 46942/tcp + 51820/udp on your router"
Enter
Type "# Then sit back and earn LTHN"
Enter
Sleep 3s

View file

@ -0,0 +1,13 @@
#!/bin/bash
curl -s localhost:46941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"get_all_alias_details"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
aliases=json.load(sys.stdin)['result']['aliases']
print(f'{len(aliases)} aliases registered on-chain:')
print()
for a in aliases:
name = a['alias']
comment = a.get('comment','')
print(f' @{name:12s} {comment[:50]}')
"

View file

@ -0,0 +1,17 @@
#!/bin/bash
curl -s localhost:46941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
hf = d.get('is_hardfok_active',[])
active = sum(1 for h in hf if h)
print(f'Height: {d[\"height\"]:,}')
print(f'Hardforks: HF0-{active-1} active')
print(f'PoW diff: {d.get(\"pow_difficulty\",0):,}')
print(f'Aliases: {d.get(\"alias_count\",0)}')
print(f'TX count: {d.get(\"tx_count\",0):,}')
print(f'Peers in: {d.get(\"incoming_connections_count\",0)}')
print(f'Peers out: {d.get(\"outgoing_connections_count\",0)}')
print(f'Status: {d[\"status\"]}')
"

View file

@ -0,0 +1,15 @@
#!/bin/bash
curl -s localhost:3335/api/get_info | python3 -c "
import sys,json
try:
d=json.load(sys.stdin)
print('Block Explorer')
print(f' Height: {d.get(\"height\",0):,}')
print(f' PoW diff: {d.get(\"pow_difficulty\",0):,}')
print(f' Aliases: {d.get(\"alias_count\",0)}')
print(f' TX count: {d.get(\"tx_count\",0):,}')
print(f' Hashrate: {d.get(\"current_network_hashrate_350\",0):,} H/s')
print(f' URL: http://localhost:3335')
except:
print('Explorer: connecting...')
"

View file

@ -0,0 +1,13 @@
#!/bin/bash
curl -s localhost:46941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getlastblockheader"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
b=json.load(sys.stdin)['result']['block_header']
btype = 'PoW' if b.get('major_version',0)==3 else 'PoS'
print(f'Latest Block #{b[\"height\"]:,}')
print(f' Type: {btype}')
print(f' Reward: {b[\"reward\"]/1e12:.4f} LTHN')
print(f' Difficulty: {b[\"difficulty\"]:,}')
print(f' Hash: {b[\"hash\"][:20]}...')
"

View file

@ -0,0 +1,15 @@
#!/bin/bash
echo "Lethean Name Service (LNS)"
curl -s localhost:5553/health | python3 -c "
import sys,json
d=json.load(sys.stdin)
print(f' Mode: {d.get(\"mode\",\"?\")}')
print(f' Names: {d.get(\"names\",0)} cached')
print(f' Status: {d.get(\"status\",\"?\")}')
"
echo ""
echo "Resolving .lthn names:"
for name in charon gateway explorer trading; do
result=$(curl -s "localhost:5553/resolve?name=$name.lthn" | python3 -c "import sys,json; d=json.load(sys.stdin); print('found' if d.get('found') else 'not cached')" 2>/dev/null)
printf " %-16s %s\n" "$name.lthn" "$result"
done

View file

@ -0,0 +1,17 @@
#!/bin/bash
curl -s localhost:2117/stats | python3 -c "
import sys,json
d=json.load(sys.stdin)
pool = d.get('pool',{})
net = d.get('network',{})
cfg = d.get('config',{})
print(f'Lethean Mining Pool')
print(f' Coin: {cfg.get(\"coin\",\"?\")}')
print(f' Algorithm: ProgPoWZ')
print(f' Pool hash: {pool.get(\"hashrate\",0)} H/s')
print(f' Miners: {pool.get(\"miners\",0)}')
print(f' Blocks found: {pool.get(\"totalBlocks\",0)}')
print(f' Net height: {net.get(\"height\",\"?\")}')
print(f' Net diff: {net.get(\"difficulty\",\"?\")}')
print(f' Stratum: stratum+tcp://localhost:5555')
"

View file

@ -0,0 +1,8 @@
#!/bin/bash
curl -s localhost:46944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print('Address:', d['address'])
"

View file

@ -0,0 +1,9 @@
#!/bin/bash
curl -s localhost:46944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(f'Balance: {d[\"balance\"]/1e12:.4f} LTHN')
print(f'Unlocked: {d[\"unlocked_balance\"]/1e12:.4f} LTHN')
"

78
docker/deploy.sh Executable file
View file

@ -0,0 +1,78 @@
#!/bin/bash
# Lethean Testnet — Production Deploy Script
# Transfers images and config to a remote server and starts the stack.
#
# Usage:
# bash deploy.sh user@server
# bash deploy.sh user@server /opt/lethean/docker
#
# Prerequisites on the remote server:
# - Docker + Docker Compose v2
# - SSH access
set -e
REMOTE="${1:?Usage: deploy.sh user@server [install_dir]}"
INSTALL_DIR="${2:-/opt/lethean/docker}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
IMAGES="$SCRIPT_DIR/dist/lethean-testnet-images.tar.gz"
if [ ! -f "$IMAGES" ]; then
echo "Building image bundle..."
mkdir -p "$SCRIPT_DIR/dist"
docker save \
lthn/chain:testnet \
lthn/explorer:testnet \
lthn/trade-api:testnet \
lthn/trade-frontend:testnet \
lthn/pool:testnet \
lthn/lns:testnet \
lthn/docs:testnet \
| gzip > "$IMAGES"
fi
echo "Image bundle: $(du -h "$IMAGES" | cut -f1)"
echo "Deploying to $REMOTE:$INSTALL_DIR"
echo ""
# Create remote directory
ssh "$REMOTE" "mkdir -p $INSTALL_DIR"
# Transfer files
echo "Transferring config files..."
scp "$SCRIPT_DIR/docker-compose.pull.yml" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/.env.example" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/pool-config.json" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/health.sh" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/lethean-testnet.service" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/docker-compose.node.yml" "$REMOTE:$INSTALL_DIR/"
scp "$SCRIPT_DIR/docker-compose.exit.yml" "$REMOTE:$INSTALL_DIR/"
scp -r "$SCRIPT_DIR/demos/helpers" "$REMOTE:$INSTALL_DIR/demos/"
# Create .env if it doesn't exist — generate unique JWT secret
ssh "$REMOTE" "
if [ ! -f $INSTALL_DIR/.env ]; then
cp $INSTALL_DIR/.env.example $INSTALL_DIR/.env
JWT=\$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | xxd -p | tr -d '\n' | head -c 64)
sed -i \"s/change-me-before-production/\$JWT/\" $INSTALL_DIR/.env
echo 'Generated unique JWT secret'
else
echo '.env already exists — skipping'
fi
"
echo "Transferring images (~$(du -h "$IMAGES" | cut -f1))... this may take a while"
scp "$IMAGES" "$REMOTE:/tmp/lethean-testnet-images.tar.gz"
echo "Loading images on remote..."
ssh "$REMOTE" "docker load < /tmp/lethean-testnet-images.tar.gz && rm /tmp/lethean-testnet-images.tar.gz"
echo "Starting stack..."
ssh "$REMOTE" "cd $INSTALL_DIR && docker compose -f docker-compose.pull.yml up -d"
echo ""
echo "Deploy complete. Run health check:"
echo " ssh $REMOTE 'cd $INSTALL_DIR && bash health.sh'"
echo ""
echo "Install systemd service (optional):"
echo " ssh $REMOTE 'sudo cp $INSTALL_DIR/lethean-testnet.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl enable lethean-testnet'"

View file

@ -0,0 +1,203 @@
# Lethean Full Ecosystem
# Chain node + wallet + explorer + trade + pool + LNS + docs
#
# Usage:
# docker compose -f docker-compose.ecosystem.yml up -d
#
# URLs after startup:
# Explorer: http://localhost:3335
# Trade: http://localhost:3337
# Trade API: http://localhost:3336
# Pool API: http://localhost:2117
# Pool Web: http://localhost:8888
# LNS HTTP: http://localhost:5553
# LNS DNS: localhost:5354
# Docs: http://localhost:8098
# Daemon RPC: http://localhost:46941
# Wallet RPC: http://localhost:46944
services:
# --- Chain ---
daemon:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-daemon
ports:
- "46941:36941"
- "46942:36942"
volumes:
- daemon-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level 1
--disable-upnp
wallet:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-wallet
ports:
- "46944:36944"
volumes:
- wallet-data:/wallet
entrypoint: >
sh -c "
if [ ! -f /wallet/main.wallet ]; then
echo '' | lethean-wallet-cli --generate-new-wallet /wallet/main.wallet --password '' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli
--wallet-file /wallet/main.wallet
--password ''
--daemon-address daemon:36941
--rpc-bind-port 36944
--rpc-bind-ip 0.0.0.0
--do-pos-mining
"
depends_on:
- daemon
# --- Explorer ---
explorer-db:
image: postgres:16-alpine
container_name: lthn-explorer-db
environment:
POSTGRES_USER: explorer
POSTGRES_PASSWORD: explorer
POSTGRES_DB: lethean_explorer
volumes:
- explorer-db:/var/lib/postgresql/data
explorer:
build:
context: ../../zano-upstream/zano-explorer-zarcanum
container_name: lthn-explorer
ports:
- "3335:3335"
environment:
API: http://daemon:36941
FRONTEND_API: http://localhost:3335
SERVER_PORT: "3335"
AUDITABLE_WALLET_API: http://daemon:36941
PGUSER: explorer
PGPASSWORD: explorer
PGDATABASE: lethean_explorer
PGHOST: explorer-db
PGPORT: "5432"
MEXC_API_URL: ""
depends_on:
- daemon
- explorer-db
# --- Trade ---
trade-db:
image: postgres:16-alpine
container_name: lthn-trade-db
environment:
POSTGRES_USER: trade
POSTGRES_PASSWORD: trade
POSTGRES_DB: lethean_trade
volumes:
- trade-db:/var/lib/postgresql/data
trade-api:
build:
context: ../../zano-upstream/zano_trade_backend
container_name: lthn-trade-api
ports:
- "3336:3336"
environment:
PORT: "3336"
PGUSER: trade
PGPASSWORD: trade
PGDATABASE: lethean_trade
PGHOST: trade-db
PGPORT: "5432"
JWT_SECRET: testnet-dev-secret
DAEMON_RPC_URL: http://daemon:36941/json_rpc
depends_on:
- daemon
- trade-db
trade-frontend:
build:
context: ../../zano-upstream/zano_trade_frontend
container_name: lthn-trade-frontend
ports:
- "3337:30289"
environment:
NEXT_PUBLIC_API_URL: http://trade-api:3336
depends_on:
- trade-api
# --- Mining Pool ---
pool-redis:
image: redis:7-alpine
container_name: lthn-pool-redis
restart: unless-stopped
pool:
build:
context: ../..
dockerfile: zano-upstream/zano-pool/Dockerfile
container_name: lthn-pool
ports:
- "5555:5555"
- "7777:7777"
- "2117:2117"
- "8888:8888"
volumes:
- ./pool-config.json:/pool/config.json:ro
depends_on:
- daemon
- wallet
- pool-redis
# --- LNS (Lethean Name Service) ---
lns:
build:
context: ../../lns
container_name: lthn-lns
ports:
- "5553:5553" # HTTP API
- "5354:5354/udp" # DNS
- "5354:5354/tcp" # DNS (TCP)
environment:
DAEMON_URL: http://daemon:36941
HSD_URL: http://host.docker.internal:14037
LNS_MODE: light
LNS_HTTP_PORT: "5553"
LNS_DNS_PORT: "5354"
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- daemon
# --- Docs ---
docs:
build:
context: ../../zano-upstream/zano-docs
container_name: lthn-docs
ports:
- "8098:80"
volumes:
daemon-data:
wallet-data:
explorer-db:
trade-db:

View file

@ -0,0 +1,186 @@
# Lethean Exit Node
# Run a VPN exit node and earn LTHN by providing bandwidth to the network.
# Peers with Lethean gateways which route encrypted VPN traffic through your node.
#
# Usage:
# cp .env.example .env
# # Set WALLET_PASSWORD, EXIT_PUBLIC_IP, and EXIT_NAME
# docker compose -f docker-compose.exit.yml up -d
#
# What it does:
# - Runs a full chain node (syncs blockchain)
# - Runs a wallet with PoS staking
# - Runs a WireGuard VPN server
# - Registers as an exit node on-chain via alias
# - Peers with gateway nodes for traffic routing
# - Earns LTHN for bandwidth provided
#
# Requirements:
# - Public IP address (or port forwarding on router)
# - Open ports: 46942 (P2P), 51820/udp (WireGuard)
# - Linux with Docker (WireGuard kernel module)
#
# Ports:
# 46942 — P2P (chain peering)
# 51820 — WireGuard VPN (UDP)
# 8124 — Exit node management API (local only)
services:
# --- Chain Node ---
daemon:
image: lthn/chain:testnet
container_name: lthn-exit-daemon
restart: unless-stopped
ports:
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
- --rpc-ignore-offline
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
networks:
exit-net:
# --- Wallet (PoS staking + payment receipt) ---
wallet:
image: lthn/chain:testnet
container_name: lthn-exit-wallet
restart: unless-stopped
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/exit.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/exit.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/exit.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
networks:
exit-net:
# --- WireGuard VPN Exit ---
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: lthn-exit-wireguard
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
PUID: 1000
PGID: 1000
TZ: ${TZ:-Europe/London}
SERVERURL: ${EXIT_PUBLIC_IP:-auto}
SERVERPORT: 51820
PEERS: ${EXIT_MAX_PEERS:-25}
PEERDNS: 1.1.1.1,1.0.0.1
INTERNAL_SUBNET: 10.13.13.0
ALLOWEDIPS: 0.0.0.0/0,::/0
LOG_CONFS: "false"
ports:
- "51820:51820/udp"
volumes:
- wireguard-config:/config
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
networks:
exit-net:
# --- Exit Node Controller ---
# Manages gateway peering, alias registration, and payment verification
controller:
image: lthn/chain:testnet
container_name: lthn-exit-controller
restart: unless-stopped
volumes:
- controller-data:/data
entrypoint:
- sh
- -c
command:
- |
echo "Lethean Exit Node Controller"
echo "Waiting for daemon and wallet..."
# Wait for daemon
until curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "Daemon ready"
# Wait for wallet
until curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "Wallet ready"
# Get wallet address
ADDR=$$(curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json' | grep -oP '"address":"[^"]+' | cut -d'"' -f4)
echo "Exit node wallet: $$ADDR"
# Get chain height
HEIGHT=$$(curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' | grep -oP '"height":[0-9]+' | cut -d: -f2)
echo "Chain height: $$HEIGHT"
# Register alias if EXIT_NAME is set and we have balance
if [ -n "${EXIT_NAME:-}" ]; then
echo "Exit node name: ${EXIT_NAME}"
echo "To register on-chain: send 1 LTHN to this wallet, then alias will auto-register"
echo "Alias comment: v=lthn1;type=exit;cap=vpn,proxy;ip=${EXIT_PUBLIC_IP:-auto}"
fi
# Status loop
while true; do
BALANCE=$$(curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json' | grep -oP '"balance":[0-9]+' | cut -d: -f2)
HEIGHT=$$(curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' | grep -oP '"height":[0-9]+' | cut -d: -f2)
WG_PEERS=$$(curl -sf http://wireguard:51820 2>/dev/null | wc -l || echo 0)
echo "$$(date +%H:%M:%S) height=$$HEIGHT balance=$$(echo "scale=4; $$BALANCE/1000000000000" | bc 2>/dev/null || echo $$BALANCE) peers=$$WG_PEERS"
sleep 60
done
depends_on:
daemon:
condition: service_healthy
networks:
exit-net:
networks:
exit-net:
driver: bridge
volumes:
chain-data:
wallet-data:
wireguard-config:
controller-data:

View file

@ -0,0 +1,7 @@
# Local override — mounts existing testnet chain data
# Usage: docker compose -f docker-compose.pull.yml -f docker-compose.local.yml up -d
services:
daemon:
volumes:
- /opt/lethean/testnet-data:/data

View file

@ -0,0 +1,87 @@
# Lethean Home Node
# A self-contained chain node for home users who want to support the network.
# Syncs the chain, runs a wallet with PoS staking, and exposes P2P for peering.
#
# Usage:
# cp .env.example .env # edit WALLET_PASSWORD at minimum
# docker compose -f docker-compose.node.yml up -d
#
# What it does:
# - Syncs and validates the Lethean blockchain
# - Peers with other nodes (P2P port 46942)
# - Runs a wallet that stakes automatically (PoS mining)
# - Optionally mines with ProgPoWZ (connect external GPU miner)
#
# Earnings:
# - PoS staking rewards (proportional to balance)
# - PoW block rewards if mining
#
# Ports:
# 46941 — Daemon RPC (local tools)
# 46942 — P2P (open this on your router for full node)
# 46944 — Wallet RPC (local tools)
services:
daemon:
image: lthn/chain:testnet
container_name: lthn-node
restart: unless-stopped
ports:
- "${DAEMON_RPC_PORT:-46941}:36941"
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
- --rpc-ignore-offline
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
wallet:
image: lthn/chain:testnet
container_name: lthn-wallet
restart: unless-stopped
ports:
- "${WALLET_RPC_PORT:-46944}:36944"
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/node.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/node.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/node.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
volumes:
chain-data:
wallet-data:

View file

@ -0,0 +1,114 @@
# Lethean Chain Nodes Only — minimal network simulation
# 3 nodes + miner, no explorer/trade (for testing consensus, HF activation, reorgs)
#
# Usage:
# docker compose -f docker-compose.nodes.yml up -d
# # Start mining on node1:
# docker exec lthn-node1 curl -X POST http://127.0.0.1:36941/start_mining \
# -H 'Content-Type: application/json' \
# -d '{"miner_address":"YOUR_iTHN_ADDRESS","threads_count":2}'
# # Check sync status:
# for n in 1 2 3; do
# echo -n "node$n: "; docker exec lthn-node$n curl -s http://127.0.0.1:36941/json_rpc \
# -H 'Content-Type: application/json' \
# -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['height'])"
# done
services:
node1:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node1
ports:
- "46941:36941"
- "46942:36942"
volumes:
- node1-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level 1
--disable-upnp
networks:
lthn-net:
ipv4_address: 172.29.0.10
node2:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node2
ports:
- "46951:36941"
volumes:
- node2-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--add-exclusive-node 172.29.0.10:36942
--allow-local-ip
--log-level 1
--disable-upnp
depends_on:
- node1
networks:
lthn-net:
ipv4_address: 172.29.0.11
node3:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node3
ports:
- "46961:36941"
volumes:
- node3-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--add-exclusive-node 172.29.0.10:36942
--allow-local-ip
--log-level 1
--disable-upnp
depends_on:
- node1
networks:
lthn-net:
ipv4_address: 172.29.0.12
networks:
lthn-net:
driver: bridge
ipam:
config:
- subnet: 172.29.0.0/16
volumes:
node1-data:
node2-data:
node3-data:

View file

@ -0,0 +1,235 @@
# Lethean Testnet Ecosystem
# Full node + wallet + explorer + trade + pool + LNS
#
# Quick start:
# cp .env.example .env # edit passwords/hostname
# docker compose -f docker-compose.pull.yml up -d
# docker compose -f docker-compose.pull.yml logs -f daemon
#
# Services:
# Explorer: http://${PUBLIC_HOST:-localhost}:3335
# Trade: http://${PUBLIC_HOST:-localhost}:3338
# Trade API: http://${PUBLIC_HOST:-localhost}:3336
# Pool API: http://${PUBLIC_HOST:-localhost}:2117
# LNS HTTP: http://${PUBLIC_HOST:-localhost}:5553
# Docs: http://${PUBLIC_HOST:-localhost}:8099
# Daemon RPC: http://${PUBLIC_HOST:-localhost}:46941
# Wallet RPC: http://${PUBLIC_HOST:-localhost}:46944
services:
# --- Chain ---
daemon:
image: lthn/chain:testnet
container_name: lthn-daemon
restart: unless-stopped
ports:
- "${DAEMON_RPC_PORT:-46941}:36941"
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
- --rpc-ignore-offline
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
wallet:
image: lthn/chain:testnet
container_name: lthn-wallet
restart: unless-stopped
ports:
- "${WALLET_RPC_PORT:-46944}:36944"
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/main.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/main.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/main.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
# --- Explorer ---
explorer-db:
image: postgres:16-alpine
container_name: lthn-explorer-db
restart: unless-stopped
environment:
POSTGRES_USER: ${EXPLORER_DB_USER:-explorer}
POSTGRES_PASSWORD: ${EXPLORER_DB_PASS:-explorer}
POSTGRES_DB: ${EXPLORER_DB_NAME:-lethean_explorer}
volumes:
- explorer-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${EXPLORER_DB_USER:-explorer}"]
interval: 10s
timeout: 5s
retries: 5
explorer:
image: lthn/explorer:testnet
container_name: lthn-explorer
restart: unless-stopped
ports:
- "${EXPLORER_PORT:-3335}:3335"
environment:
API: http://daemon:36941
FRONTEND_API: http://${PUBLIC_HOST:-localhost}:${EXPLORER_PORT:-3335}
SERVER_PORT: "3335"
AUDITABLE_WALLET_API: http://daemon:36941
PGUSER: ${EXPLORER_DB_USER:-explorer}
PGPASSWORD: ${EXPLORER_DB_PASS:-explorer}
PGDATABASE: ${EXPLORER_DB_NAME:-lethean_explorer}
PGHOST: explorer-db
PGPORT: "5432"
MEXC_API_URL: ""
ASSETS_WHITELIST_URL: ""
depends_on:
daemon:
condition: service_healthy
explorer-db:
condition: service_healthy
# --- Trade ---
trade-db:
image: postgres:16-alpine
container_name: lthn-trade-db
restart: unless-stopped
environment:
POSTGRES_USER: ${TRADE_DB_USER:-trade}
POSTGRES_PASSWORD: ${TRADE_DB_PASS:-trade}
POSTGRES_DB: ${TRADE_DB_NAME:-lethean_trade}
volumes:
- trade-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${TRADE_DB_USER:-trade}"]
interval: 10s
timeout: 5s
retries: 5
trade-api:
image: lthn/trade-api:testnet
container_name: lthn-trade-api
restart: unless-stopped
ports:
- "${TRADE_API_PORT:-3336}:3336"
environment:
PORT: "3336"
PGUSER: ${TRADE_DB_USER:-trade}
PGPASSWORD: ${TRADE_DB_PASS:-trade}
PGDATABASE: ${TRADE_DB_NAME:-lethean_trade}
PGHOST: trade-db
PGPORT: "5432"
JWT_SECRET: ${JWT_SECRET:-change-me-before-production}
DAEMON_RPC_URL: http://daemon:36941/json_rpc
depends_on:
daemon:
condition: service_healthy
trade-db:
condition: service_healthy
trade-frontend:
image: lthn/trade-frontend:testnet
container_name: lthn-trade-frontend
restart: unless-stopped
ports:
- "${TRADE_FRONTEND_PORT:-3338}:30289"
environment:
NEXT_PUBLIC_API_URL: http://${PUBLIC_HOST:-localhost}:${TRADE_API_PORT:-3336}
API_URL: http://trade-api:3336
depends_on:
- trade-api
# --- Mining Pool ---
pool-redis:
image: redis:7-alpine
container_name: lthn-pool-redis
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
pool:
image: lthn/pool:testnet
container_name: lthn-pool
restart: unless-stopped
ports:
- "${POOL_STRATUM_PORT:-5555}:5555"
- "${POOL_API_PORT:-2117}:2117"
- "7777:7777"
- "8888:8888"
volumes:
- ./pool-config.json:/pool/config.json:ro
depends_on:
daemon:
condition: service_healthy
wallet:
condition: service_started
pool-redis:
condition: service_healthy
# --- LNS (Lethean Name Service) ---
lns:
image: lthn/lns:testnet
container_name: lthn-lns
restart: unless-stopped
ports:
- "${LNS_HTTP_PORT:-5553}:5553"
- "${LNS_DNS_PORT:-5354}:5354/udp"
- "${LNS_DNS_PORT:-5354}:5354/tcp"
environment:
DAEMON_URL: http://daemon:36941
HSD_URL: http://host.docker.internal:14037
LNS_MODE: light
LNS_HTTP_PORT: "5553"
LNS_DNS_PORT: "5354"
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
daemon:
condition: service_healthy
# --- Docs ---
docs:
image: lthn/docs:testnet
container_name: lthn-docs
restart: unless-stopped
ports:
- "${DOCS_PORT:-8099}:80"
volumes:
chain-data:
wallet-data:
explorer-db:
trade-db:

View file

@ -0,0 +1,221 @@
# Lethean Testnet Network Simulation
# Spins up a 3-node testnet with explorer, wallet RPC, and trade services
#
# Usage:
# docker compose -f docker-compose.testnet.yml up -d
# docker compose -f docker-compose.testnet.yml logs -f node1
# docker compose -f docker-compose.testnet.yml down -v
#
# Nodes discover each other via exclusive-node flags.
# Node1 is the seed node, Node2 and Node3 connect to it.
services:
# === Blockchain Nodes ===
node1:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node1
ports:
- "46941:36941" # RPC
- "46942:36942" # P2P
volumes:
- node1-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level 1
--disable-upnp
networks:
lthn-testnet:
ipv4_address: 172.28.0.10
node2:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node2
volumes:
- node2-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--add-exclusive-node 172.28.0.10:36942
--allow-local-ip
--log-level 1
--disable-upnp
depends_on:
- node1
networks:
lthn-testnet:
ipv4_address: 172.28.0.11
node3:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-node3
volumes:
- node3-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--add-exclusive-node 172.28.0.10:36942
--allow-local-ip
--log-level 1
--disable-upnp
depends_on:
- node1
networks:
lthn-testnet:
ipv4_address: 172.28.0.12
# === Wallet RPC ===
wallet:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-wallet
ports:
- "46944:36944" # Wallet RPC
volumes:
- wallet-data:/wallet
entrypoint: >
sh -c "
if [ ! -f /wallet/testnet.wallet ]; then
echo '' | lethean-wallet-cli --generate-new-wallet /wallet/testnet.wallet --password '' --daemon-address node1:36941 --command exit;
fi;
lethean-wallet-cli
--wallet-file /wallet/testnet.wallet
--password ''
--daemon-address node1:36941
--rpc-bind-port 36944
--rpc-bind-ip 0.0.0.0
--do-pos-mining
"
depends_on:
- node1
networks:
lthn-testnet:
ipv4_address: 172.28.0.20
# === Explorer ===
explorer-db:
image: postgres:16-alpine
container_name: lthn-explorer-db
environment:
POSTGRES_USER: explorer
POSTGRES_PASSWORD: explorer
POSTGRES_DB: lethean_explorer
volumes:
- explorer-db-data:/var/lib/postgresql/data
networks:
lthn-testnet:
ipv4_address: 172.28.0.30
explorer:
build:
context: ../../lthn/zano-upstream/zano-explorer-zarcanum
dockerfile: Dockerfile
container_name: lthn-explorer
ports:
- "3335:3335"
environment:
API: http://node1:36941
FRONTEND_API: http://127.0.0.1:3335
SERVER_PORT: "3335"
AUDITABLE_WALLET_API: http://node1:36941
PGUSER: explorer
PGPASSWORD: explorer
PGDATABASE: lethean_explorer
PGHOST: explorer-db
PGPORT: "5432"
MEXC_API_URL: ""
depends_on:
- node1
- explorer-db
networks:
lthn-testnet:
ipv4_address: 172.28.0.31
# === Trade Backend ===
trade-db:
image: postgres:16-alpine
container_name: lthn-trade-db
environment:
POSTGRES_USER: trade
POSTGRES_PASSWORD: trade
POSTGRES_DB: lethean_trade
volumes:
- trade-db-data:/var/lib/postgresql/data
networks:
lthn-testnet:
ipv4_address: 172.28.0.40
trade-api:
build:
context: ../../lthn/zano-upstream/zano_trade_backend
container_name: lthn-trade-api
ports:
- "3336:3336"
environment:
PORT: "3336"
PGUSER: trade
PGPASSWORD: trade
PGDATABASE: lethean_trade
PGHOST: trade-db
PGPORT: "5432"
JWT_SECRET: testnet-dev-secret
DAEMON_RPC_URL: http://node1:36941/json_rpc
depends_on:
- node1
- trade-db
networks:
lthn-testnet:
ipv4_address: 172.28.0.41
networks:
lthn-testnet:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
volumes:
node1-data:
node2-data:
node3-data:
wallet-data:
explorer-db-data:
trade-db-data:

View file

@ -0,0 +1,126 @@
# Lethean VPN Stack — sandboxed legacy Python + WireGuard
# Chain node + wallet + VPN dispatcher + WireGuard gateway
#
# Usage:
# docker compose -f docker-compose.vpn.yml up -d
#
# This sandboxes the legacy Python VPN code inside containers
# until the CoreGO replacement is ready.
services:
# Chain daemon (testnet)
daemon:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-vpn-daemon
volumes:
- daemon-data:/data
command: >
lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level 1
--disable-upnp
networks:
vpn-net:
ipv4_address: 172.31.0.10
# Wallet RPC (for payment processing)
wallet:
build:
context: ..
dockerfile: utils/docker/lthn-chain/Dockerfile
target: chain-service
args:
BUILD_TESTNET: 1
BUILD_THREADS: 4
container_name: lthn-vpn-wallet
volumes:
- wallet-data:/wallet
entrypoint: >
sh -c "
if [ ! -f /wallet/vpn.wallet ]; then
echo '' | lethean-wallet-cli --generate-new-wallet /wallet/vpn.wallet --password '' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli
--wallet-file /wallet/vpn.wallet
--password ''
--daemon-address daemon:36941
--rpc-bind-port 36944
--rpc-bind-ip 0.0.0.0
"
depends_on:
- daemon
networks:
vpn-net:
ipv4_address: 172.31.0.20
# VPN Dispatcher (legacy Python, sandboxed)
dispatcher:
build:
context: ../../lthn/lthn-app-vpn
container_name: lthn-vpn-dispatcher
cap_add:
- NET_ADMIN
environment:
DAEMON_HOST: daemon
DAEMON_RPC_PORT: "36941"
MODE: server
ports:
- "8124:8124" # Server management API
depends_on:
- daemon
- wallet
networks:
vpn-net:
ipv4_address: 172.31.0.30
# WireGuard Gateway
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: lthn-vpn-wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
PUID: 1000
PGID: 1000
TZ: Europe/London
SERVERURL: auto
SERVERPORT: 51820
PEERS: 10
PEERDNS: 1.1.1.1
INTERNAL_SUBNET: 10.13.13.0
ALLOWEDIPS: 0.0.0.0/0,::/0
LOG_CONFS: "false"
ports:
- "51820:51820/udp"
volumes:
- wireguard-config:/config
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
networks:
vpn-net:
ipv4_address: 172.31.0.40
networks:
vpn-net:
driver: bridge
ipam:
config:
- subnet: 172.31.0.0/24
volumes:
daemon-data:
wallet-data:
wireguard-config:

58
docker/health.sh Executable file
View file

@ -0,0 +1,58 @@
#!/bin/bash
# Lethean Testnet Health Check
# Run: bash health.sh
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
check() {
local name="$1"
local url="$2"
local code
code=$(curl -sf -o /dev/null -w "%{http_code}" "$url" 2>/dev/null)
if [ "$code" = "200" ] || [ "$code" = "307" ] || [ "$code" = "404" ]; then
printf " ${GREEN}%-16s${NC} %s ${YELLOW}(HTTP %s)${NC}\n" "$name" "$url" "$code"
else
printf " ${RED}%-16s${NC} %s ${RED}(DOWN)${NC}\n" "$name" "$url"
fi
}
rpc() {
local name="$1"
local url="$2"
local method="$3"
local result
result=$(curl -sf "$url" -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"$method\"}" -H 'Content-Type: application/json' 2>/dev/null)
if [ -n "$result" ]; then
printf " ${GREEN}%-16s${NC} %s\n" "$name" "$(echo "$result" | python3 -c "
import sys,json
d=json.load(sys.stdin).get('result',{})
if 'height' in d:
hf = d.get('is_hardfok_active',[])
active = sum(1 for h in hf if h)
print(f'height={d[\"height\"]}, HF0-{active-1} active, status={d.get(\"status\",\"?\")}')
elif 'balance' in d:
print(f'{d[\"balance\"]/1e12:.4f} LTHN ({d[\"unlocked_balance\"]/1e12:.4f} unlocked)')
else:
print(json.dumps(d)[:80])
" 2>/dev/null)"
else
printf " ${RED}%-16s${NC} %s ${RED}(DOWN)${NC}\n" "$name" "$url"
fi
}
echo ""
echo " Lethean Testnet Health Check"
echo " $(date)"
echo " ---"
rpc "Daemon" "http://localhost:${DAEMON_RPC_PORT:-46941}/json_rpc" "getinfo"
rpc "Wallet" "http://localhost:${WALLET_RPC_PORT:-46944}/json_rpc" "getbalance"
check "Explorer" "http://localhost:${EXPLORER_PORT:-3335}/"
check "Trade API" "http://localhost:${TRADE_API_PORT:-3336}/"
check "Trade Web" "http://localhost:${TRADE_FRONTEND_PORT:-3338}/"
check "Pool API" "http://localhost:${POOL_API_PORT:-2117}/stats"
check "LNS" "http://localhost:${LNS_HTTP_PORT:-5553}/"
check "Docs" "http://localhost:${DOCS_PORT:-8099}/"
echo ""

View file

@ -0,0 +1,15 @@
[Unit]
Description=Lethean Testnet Ecosystem
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/lethean/docker
ExecStart=/usr/bin/docker compose -f docker-compose.pull.yml up -d
ExecStop=/usr/bin/docker compose -f docker-compose.pull.yml down
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target

52
docker/lethean/.env Normal file
View file

@ -0,0 +1,52 @@
# Lethean Testnet Configuration
# Copy to .env and customise before running:
# cp .env.example .env
# docker compose -f docker-compose.pull.yml up -d
# Public hostname (used by explorer and trade frontend)
PUBLIC_HOST=localhost
# Wallet password (empty = no password, change for production)
WALLET_PASSWORD=my-secure-pass
# Trade API JWT secret (CHANGE THIS for production)
JWT_SECRET=change-me-before-production
# Explorer database
EXPLORER_DB_USER=explorer
EXPLORER_DB_PASS=explorer
EXPLORER_DB_NAME=lethean_explorer
# Trade database
TRADE_DB_USER=trade
TRADE_DB_PASS=trade
TRADE_DB_NAME=lethean_trade
# Daemon log level (0=minimal, 1=normal, 2=detailed, 3=trace)
DAEMON_LOG_LEVEL=1
# Port overrides (defaults shown)
# DAEMON_RPC_PORT=46941
# DAEMON_P2P_PORT=46942
# WALLET_RPC_PORT=46944
# EXPLORER_PORT=3335
# TRADE_API_PORT=3336
# TRADE_FRONTEND_PORT=3338
# POOL_STRATUM_PORT=5555
# POOL_API_PORT=2117
# LNS_HTTP_PORT=5553
# LNS_DNS_PORT=5354
# === Exit Node Settings (docker-compose.exit.yml) ===
# Your public IP address (required for VPN exit node)
# EXIT_PUBLIC_IP=auto
# Exit node name (registered as on-chain alias)
# EXIT_NAME=my-exit-node
# Maximum VPN peers (WireGuard clients)
# EXIT_MAX_PEERS=25
# Timezone
# TZ=Europe/London

View file

@ -0,0 +1,52 @@
# Lethean Testnet Configuration
# Copy to .env and customise before running:
# cp .env.example .env
# docker compose -f docker-compose.pull.yml up -d
# Public hostname (used by explorer and trade frontend)
PUBLIC_HOST=localhost
# Wallet password (empty = no password, change for production)
WALLET_PASSWORD=
# Trade API JWT secret (CHANGE THIS for production)
JWT_SECRET=change-me-before-production
# Explorer database
EXPLORER_DB_USER=explorer
EXPLORER_DB_PASS=explorer
EXPLORER_DB_NAME=lethean_explorer
# Trade database
TRADE_DB_USER=trade
TRADE_DB_PASS=trade
TRADE_DB_NAME=lethean_trade
# Daemon log level (0=minimal, 1=normal, 2=detailed, 3=trace)
DAEMON_LOG_LEVEL=1
# Port overrides (defaults shown)
# DAEMON_RPC_PORT=46941
# DAEMON_P2P_PORT=46942
# WALLET_RPC_PORT=46944
# EXPLORER_PORT=3335
# TRADE_API_PORT=3336
# TRADE_FRONTEND_PORT=3338
# POOL_STRATUM_PORT=5555
# POOL_API_PORT=2117
# LNS_HTTP_PORT=5553
# LNS_DNS_PORT=5354
# === Exit Node Settings (docker-compose.exit.yml) ===
# Your public IP address (required for VPN exit node)
# EXIT_PUBLIC_IP=auto
# Exit node name (registered as on-chain alias)
# EXIT_NAME=my-exit-node
# Maximum VPN peers (WireGuard clients)
# EXIT_MAX_PEERS=25
# Timezone
# TZ=Europe/London

View file

@ -0,0 +1,86 @@
# Lethean Home Node
# A self-contained chain node for home users who want to support the network.
# Syncs the chain, runs a wallet with PoS staking, and exposes P2P for peering.
#
# Usage:
# cp .env.example .env # edit WALLET_PASSWORD at minimum
# docker compose -f docker-compose.node.yml up -d
#
# What it does:
# - Syncs and validates the Lethean blockchain
# - Peers with other nodes (P2P port 46942)
# - Runs a wallet that stakes automatically (PoS mining)
# - Optionally mines with ProgPoWZ (connect external GPU miner)
#
# Earnings:
# - PoS staking rewards (proportional to balance)
# - PoW block rewards if mining
#
# Ports:
# 46941 — Daemon RPC (local tools)
# 46942 — P2P (open this on your router for full node)
# 46944 — Wallet RPC (local tools)
services:
daemon:
image: lthn/chain:testnet
container_name: lthn-node
restart: unless-stopped
ports:
- "${DAEMON_RPC_PORT:-46941}:36941"
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
wallet:
image: lthn/chain:testnet
container_name: lthn-wallet
restart: unless-stopped
ports:
- "${WALLET_RPC_PORT:-46944}:36944"
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/node.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/node.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/node.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
volumes:
chain-data:
wallet-data:

301
docker/pool-config.json Normal file
View file

@ -0,0 +1,301 @@
{
"poolHost": "lethean.somewhere.com",
"coin": "Lethean",
"symbol": "LTHN",
"coinUnits": 1000000000000,
"coinDecimalPlaces": 12,
"coinDifficultyTarget": 120,
"blockchainExplorer": "http://localhost:3335/block/{id}",
"transactionExplorer": "http://localhost:3335/transaction/{id}",
"daemonType": "default",
"cnAlgorithm": "progpowz",
"cnVariant": 2,
"cnBlobType": 0,
"isRandomX": false,
"includeHeight": false,
"previousOffset": 7,
"offset": 2,
"isCryptonight": false,
"reward": 1000000000000,
"logging": {
"files": {
"level": "info",
"directory": "logs",
"flushInterval": 5,
"prefix": "Lethean"
},
"console": {
"level": "info",
"colors": true
}
},
"childPools": [],
"poolServer": {
"enabled": true,
"mergedMining": false,
"clusterForks": 3,
"poolAddress": "iTHNUNiuu3VP1yy8xH2y5iQaABKXurdjqZmzFiBiyR4dKG3j6534e9jMriY6SM7PH8NibVwVWW1DWJfQEWnSjS8n3Wgx86pQpY",
"intAddressPrefix": null,
"blockRefreshInterval": 1000,
"minerTimeout": 900,
"sslCert": "cert.pem",
"sslKey": "privkey.pem",
"sslCA": "chain.pem",
"ports": [
{
"port": 5555,
"difficulty": 50000,
"desc": "Low end hardware"
},
{
"port": 7777,
"difficulty": 500000,
"desc": "Mid/high end hardware"
},
{
"port": 8888,
"difficulty": 5000000,
"desc": "Nicehash, MRR"
}
],
"varDiff": {
"minDiff": 10000,
"maxDiff": 5000000,
"targetTime": 45,
"retargetTime": 60,
"variancePercent": 30,
"maxJump": 100
},
"paymentId": {
"addressSeparator": "+"
},
"fixedDiff": {
"enabled": true,
"addressSeparator": "."
},
"shareTrust": {
"enabled": true,
"min": 10,
"stepDown": 3,
"threshold": 10,
"penalty": 30
},
"banning": {
"enabled": true,
"time": 600,
"invalidPercent": 25,
"checkThreshold": 30
},
"slushMining": {
"enabled": false,
"weight": 300,
"blockTime": 60,
"lastBlockCheckRate": 1
}
},
"payments": {
"enabled": true,
"interval": 900,
"maxAddresses": 5,
"mixin": 10,
"priority": 0,
"transferFee": 10000000000,
"dynamicTransferFee": true,
"minerPayFee": true,
"minPayment": 1000000000000,
"maxPayment": 100000000000000,
"maxTransactionAmount": 100000000000000,
"denomination": 1000000000000
},
"blockUnlocker": {
"enabled": true,
"interval": 60,
"depth": 10,
"poolFee": 0.2,
"soloFee": 0.2,
"devDonation": 0.5,
"networkFee": 0.0
},
"api": {
"enabled": true,
"hashrateWindow": 600,
"updateInterval": 15,
"bindIp": "0.0.0.0",
"port": 2117,
"blocks": 30,
"payments": 30,
"password": "password",
"ssl": false,
"sslPort": 2119,
"sslCert": "cert.pem",
"sslKey": "privkey.pem",
"sslCA": "chain.pem",
"trustProxyIP": true
},
"zmq": {
"enabled": false,
"host": "127.0.0.1",
"port": 39995
},
"daemon": {
"host": "daemon",
"port": 36941
},
"wallet": {
"host": "wallet",
"port": 36944
},
"redis": {
"host": "pool-redis",
"port": 6379,
"db": 11,
"cleanupInterval": 15
},
"notifications": {
"emailTemplate": "email_templates/default.txt",
"emailSubject": {
"emailAdded": "Your email was registered",
"workerConnected": "Worker %WORKER_NAME% connected",
"workerTimeout": "Worker %WORKER_NAME% stopped hashing",
"workerBanned": "Worker %WORKER_NAME% banned",
"blockFound": "Block %HEIGHT% found !",
"blockUnlocked": "Block %HEIGHT% unlocked !",
"blockOrphaned": "Block %HEIGHT% orphaned !",
"payment": "We sent you a payment !"
},
"emailMessage": {
"emailAdded": "Your email has been registered to receive pool notifications.",
"workerConnected": "Your worker %WORKER_NAME% for address %MINER% is now connected from ip %IP%.",
"workerTimeout": "Your worker %WORKER_NAME% for address %MINER% has stopped submitting hashes on %LAST_HASH%.",
"workerBanned": "Your worker %WORKER_NAME% for address %MINER% has been banned.",
"blockFound": "Block found at height %HEIGHT% by miner %MINER% on %TIME%. Waiting maturity.",
"blockUnlocked": "Block mined at height %HEIGHT% with %REWARD% and %EFFORT% effort on %TIME%.",
"blockOrphaned": "Block orphaned at height %HEIGHT% :(",
"payment": "A payment of %AMOUNT% has been sent to %ADDRESS% wallet."
},
"telegramMessage": {
"workerConnected": "Your worker _%WORKER_NAME%_ for address _%MINER%_ is now connected from ip _%IP%_.",
"workerTimeout": "Your worker _%WORKER_NAME%_ for address _%MINER%_ has stopped submitting hashes on _%LAST_HASH%_.",
"workerBanned": "Your worker _%WORKER_NAME%_ for address _%MINER%_ has been banned.",
"blockFound": "*Block found at height* _%HEIGHT%_ *by miner* _%MINER%_*! Waiting maturity.*",
"blockUnlocked": "*Block mined at height* _%HEIGHT%_ *with* _%REWARD%_ *and* _%EFFORT%_ *effort on* _%TIME%_*.*",
"blockOrphaned": "*Block orphaned at height* _%HEIGHT%_ *:(*",
"payment": "A payment of _%AMOUNT%_ has been sent."
}
},
"email": {
"enabled": false,
"fromAddress": "your@email.com",
"transport": "sendmail",
"sendmail": {
"path": "/usr/sbin/sendmail"
},
"smtp": {
"host": "smtp.example.com",
"port": 587,
"secure": false,
"auth": {
"user": "username",
"pass": "password"
},
"tls": {
"rejectUnauthorized": false
}
},
"mailgun": {
"key": "your-private-key",
"domain": "mg.yourdomain"
}
},
"telegram": {
"enabled": false,
"botName": "",
"token": "",
"channel": "",
"channelStats": {
"enabled": false,
"interval": 30
},
"botCommands": {
"stats": "/stats",
"report": "/report",
"notify": "/notify",
"blocks": "/blocks"
}
},
"monitoring": {
"daemon": {
"checkInterval": 60,
"rpcMethod": "getblockcount"
},
"wallet": {
"checkInterval": 60,
"rpcMethod": "getbalance"
}
},
"prices": {
"source": "tradeogre",
"currency": "USD"
},
"charts": {
"pool": {
"hashrate": {
"enabled": true,
"updateInterval": 60,
"stepInterval": 1800,
"maximumPeriod": 86400
},
"miners": {
"enabled": true,
"updateInterval": 60,
"stepInterval": 1800,
"maximumPeriod": 86400
},
"workers": {
"enabled": true,
"updateInterval": 60,
"stepInterval": 1800,
"maximumPeriod": 86400
},
"difficulty": {
"enabled": true,
"updateInterval": 1800,
"stepInterval": 10800,
"maximumPeriod": 604800
},
"price": {
"enabled": true,
"updateInterval": 1800,
"stepInterval": 10800,
"maximumPeriod": 604800
},
"profit": {
"enabled": true,
"updateInterval": 1800,
"stepInterval": 10800,
"maximumPeriod": 604800
}
},
"user": {
"hashrate": {
"enabled": true,
"updateInterval": 180,
"stepInterval": 1800,
"maximumPeriod": 86400
},
"worker_hashrate": {
"enabled": true,
"updateInterval": 60,
"stepInterval": 60,
"maximumPeriod": 86400
},
"payments": {
"enabled": true
}
},
"blocks": {
"enabled": true,
"days": 30
}
}
}

90
docker/test-network.sh Executable file
View file

@ -0,0 +1,90 @@
#!/bin/bash
# Lethean testnet network validation script
# Tests: node sync, mining, wallet, block propagation
#
# Usage: ./test-network.sh [compose-file]
# Default: docker-compose.nodes.yml
set -e
COMPOSE=${1:-docker-compose.nodes.yml}
echo "=== Lethean Network Test ==="
echo "Using: $COMPOSE"
echo ""
# Check all nodes are running
echo "1. Checking node health..."
for n in 1 2 3; do
port=$((46940 + (n-1)*10 + 1))
height=$(curl -s -X POST http://127.0.0.1:$port/json_rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin)['result']['height'])" 2>/dev/null)
echo " node$n (:$port): height=$height"
done
echo ""
echo "2. Checking P2P connectivity..."
peers=$(curl -s -X POST http://127.0.0.1:46941/json_rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' 2>/dev/null | \
python3 -c "import sys,json; d=json.load(sys.stdin)['result']; print(f'out={d[\"outgoing_connections_count\"]} in={d[\"incoming_connections_count\"]}')" 2>/dev/null)
echo " node1 peers: $peers"
echo ""
echo "3. Testing getblocktemplate..."
template=$(curl -s -X POST http://127.0.0.1:46941/json_rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"0","method":"getblocktemplate","params":{"wallet_address":"iTHNUNiuu3VP1yy8xH2y5iQaABKXurdjqZmzFiBiyR4dKG3j6534e9jMriY6SM7PH8NibVwVWW1DWJfQEWnSjS8n3Wgx86pQpY"}}' 2>/dev/null | \
python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(f'height={r[\"height\"]} diff={r[\"difficulty\"]}')" 2>/dev/null)
echo " template: $template"
echo ""
echo "4. Starting mining on node1..."
curl -s -X POST http://127.0.0.1:46941/start_mining \
-H 'Content-Type: application/json' \
-d '{"miner_address":"iTHNUNiuu3VP1yy8xH2y5iQaABKXurdjqZmzFiBiyR4dKG3j6534e9jMriY6SM7PH8NibVwVWW1DWJfQEWnSjS8n3Wgx86pQpY","threads_count":4}' 2>/dev/null | python3 -m json.tool 2>/dev/null
echo ""
echo "5. Waiting 60s for blocks..."
sleep 60
echo ""
echo "6. Checking sync across nodes..."
heights=""
for n in 1 2 3; do
port=$((46940 + (n-1)*10 + 1))
h=$(curl -s -X POST http://127.0.0.1:$port/json_rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin)['result']['height'])" 2>/dev/null)
echo " node$n: height=$h"
heights="$heights $h"
done
# Check all nodes at same height
unique=$(echo $heights | tr ' ' '\n' | sort -u | wc -l)
if [ "$unique" -eq 1 ]; then
echo ""
echo " PASS: All nodes synced at same height"
else
echo ""
echo " WARN: Nodes at different heights (propagation delay normal)"
fi
echo ""
echo "7. Checking HF status..."
curl -s -X POST http://127.0.0.1:46941/json_rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' 2>/dev/null | \
python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
hf=[i for i,v in enumerate(d['is_hardfok_active']) if v]
print(f' Active HFs: {hf}')
print(f' PoS allowed: {d[\"pos_allowed\"]}')
print(f' Aliases: {d[\"alias_count\"]}')
"
echo ""
echo "=== Test Complete ==="

View file

@ -0,0 +1,153 @@
#!/usr/bin/env python3
"""
Lethean Key Bridge Prototype
Derives an HNS sidechain secp256k1 keypair from a Lethean ed25519 spend key.
One seed phrase both chains.
Lethean seed phrase
ed25519 spend key (32 bytes)
Main chain wallet (native CryptoNote)
HKDF("lethean-hns-bridge", spend_key)
secp256k1 private key (32 bytes)
Sidechain wallet (derived)
Usage:
python3 key-bridge-prototype.py <hex_spend_key>
python3 key-bridge-prototype.py --from-wallet http://127.0.0.1:46944/json_rpc
Dependencies:
pip install cryptography secp256k1 (or use hashlib for prototype)
"""
import hashlib
import hmac
import sys
import json
import urllib.request
def derive_sidechain_key(spend_key_hex: str) -> dict:
"""
Derive a secp256k1 private key from a Lethean ed25519 spend key.
Uses HKDF-like construction:
prk = HMAC-SHA256(key="lethean-hns-bridge", msg=spend_key)
secp256k1_key = HMAC-SHA256(key=prk, msg="hns-sidechain-v1" || 0x01)
The domain separation ensures:
- Different derivation paths produce different keys
- The ed25519 key cannot be recovered from the secp256k1 key
- Future derivation paths (v2, v3) won't collide
"""
spend_key = bytes.fromhex(spend_key_hex)
assert len(spend_key) == 32, f"Spend key must be 32 bytes, got {len(spend_key)}"
# Step 1: Extract — domain-separated PRK
salt = b"lethean-hns-bridge"
prk = hmac.new(salt, spend_key, hashlib.sha256).digest()
# Step 2: Expand — derive the secp256k1 key
info = b"hns-sidechain-v1\x01"
secp256k1_privkey = hmac.new(prk, info, hashlib.sha256).digest()
# secp256k1 requires the key to be in range [1, n-1]
# n = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
key_int = int.from_bytes(secp256k1_privkey, 'big')
if key_int == 0 or key_int >= n:
# Extremely unlikely but handle it — rehash
secp256k1_privkey = hmac.new(prk, b"hns-sidechain-v1\x02", hashlib.sha256).digest()
key_int = int.from_bytes(secp256k1_privkey, 'big') % (n - 1) + 1
secp256k1_privkey = key_int.to_bytes(32, 'big')
# Derive additional keys for future use
document_signing_key = hmac.new(prk, b"document-signing-v1\x01", hashlib.sha256).digest()
audit_key = hmac.new(prk, b"audit-trail-v1\x01", hashlib.sha256).digest()
return {
"source": {
"type": "ed25519",
"chain": "lethean-mainchain",
"spend_key": spend_key_hex,
},
"derived": {
"hns_sidechain": {
"type": "secp256k1",
"chain": "lethean-hns-sidechain",
"private_key": secp256k1_privkey.hex(),
"derivation": "HKDF(salt=lethean-hns-bridge, ikm=spend_key, info=hns-sidechain-v1)",
},
"document_signing": {
"type": "ed25519",
"purpose": "document hash timestamping",
"private_key": document_signing_key.hex(),
"derivation": "HKDF(salt=lethean-hns-bridge, ikm=spend_key, info=document-signing-v1)",
},
"audit": {
"type": "ed25519",
"purpose": "audit trail verification",
"private_key": audit_key.hex(),
"derivation": "HKDF(salt=lethean-hns-bridge, ikm=spend_key, info=audit-trail-v1)",
},
},
"derivation_version": "1.0",
"note": "All keys derived deterministically from the Lethean spend key. One seed, all chains and purposes.",
}
def get_spend_key_from_wallet(rpc_url: str) -> str:
"""Fetch the spend key from a running wallet RPC."""
payload = json.dumps({
"jsonrpc": "2.0",
"id": "0",
"method": "get_wallet_info",
"params": {}
}).encode()
req = urllib.request.Request(
rpc_url,
data=payload,
headers={"Content-Type": "application/json"}
)
try:
with urllib.request.urlopen(req, timeout=5) as resp:
data = json.loads(resp.read())
# The spend key isn't directly in get_wallet_info
# We'd need a custom RPC or the seed to derive it
# For prototype, use the address as a stand-in
print("Note: Full implementation needs 'get_spend_key' RPC or seed phrase input")
print(f"Wallet address: {data.get('result', {}).get('wi', {}).get('address', '?')}")
return None
except Exception as e:
print(f"Error connecting to wallet: {e}")
return None
def main():
if len(sys.argv) < 2:
print(__doc__)
print("\nExample with test key:")
test_key = "a" * 64 # 32 bytes of 0xAA
result = derive_sidechain_key(test_key)
print(json.dumps(result, indent=2))
return
if sys.argv[1] == "--from-wallet":
rpc_url = sys.argv[2] if len(sys.argv) > 2 else "http://127.0.0.1:46944/json_rpc"
spend_key = get_spend_key_from_wallet(rpc_url)
if not spend_key:
print("\nUsing test key for demonstration:")
spend_key = "7b9f1e2a3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7"
else:
spend_key = sys.argv[1]
result = derive_sidechain_key(spend_key)
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()

130
docker/tools/register-reserved.sh Executable file
View file

@ -0,0 +1,130 @@
#!/bin/bash
# Lethean Reserved Name Registrar
# Batch-registers protected aliases on the main chain to prevent squatting.
#
# Usage:
# bash register-reserved.sh [names-file] [wallet-rpc] [batch-size] [delay]
#
# Defaults:
# names-file: /tmp/protected-names-priority.txt
# wallet-rpc: http://127.0.0.1:46944/json_rpc
# batch-size: 10 (aliases per batch before checking balance)
# delay: 2 (seconds between registrations)
NAMES_FILE="${1:-/tmp/protected-names-priority.txt}"
WALLET_RPC="${2:-http://127.0.0.1:46944/json_rpc}"
BATCH_SIZE="${3:-10}"
DELAY="${4:-2}"
COMMENT="v=lthn1;type=reserved;reason=hns-protected"
LOG_FILE="/tmp/register-reserved.log"
DONE_FILE="/tmp/registered-names.txt"
touch "$DONE_FILE"
get_balance() {
curl -sf "$WALLET_RPC" -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(d['unlocked_balance'])
" 2>/dev/null
}
get_address() {
curl -sf "$WALLET_RPC" -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
print(json.load(sys.stdin)['result']['address'])
" 2>/dev/null
}
register_alias() {
local name="$1"
local address="$2"
result=$(curl -sf "$WALLET_RPC" -d "{
\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"register_alias\",
\"params\":{
\"alias\":\"$name\",
\"address\":\"$address\",
\"comment\":\"$COMMENT\"
}
}" -H 'Content-Type: application/json' 2>/dev/null)
if echo "$result" | grep -q '"result"'; then
tx=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin)['result'].get('tx_hash','ok'))" 2>/dev/null)
echo "$name" >> "$DONE_FILE"
echo "$(date +%H:%M:%S) OK @$name ($tx)" | tee -a "$LOG_FILE"
return 0
else
error=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('error',{}).get('message','unknown')[:80])" 2>/dev/null)
echo "$(date +%H:%M:%S) ERR @$name$error" | tee -a "$LOG_FILE"
return 1
fi
}
# Get wallet address
ADDRESS=$(get_address)
if [ -z "$ADDRESS" ]; then
echo "ERROR: Can't connect to wallet at $WALLET_RPC"
exit 1
fi
echo "Wallet: $ADDRESS"
echo "Names file: $NAMES_FILE ($(wc -l < "$NAMES_FILE") names)"
echo "Already registered: $(wc -l < "$DONE_FILE") names"
echo "Comment: $COMMENT"
echo "Batch: $BATCH_SIZE, Delay: ${DELAY}s"
echo "Log: $LOG_FILE"
echo "---"
BALANCE=$(get_balance)
BALANCE_LTHN=$(echo "scale=2; $BALANCE / 1000000000000" | bc 2>/dev/null)
echo "Balance: $BALANCE_LTHN LTHN"
echo ""
COUNT=0
REGISTERED=0
FAILED=0
SKIPPED=0
while IFS= read -r name; do
# Skip empty lines and comments
[[ -z "$name" || "$name" == \#* ]] && continue
# Skip already registered
if grep -qxF "$name" "$DONE_FILE" 2>/dev/null; then
((SKIPPED++))
continue
fi
# Check balance every batch
if (( COUNT % BATCH_SIZE == 0 && COUNT > 0 )); then
BALANCE=$(get_balance)
BALANCE_LTHN=$(echo "scale=2; $BALANCE / 1000000000000" | bc 2>/dev/null)
echo "--- Batch checkpoint: $BALANCE_LTHN LTHN, $REGISTERED registered, $FAILED failed ---"
# Stop if balance too low (need 1 LTHN + fee)
if (( BALANCE < 1100000000000 )); then
echo "Balance too low ($BALANCE_LTHN LTHN). Stopping."
break
fi
fi
register_alias "$name" "$ADDRESS"
if [ $? -eq 0 ]; then
((REGISTERED++))
else
((FAILED++))
fi
((COUNT++))
sleep "$DELAY"
done < "$NAMES_FILE"
echo ""
echo "=== Done ==="
echo "Registered: $REGISTERED"
echo "Failed: $FAILED"
echo "Skipped: $SKIPPED"
echo "Total processed: $COUNT"

2
docs

@ -1 +1 @@
Subproject commit 12e20efce7eaf51e38d8953c318633b1c5189256 Subproject commit e40a78d5020661f05d9bae64f2edd4519d9d98b3

View file

@ -0,0 +1,30 @@
{
"payments": [
{
"address_this": "iTHNdRWX6pKGXF1HqHgZyXie8EdaCwwdWUmsEnQhNojSUrkrR2eTemhFYkjWXbhdbyGcRBLgV2RYp3HhNAFCQ67w4bTHErZL1J",
"amount_this": 10000000.0,
"this_usd_price": "1.0",
"paid_prm": "",
"prm_usd_price": "",
"paid_xmr": "",
"xmr_usd_price": "",
"paid_qtum": "",
"qtum_usd_price": "",
"paid_bch": "",
"bch_usd_price": "",
"paid_rep": "",
"rep_usd_price": "",
"paid_dash": "",
"dash_usd_price": "",
"paid_ltc": "",
"ltc_usd_price": "",
"paid_eos": "",
"eos_usd_price": "",
"paid_eth": "",
"eth_usd_price": "",
"paid_btc": "",
"btc_usd_price": ""
}
],
"proof_string": "Lethean genesis — the advantage of the nature of information being easy to spread but hard to stifle. - Satoshi Nakamoto"
}

Some files were not shown because too many files have changed in this diff Show more