8 Commits

Author SHA1 Message Date
7baadc74b1 添加参数
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 13s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 21s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 24s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 35s
Build and Release / release (push) Has been skipped
2025-12-06 13:59:12 +08:00
b220fdc9e9 添加脚本
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 13s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 19s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 24s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 34s
Build and Release / release (push) Has been skipped
2025-12-05 20:44:57 +08:00
782d9e05bb 添加 Tari Solo 支持
All checks were successful
Build and Release / build-and-test (amd64, alpine) (push) Successful in 18s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 32s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 23s
Build and Release / build-and-test (arm64, alpine) (push) Successful in 1m0s
Build and Release / release (push) Successful in 1m11s
2025-12-05 18:03:10 +08:00
5545b76e0b 添加 README
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 9s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 16s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 21s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 32s
Build and Release / release (push) Has been skipped
2025-12-03 16:41:21 +08:00
9142021f26 添加deb包构建,删除容器构建
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 8s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 15s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 19s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 37s
Build and Release / release (push) Successful in 1m8s
2025-12-03 16:10:42 +08:00
8100b2f2e5 修改 PACKAGE_VERSION
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 7s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 7s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 14s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 22s
Build and Release / docker-images (push) Successful in 39s
Build and Release / release (push) Successful in 47s
2025-12-02 14:56:36 +08:00
877ba3d3bb 修改12
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 7s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 7s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 13s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 13s
Build and Release / docker-images (push) Successful in 26s
Build and Release / release (push) Successful in 53s
2025-12-02 14:51:55 +08:00
47c0c4de32 修改11
All checks were successful
Build and Release / build-and-test (arm64, alpine) (push) Successful in 7s
Build and Release / build-and-test (arm64, ubuntu) (push) Successful in 7s
Build and Release / build-and-test (amd64, alpine) (push) Successful in 14s
Build and Release / build-and-test (amd64, ubuntu) (push) Successful in 14s
Build and Release / docker-images (push) Successful in 25s
Build and Release / release (push) Successful in 27s
2025-12-02 14:41:55 +08:00
18 changed files with 2065 additions and 213 deletions

View File

@@ -9,7 +9,7 @@ on:
env: env:
DOCKER_BUILDKIT: "1" DOCKER_BUILDKIT: "1"
PRODUCT_NAME: "xxxigcc" PRODUCT_NAME: "xxxigcc"
PACKAGE_VERSION: "3.4.6-xg1" PACKAGE_VERSION: "3.4.6-xg2"
BUILDX_NO_DEFAULT_ATTESTATIONS: "1" BUILDX_NO_DEFAULT_ATTESTATIONS: "1"
jobs: jobs:
@@ -70,85 +70,28 @@ jobs:
test/xxxigDaemon --version 2>/dev/null || echo "⚠️ 跳过版本检查" test/xxxigDaemon --version 2>/dev/null || echo "⚠️ 跳过版本检查"
rm -rf test rm -rf test
- name: Build Debian package
if: matrix.distro == 'ubuntu'
run: |
# 安装 dpkg-deb如果需要
sudo apt-get update && sudo apt-get install -y dpkg-dev
TARGZ="${PRODUCT_NAME}-${{ matrix.arch }}-${{ matrix.distro }}-${PACKAGE_VERSION}.tar.gz"
echo "📦 Building Debian package for ${{ matrix.arch }}..."
chmod +x debian/build-deb.sh
./debian/build-deb.sh ${{ matrix.arch }} ${PACKAGE_VERSION} "${TARGZ}"
ls -lh *.deb
- uses: https://github.com/ChristopherHX/gitea-upload-artifact@v4 - uses: https://github.com/ChristopherHX/gitea-upload-artifact@v4
with: with:
name: binaries-${{ matrix.arch }}-${{ matrix.distro }} name: binaries-${{ matrix.arch }}-${{ matrix.distro }}
path: "*.tar.gz" path: |
*.tar.gz
*.deb
retention-days: 1 retention-days: 1
docker-images:
runs-on: ubuntu-latest-amd64
needs: build-and-test
if: github.ref_name == 'main' || github.ref_name == 'develop' || startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
- name: Debug branch info
run: |
echo "📋 Branch Information:"
echo " github.ref: ${{ github.ref }}"
echo " github.ref_name: ${{ github.ref_name }}"
echo " github.event_name: ${{ github.event_name }}"
- uses: https://github.com/ChristopherHX/gitea-download-artifact@v4
with:
pattern: binaries-*
path: ./app
merge-multiple: true
- name: Setup Docker and Login
run: |
# 尝试设置 QEMU忽略错误
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes 2>/dev/null || true
# 创建 buildx builder增加资源限制和优化参数
docker buildx create --use --name multiarch-builder \
--driver docker-container \
--driver-opt network=host \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=50000000 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000 \
--buildkitd-flags '--allow-insecure-entitlement security.insecure --allow-insecure-entitlement network.host' \
|| true
docker buildx inspect --bootstrap
# 登录
echo "${{ secrets.BUILD_TOKEN }}" | docker login ${{ gitea.server_url }} -u ${{ gitea.actor }} --password-stdin
- name: Determine Docker tag
id: tag
run: |
if [ "${{ github.ref_name }}" = "main" ]; then
TAG="latest"
elif [ "${{ github.ref_name }}" = "develop" ]; then
TAG="develop"
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
TAG="${{ github.ref_name }}"
else
TAG="${{ github.ref_name }}"
fi
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "📦 Docker tag: ${TAG}"
- name: Build and push Docker images
run: |
# 移除 URL 中的 https:// 前缀
REGISTRY=$(echo "${{ gitea.server_url }}" | sed 's|https\?://||')/${{ gitea.repository }}
TAG="${{ steps.tag.outputs.tag }}"
echo "📦 Docker Registry: ${REGISTRY}"
echo "📦 Docker Tag: ${TAG}"
BUILD_ARGS="--pull --push --platform linux/amd64,linux/arm64 \
--build-arg TARGZ_FILE_AMD64=${PRODUCT_NAME}-amd64-alpine-${PACKAGE_VERSION}.tar.gz \
--build-arg TARGZ_FILE_ARM64=${PRODUCT_NAME}-arm64-alpine-${PACKAGE_VERSION}.tar.gz \
--provenance=false --sbom=false"
echo "🐳 Building server image..."
docker buildx build $BUILD_ARGS -t "${REGISTRY}/server:${TAG}" -f docker/Dockerfile.Server .
echo "🐳 Building daemon image..."
docker buildx build $BUILD_ARGS -t "${REGISTRY}/daemon:${TAG}" -f docker/Dockerfile.Daemon .
release: release:
runs-on: ubuntu-latest-amd64 runs-on: ubuntu-latest-amd64
needs: build-and-test needs: build-and-test
@@ -164,47 +107,115 @@ jobs:
env: env:
TOKEN: ${{ secrets.BUILD_TOKEN }} TOKEN: ${{ secrets.BUILD_TOKEN }}
TAG: ${{ github.ref_name }} TAG: ${{ github.ref_name }}
REGISTRY: ${{ gitea.server_url }}
OWNER: ${{ gitea.repository_owner }}
REPO: ${{ gitea.repository }}
run: | run: |
cd packages cd packages
# 上传所有包 # 提取仓库信息(移除 https:// 前缀和仓库路径)
REGISTRY=$(echo "${{ gitea.server_url }}" | sed 's|https\?://||')
OWNER="${{ gitea.repository_owner }}"
REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2)
echo "📦 上传包到 Generic Package Registry..." echo "📦 上传包到 Generic Package Registry..."
echo " Registry: ${REGISTRY}"
echo " Owner: ${OWNER}"
echo " Package: ${PRODUCT_NAME}"
echo " Version: ${TAG}"
# 上传所有 tar.gz 包到 Generic Package Registry
for file in *.tar.gz; do for file in *.tar.gz; do
[ ! -f "$file" ] && continue [ ! -f "$file" ] && continue
echo " ⬆️ $file" echo " ⬆️ $file"
curl -fsSL -X POST \ curl -fsSL -X PUT \
-H "Authorization: token ${TOKEN}" \ -H "Authorization: token ${TOKEN}" \
-F "file=@$file" \ --upload-file "$file" \
"${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/$file" || { "https://${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/$file" || {
echo "❌ 上传失败: $file" echo "❌ 上传失败: $file"
exit 1 exit 1
} }
done done
# 生成 Release 描述 # 上传 Debian 包到 Debian Package Registry (支持多个发行版)
echo "📝 生成 Release 描述..." echo ""
BODY="## Release ${TAG}\n\n### 📥 下载链接\n" echo "📦 上传 Debian 包到 Debian Package Registry..."
for file in *.tar.gz; do for file in *.deb; do
[ -f "$file" ] && BODY="${BODY}- [${file}](${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/${file})\n" [ ! -f "$file" ] && continue
# 上传到 bookworm (Debian 12)
echo " ⬆️ $file → bookworm"
curl -fsSL -X PUT \
-H "Authorization: token ${TOKEN}" \
--upload-file "$file" \
"https://${REGISTRY}/api/packages/${OWNER}/debian/pool/bookworm/main/upload" || {
echo "❌ Debian 包上传失败: $file (bookworm)"
exit 1
}
# 上传到 trixie (Debian 13)
echo " ⬆️ $file → trixie"
curl -fsSL -X PUT \
-H "Authorization: token ${TOKEN}" \
--upload-file "$file" \
"https://${REGISTRY}/api/packages/${OWNER}/debian/pool/trixie/main/upload" || {
echo "❌ Debian 包上传失败: $file (trixie)"
exit 1
}
done done
# 生成 Release JSON payload
echo ""
echo "📝 生成 Release..."
export REGISTRY OWNER TAG
RELEASE_DATA=$(python3 -c 'import json,glob,os;r=os.environ["REGISTRY"];o=os.environ["OWNER"];p=os.environ["PRODUCT_NAME"];t=os.environ["TAG"];b=["## Release "+t,"","### 📥 下载方式","","#### 方式 1: 直接下载(推荐)","","点击下面 **Assets** 部分的文件名直接下载。","","#### 方式 2: Generic Package Registry",""]+[f"- [`{f}`](https://{r}/api/packages/{o}/generic/{p}/{t}/{f})" for f in sorted(glob.glob("*.tar.gz"))]+["","#### 方式 3: Debian Repository","","**Debian 12 (bookworm):**","","```bash","# Download GPG key",f"sudo curl https://{r}/api/packages/{o}/debian/repository.key -o /etc/apt/keyrings/gitea-{o}.asc","","# Add repository",f"echo \"deb [signed-by=/etc/apt/keyrings/gitea-{o}.asc] https://{r}/api/packages/{o}/debian bookworm main\" | sudo tee -a /etc/apt/sources.list.d/{o}.list","","# Update and install","sudo apt-get update","sudo apt-get install xxxigcc","```","","**Debian 13 (trixie):**","","```bash","# Download GPG key",f"sudo curl https://{r}/api/packages/{o}/debian/repository.key -o /etc/apt/keyrings/gitea-{o}.asc","","# Add repository",f"echo \"deb [signed-by=/etc/apt/keyrings/gitea-{o}.asc] https://{r}/api/packages/{o}/debian trixie main\" | sudo tee -a /etc/apt/sources.list.d/{o}.list","","# Update and install","sudo apt-get update","sudo apt-get install xxxigcc","```"];print(json.dumps({"tag_name":t,"name":f"Release {t}","body":"\n".join(b),"draft":False,"prerelease":False}))')
# 创建 Release # 创建 Release
echo ""
echo "🎉 创建 Release..." echo "🎉 创建 Release..."
curl -fsSL -X POST \ RESPONSE=$(curl -fsSL -w "\n%{http_code}" -X POST \
-H "Authorization: token ${TOKEN}" \ -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${REGISTRY}/api/v1/repos/${REPO}/releases" \ "https://${REGISTRY}/api/v1/repos/${{ gitea.repository }}/releases" \
-d @- << EOF || echo "⚠️ Release 可能已存在" -d "${RELEASE_DATA}")
{
"tag_name": "${TAG}",
"name": "Release ${TAG}",
"body": "${BODY}",
"draft": false,
"prerelease": false
}
EOF
echo "✅ Release 创建完成!" HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$RESPONSE" | head -n-1)
if [ "$HTTP_CODE" = "201" ]; then
echo "✅ Release 创建成功"
RELEASE_ID=$(echo "$RESPONSE_BODY" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
echo " Release ID: ${RELEASE_ID}"
elif [ "$HTTP_CODE" = "409" ]; then
echo "⚠️ Release 已存在,获取现有 Release ID..."
RELEASE_ID=$(curl -fsSL \
-H "Authorization: token ${TOKEN}" \
"https://${REGISTRY}/api/v1/repos/${{ gitea.repository }}/releases/tags/${TAG}" | \
grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
echo " Release ID: ${RELEASE_ID}"
else
echo "❌ 创建 Release 失败 (HTTP ${HTTP_CODE})"
echo "$RESPONSE_BODY"
exit 1
fi
# 上传文件作为 Release 附件
echo ""
echo "📎 上传文件作为 Release 附件..."
for file in *.tar.gz *.deb; do
[ ! -f "$file" ] && continue
echo " ⬆️ $file"
# 使用 multipart/form-data 上传附件
curl -fsSL -X POST \
-H "Authorization: token ${TOKEN}" \
-F "attachment=@${file}" \
"https://${REGISTRY}/api/v1/repos/${{ gitea.repository }}/releases/${RELEASE_ID}/assets?name=${file}" || {
echo " ⚠️ 附件上传失败: $file可能已存在"
}
done
echo ""
echo "✅ Release 创建完成!"
echo "🔗 访问: https://${REGISTRY}/${{ gitea.repository }}/releases/tag/${TAG}"
# 清理临时文件
rm -f release_body.md

191
README.md Normal file
View File

@@ -0,0 +1,191 @@
# XXXigCC
> 禁用捐赠功能的 XMRigCC 修改版本。
[![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg)](LICENSE)
[![Build Status](https://img.shields.io/badge/build-passing-brightgreen.svg)](.gitea/workflows/ci.yaml)
## 🎯 主要特性
- 🚫 **零捐赠** - 捐赠等级设为 0所有捐赠端点已禁用
- 🏗️ **多架构支持** - 原生支持 AMD64 和 ARM64 架构
- 📦 **多种安装方式** - 提供 Debian 包和通用二进制包
- 🐧 **多发行版兼容** - 支持 Ubuntu、Debian 和 Alpine Linux
- 🎛️ **集中化管理** - 通过 Web UI 集中管理多个挖矿节点
- 🔄 **自动更新** - 通过 Debian 仓库轻松安装和更新
## 🚀 快速开始
### 方式一Debian/Ubuntu推荐
#### Debian 12 (Bookworm)
```bash
# 1. 下载并添加 GPG 密钥
sudo curl https://gitea.bcde.io/api/packages/wangdefa/debian/repository.key \
-o /etc/apt/keyrings/gitea-wangdefa.asc
# 2. 添加软件源
echo "deb [signed-by=/etc/apt/keyrings/gitea-wangdefa.asc] https://gitea.bcde.io/api/packages/wangdefa/debian bookworm main" | \
sudo tee -a /etc/apt/sources.list.d/wangdefa.list
# 3. 安装
sudo apt-get update
sudo apt-get install xxxigcc
```
#### Debian 13 (Trixie)
```bash
# 1. 下载并添加 GPG 密钥
sudo curl https://gitea.bcde.io/api/packages/wangdefa/debian/repository.key \
-o /etc/apt/keyrings/gitea-wangdefa.asc
# 2. 添加软件源
echo "deb [signed-by=/etc/apt/keyrings/gitea-wangdefa.asc] https://gitea.bcde.io/api/packages/wangdefa/debian trixie main" | \
sudo tee -a /etc/apt/sources.list.d/wangdefa.list
# 3. 安装
sudo apt-get update
sudo apt-get install xxxigcc
```
### 方式二:通用二进制包
```bash
# 1. 下载对应架构的包
wget https://gitea.bcde.io/releases/download/VERSION/xxxigcc-amd64-ubuntu-VERSION.tar.gz
# 2. 解压
tar -xzf xxxigcc-amd64-ubuntu-VERSION.tar.gz
cd xxxigcc
# 3. 编辑配置文件
nano config.json # 用于 Daemon/Miner
nano config_cc.json # 用于 Server
# 4. 运行
./xxxigDaemon --config config.json # 挖矿客户端
# 或
./xxxigServer --config config_cc.json # 控制服务器
```
## 📋 使用说明
### Debian/Ubuntu 系统服务
#### 启动服务器(控制中心)
```bash
# 配置文件位置:/etc/xxxigcc/config_cc.json
sudo systemctl enable xxxigcc-server.service
sudo systemctl start xxxigcc-server.service
# 查看状态
sudo systemctl status xxxigcc-server.service
# 查看日志
sudo journalctl -u xxxigcc-server -f
```
#### 启动挖矿客户端
```bash
# 配置文件位置:/etc/xxxigcc/config.json
sudo systemctl enable xxxigcc-daemon.service
sudo systemctl start xxxigcc-daemon.service
# 查看状态
sudo systemctl status xxxigcc-daemon.service
# 查看日志
sudo journalctl -u xxxigcc-daemon -f
```
### 访问 Web 管理界面
服务器启动后,访问:
```
http://服务器IP:3344
```
默认凭据(请及时修改):
- 用户名admin
- 密码:请查看配置文件
## ⚙️ 配置说明
### 配置文件位置
#### Debian/Ubuntu 系统包
```
/etc/xxxigcc/config.json # Daemon/Miner 配置
/etc/xxxigcc/config_cc.json # Server 配置
/var/log/xxxigcc/ # 日志目录
```
#### 通用二进制包
```
./config.json # Daemon/Miner 配置
./config_cc.json # Server 配置
```
### 主要配置项
#### config.json (Daemon/Miner)
```json
{
"cc-url": "控制服务器地址",
"cc-access-token": "访问令牌",
"cc-worker-id": "工作节点ID",
"pools": [
{
"url": "矿池地址",
"user": "钱包地址",
"pass": "密码"
}
]
}
```
#### config_cc.json (Server)
```json
{
"cc-port": 3344,
"cc-user": "admin",
"cc-pass": "管理员密码",
"cc-access-token": "访问令牌",
"cc-enable-tls": false
}
```
## 🔄 修改内容
本项目基于 [Bendr0id/xmrigCC](https://github.com/Bendr0id/xmrigCC) 进行以下修改:
1. **禁用捐赠**`kDefaultDonateLevel` 设为 0
2. **捐赠端点**:重定向到本地 (127.0.0.1)
3. **详细日志**:默认启用详细日志模式
4. **项目重命名**"xmrigcc" → "xxxigcc"
所有修改通过 [init.sh](init.sh) 在构建过程中自动应用。
## 📝 许可证
本项目基于 GPL-3.0 许可证开源。
- 原始项目:[XMRigCC](https://github.com/Bendr0id/XMRigCC) (GPL-3.0)
- 修改内容:详见 [init.sh](init.sh)
## 🙏 致谢
- [XMRigCC](https://github.com/Bendr0id/XMRigCC) - 原始项目
- [XMRig](https://github.com/xmrig/xmrig) - 核心挖矿引擎
## ⚠️ 免责声明
本软件仅供学习和研究使用。使用本软件进行挖矿活动请遵守当地法律法规。作者不对使用本软件造成的任何损失或法律问题负责。

91
debian/build-deb.sh vendored Executable file
View File

@@ -0,0 +1,91 @@
#!/bin/bash
set -e
# 参数检查
if [ $# -ne 3 ]; then
echo "Usage: $0 <ARCH> <VERSION> <TARGZ_FILE>"
echo "Example: $0 amd64 3.4.6-xg2 xxxigcc-amd64-ubuntu-3.4.6-xg2.tar.gz"
exit 1
fi
ARCH=$1
VERSION=$2
TARGZ_FILE=$3
PKG_NAME="xxxigcc"
DEB_FILE="${PKG_NAME}_${VERSION}_${ARCH}.deb"
# 转换架构名称Docker 使用的架构名到 Debian 架构名)
case "$ARCH" in
amd64)
DEB_ARCH="amd64"
;;
arm64)
DEB_ARCH="arm64"
;;
*)
echo "Unsupported architecture: $ARCH"
exit 1
;;
esac
echo "📦 Building Debian package: ${DEB_FILE}"
echo " Architecture: ${DEB_ARCH}"
echo " Version: ${VERSION}"
echo " Source: ${TARGZ_FILE}"
# 创建临时目录
BUILD_DIR=$(mktemp -d)
trap "rm -rf $BUILD_DIR" EXIT
# 创建包目录结构
PKG_DIR="${BUILD_DIR}/${PKG_NAME}_${VERSION}_${DEB_ARCH}"
mkdir -p "${PKG_DIR}/DEBIAN"
mkdir -p "${PKG_DIR}/opt/xxxigcc"
mkdir -p "${PKG_DIR}/lib/systemd/system"
# 解压二进制文件
echo "📂 Extracting binaries..."
tar -xzf "${TARGZ_FILE}" -C "${PKG_DIR}/opt/xxxigcc"
# 生成 control 文件
echo "📝 Generating control file..."
sed -e "s/{{VERSION}}/${VERSION}/" \
-e "s/{{ARCH}}/${DEB_ARCH}/" \
debian/control.template > "${PKG_DIR}/DEBIAN/control"
# 复制维护脚本
echo "📋 Copying maintainer scripts..."
cp debian/postinst "${PKG_DIR}/DEBIAN/postinst"
cp debian/prerm "${PKG_DIR}/DEBIAN/prerm"
cp debian/postrm "${PKG_DIR}/DEBIAN/postrm"
chmod 755 "${PKG_DIR}/DEBIAN/postinst"
chmod 755 "${PKG_DIR}/DEBIAN/prerm"
chmod 755 "${PKG_DIR}/DEBIAN/postrm"
# 复制 systemd service 文件
echo "🔧 Installing systemd services..."
cp debian/xxxigcc-server.service "${PKG_DIR}/lib/systemd/system/"
cp debian/xxxigcc-daemon.service "${PKG_DIR}/lib/systemd/system/"
# 设置权限
chmod 755 "${PKG_DIR}/opt/xxxigcc/xxxigServer"
chmod 755 "${PKG_DIR}/opt/xxxigcc/xxxigDaemon"
chmod 755 "${PKG_DIR}/opt/xxxigcc/xxxigMiner"
chmod 644 "${PKG_DIR}/opt/xxxigcc/config.json"
chmod 644 "${PKG_DIR}/opt/xxxigcc/config_cc.json"
chmod 644 "${PKG_DIR}/opt/xxxigcc/index.html"
chmod 644 "${PKG_DIR}/lib/systemd/system/xxxigcc-server.service"
chmod 644 "${PKG_DIR}/lib/systemd/system/xxxigcc-daemon.service"
# 构建 deb 包
echo "🔨 Building package..."
dpkg-deb --build --root-owner-group "${PKG_DIR}" "${DEB_FILE}"
# 检查包
echo "✅ Package built successfully!"
echo "📦 Package: $(pwd)/${DEB_FILE}"
echo "📊 Package info:"
dpkg-deb --info "${DEB_FILE}"
echo ""
echo "🎉 Done!"

18
debian/control.template vendored Normal file
View File

@@ -0,0 +1,18 @@
Package: xxxigcc
Version: {{VERSION}}
Section: net
Priority: optional
Architecture: {{ARCH}}
Depends: libc6, libuv1, libssl3 | libssl1.1, libhwloc15 | libhwloc5
Maintainer: XXXigCC Team <noreply@example.com>
Homepage: https://github.com/Bendr0id/xmrigCC
Description: Cryptocurrency mining software suite
XXXigCC is a customized build of XMRigCC,
a cryptocurrency mining software with centralized management.
.
This package includes:
- xxxigServer: Central control server with web UI
- xxxigDaemon: Client daemon that connects to the server
- xxxigMiner: Mining executable controlled by the daemon
- Systemd service configurations
- Default configuration files

82
debian/postinst vendored Executable file
View File

@@ -0,0 +1,82 @@
#!/bin/sh
set -e
# Create user and group if they don't exist
if ! getent group xxxigcc >/dev/null; then
addgroup --system xxxigcc
fi
if ! getent passwd xxxigcc >/dev/null; then
adduser --system --ingroup xxxigcc --no-create-home \
--home /opt/xxxigcc --shell /usr/sbin/nologin \
--gecos "XXXigCC Service" xxxigcc
fi
# Create log directory
mkdir -p /var/log/xxxigcc
chown xxxigcc:xxxigcc /var/log/xxxigcc
chmod 750 /var/log/xxxigcc
# Create config directory
mkdir -p /etc/xxxigcc
# Copy default configs if they don't exist
if [ ! -f /etc/xxxigcc/config.json ]; then
cp /opt/xxxigcc/config.json /etc/xxxigcc/config.json
chown xxxigcc:xxxigcc /etc/xxxigcc/config.json
chmod 640 /etc/xxxigcc/config.json
fi
if [ ! -f /etc/xxxigcc/config_cc.json ]; then
cp /opt/xxxigcc/config_cc.json /etc/xxxigcc/config_cc.json
chown xxxigcc:xxxigcc /etc/xxxigcc/config_cc.json
chmod 640 /etc/xxxigcc/config_cc.json
fi
# Set permissions
chown -R xxxigcc:xxxigcc /opt/xxxigcc
chmod 755 /opt/xxxigcc
chmod 755 /opt/xxxigcc/xxxigServer
chmod 755 /opt/xxxigcc/xxxigDaemon
chmod 755 /opt/xxxigcc/xxxigMiner
# Reload systemd
if [ -d /run/systemd/system ]; then
systemctl daemon-reload
# Note: Services are NOT auto-enabled or auto-started
# Users should manually enable the services they need:
# systemctl enable xxxigcc-server.service
# systemctl start xxxigcc-server.service
# or
# systemctl enable xxxigcc-daemon.service
# systemctl start xxxigcc-daemon.service
fi
echo ""
echo "✅ XXXigCC installed successfully!"
echo ""
echo "📋 Service Information:"
echo ""
echo " xxxigcc-server - Control server with web UI (uses config_cc.json)"
echo " xxxigcc-daemon - Mining client daemon (uses config.json, auto-calls xxxigMiner)"
echo ""
echo "To start the server (central control):"
echo " sudo systemctl enable xxxigcc-server.service"
echo " sudo systemctl start xxxigcc-server.service"
echo ""
echo "To start the daemon (mining client):"
echo " sudo systemctl enable xxxigcc-daemon.service"
echo " sudo systemctl start xxxigcc-daemon.service"
echo ""
echo "Configuration files:"
echo " /etc/xxxigcc/config.json - Daemon/Miner configuration"
echo " /etc/xxxigcc/config_cc.json - Server configuration"
echo ""
echo "Binaries location:"
echo " /opt/xxxigcc/xxxigServer - Control server"
echo " /opt/xxxigcc/xxxigDaemon - Client daemon (auto-calls xxxigMiner)"
echo " /opt/xxxigcc/xxxigMiner - Miner executable"
echo ""
exit 0

30
debian/postrm vendored Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
set -e
case "$1" in
purge)
# Remove log directory
rm -rf /var/log/xxxigcc
# Remove config directory
rm -rf /etc/xxxigcc
# Remove user and group
if getent passwd xxxigcc >/dev/null; then
deluser --system xxxigcc 2>/dev/null || true
fi
if getent group xxxigcc >/dev/null; then
delgroup --system xxxigcc 2>/dev/null || true
fi
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
# Reload systemd
if [ -d /run/systemd/system ]; then
systemctl daemon-reload
fi
;;
esac
exit 0

17
debian/prerm vendored Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
set -e
# Stop services before removal
if [ -d /run/systemd/system ]; then
for service in xxxigcc-server.service xxxigcc-daemon.service; do
if systemctl is-active "$service" >/dev/null 2>&1; then
systemctl stop "$service"
fi
if systemctl is-enabled "$service" >/dev/null 2>&1; then
systemctl disable "$service"
fi
done
fi
exit 0

38
debian/xxxigcc-daemon.service vendored Normal file
View File

@@ -0,0 +1,38 @@
[Unit]
Description=XXXigCC Daemon (Miner Client)
After=network.target
[Service]
Type=simple
# 工作目录
WorkingDirectory=/opt/xxxigcc
# 执行命令
ExecStart=/opt/xxxigcc/xxxigDaemon --config /etc/xxxigcc/config.json --log-file=/var/log/xxxigcc/daemon.log
# 重启策略
Restart=always
RestartSec=10
# 用户和组
User=xxxigcc
Group=xxxigcc
# 安全设置
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/xxxigcc
# 日志设置
StandardOutput=journal
StandardError=journal
SyslogIdentifier=xxxigcc-daemon
# 资源限制
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target

38
debian/xxxigcc-server.service vendored Normal file
View File

@@ -0,0 +1,38 @@
[Unit]
Description=XXXigCC Server (Control Center)
After=network.target
[Service]
Type=simple
# 工作目录
WorkingDirectory=/opt/xxxigcc
# 执行命令
ExecStart=/opt/xxxigcc/xxxigServer --config /etc/xxxigcc/config_cc.json --log-file=/var/log/xxxigcc/server.log
# 重启策略
Restart=always
RestartSec=10
# 用户和组
User=xxxigcc
Group=xxxigcc
# 安全设置
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/xxxigcc
# 日志设置
StandardOutput=journal
StandardError=journal
SyslogIdentifier=xxxigcc-server
# 资源限制
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target

View File

@@ -1,33 +0,0 @@
FROM alpine:3.21
ARG TARGETARCH
ARG TARGZ_FILE_AMD64
ARG TARGZ_FILE_ARM64
RUN apk update && apk add --no-cache wget
COPY ./app /app
RUN if [ "$TARGETARCH" = "amd64" ]; then \
ARCH_FILE="$TARGZ_FILE_AMD64"; \
elif [ "$TARGETARCH" = "arm64" ]; then \
ARCH_FILE="$TARGZ_FILE_ARM64"; \
else \
echo "不支持的架构: $TARGETARCH" && exit 1; \
fi && \
echo "TARGETARCH: $TARGETARCH" && \
echo "使用文件: $ARCH_FILE" && \
ls -la /app/ && \
tar -xzf "/app/${ARCH_FILE}" -C /app --strip-components=1 && \
ls -la /app/ && \
rm -rf /app/*.tar.gz /app/config.json /app/config_cc.json /app/index.html /app/xxxigServer && \
addgroup -S xxxig && \
adduser -S -G xxxig xxxig && \
mkdir -p /app/data && \
chown -R xxxig:xxxig /app && \
chmod +x /app/xxxigDaemon /app/xxxigMiner
USER xxxig
WORKDIR /app
ENTRYPOINT ["/app/xxxigDaemon"]

View File

@@ -1,78 +0,0 @@
FROM alpine:3.21
ARG TARGETARCH
ARG TARGZ_FILE_AMD64
ARG TARGZ_FILE_ARM64
RUN apk update && apk add --no-cache wget gettext
COPY ./app /app
RUN if [ "$TARGETARCH" = "amd64" ]; then \
ARCH_FILE="$TARGZ_FILE_AMD64"; \
elif [ "$TARGETARCH" = "arm64" ]; then \
ARCH_FILE="$TARGZ_FILE_ARM64"; \
else \
echo "不支持的架构: $TARGETARCH" && exit 1; \
fi && \
echo "TARGETARCH: $TARGETARCH" && \
echo "使用文件: $ARCH_FILE" && \
ls -la /app/ && \
tar -xzf "/app/${ARCH_FILE}" -C /app --strip-components=1 && \
ls -la /app/ && \
rm -rf /app/*.tar.gz /app/config.json /app/config_cc.json /app/xxxigDaemon /app/xxxigMiner && \
addgroup -S xxxig && \
adduser -S -G xxxig xxxig && \
mkdir -p /app/data && \
chown -R xxxig:xxxig /app && \
chmod +x /app/xxxigServer
ENV LOG_FILE=/app/data/xxxigServer.log \
BIND_IP=0.0.0.0 \
PORT=80 \
USER= \
PASS= \
ACCESS_TOKEN= \
TLS=false \
CERT_FILE= \
KEY_FILE= \
TG_BOT_TOKEN= \
TG_CHAT_ID=
COPY <<EOF /app/config.template.json
{
"bind-ip": "\${BIND_IP}",
"log-file": "\${LOG_FILE}",
"port": \${PORT},
"user": "\${USER}",
"pass": "\${PASS}",
"access-token": "\${ACCESS_TOKEN}",
"use-tls": \${TLS},
"cert-file": "\${CERT_FILE}",
"key-file": "\${KEY_FILE}",
"telegram-bot-token": "\${TG_BOT_TOKEN}",
"telegram-chat-id": "\${TG_CHAT_ID}"
}
EOF
RUN chmod 644 /app/config.template.json
COPY <<EOF /app/entrypoint.sh
#!/bin/sh
if [ ! -f /app/data/config.json ]; then
envsubst < /app/config.template.json > /app/data/config.json
fi
exec "\$@"
EOF
RUN chmod +x /app/entrypoint.sh
EXPOSE 80 443
VOLUME /app/data \
/app/certs
USER xxxig
WORKDIR /app
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["/app/xxxigServer", "-c", "/app/data/config.json"]

View File

@@ -33,6 +33,9 @@ RUN git clone --recursive https://github.com/Bendr0id/xmrigCC.git && \
WORKDIR /xxxigcc WORKDIR /xxxigcc
RUN rm -rf ./src/base/tools/cryptonote/BlockTemplate.cpp
COPY ./templates/BlockTemplate.cpp ./src/base/tools/cryptonote/BlockTemplate.cpp
COPY ./init.sh ./init.sh COPY ./init.sh ./init.sh
# 根据目标架构优化编译 # 根据目标架构优化编译

View File

@@ -37,6 +37,9 @@ RUN git clone --recursive https://github.com/Bendr0id/xmrigCC.git && \
WORKDIR /xxxigcc WORKDIR /xxxigcc
RUN rm -rf ./src/base/tools/cryptonote/BlockTemplate.cpp
COPY ./templates/BlockTemplate.cpp ./src/base/tools/cryptonote/BlockTemplate.cpp
COPY ./init.sh ./init.sh COPY ./init.sh ./init.sh
# 根据目标架构设置编译环境和参数 # 根据目标架构设置编译环境和参数

255
script/README.md Normal file
View File

@@ -0,0 +1,255 @@
# XXXigCC 安装脚本
本目录包含 XXXigCC 的安装和卸载脚本。
## 脚本列表
### 1. install.sh - 通用安装脚本
从 Gitea Generic Package Registry 下载 tar.gz 包并安装。
**支持系统:**
- Alpine Linux (OpenRC)
- Ubuntu/Debian (systemd)
**使用方法:**
```bash
# 基本安装
sudo ./install.sh -o pool.example.com:3333 -w YOUR_WALLET_ADDRESS
# 指定版本和线程数
sudo ./install.sh -v 3.4.6-xg1 -t 4 -o pool.example.com:3333 -w YOUR_WALLET
# 启用高级功能
sudo ./install.sh -o pool.example.com:3333 -w YOUR_WALLET \
--1gb-pages --tls --keepalive \
--cc --cc-url http://server:3344 --cc-token YOUR_TOKEN
```
### 2. install.deb.sh - DEB 包安装脚本
通过 APT 仓库直接安装。
**支持系统:**
- Ubuntu/Debian (systemd)
**使用方法:**
```bash
# 基本安装
sudo ./install.deb.sh -o pool.example.com:3333 -w YOUR_WALLET_ADDRESS
# 指定版本
sudo ./install.deb.sh -v 3.4.6-xg1 -o pool.example.com:3333 -w YOUR_WALLET
# 查看可用版本
apt-cache policy xxxigcc
```
### 3. uninstall.sh - 卸载脚本
通用卸载脚本,自动检测安装方式。
**使用方法:**
```bash
# 交互式卸载(推荐)
sudo ./uninstall.sh
# 直接卸载,不确认
sudo ./uninstall.sh -y
# 完全清除(包括配置文件和日志)
sudo ./uninstall.sh --purge -y
```
## 命令行参数
### 通用参数(两种安装脚本都支持)
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `-v, --version` | 版本号 | latest |
| `-t, --threads` | 线程数 | 自动 (CPU 核心数) |
| `-a, --algo` | 算法 | rx/0 |
| `-o, --pool` | 矿池地址 | **必需** |
| `-w, --wallet` | 钱包地址 | 自动生成 |
| `-p, --password` | 矿池密码 | 自动生成 |
| `--1gb-pages` | 启用 1GB 大页 | false |
| `--tls` | 启用 TLS | false |
| `--keepalive` | 启用 KeepAlive | false |
| `--daemon` | 启用 SOLO 挖矿 | false |
| `--nicehash` | 启用 NiceHash 模式 | **true** |
| `--verbose` | 启用详细输出 | **true** |
| `--submit-to-origin` | 提交到原始矿池 | false |
| `--self-select` | 自选矿池地址 | - |
| `--cc` | 启用 CC | false |
| `--cc-url` | CC 服务器地址 | - |
| `--cc-work-id` | CC 工作 ID | 自动生成 |
| `--cc-token` | CC 访问令牌 | - |
| `--cc-tls` | 启用 CC TLS | false |
## 安装路径
### tar.gz 安装
```
/etc/miner/xxxigcc/
├── config.json # 配置文件
├── xxxigDaemon # 守护进程
├── xxxigMiner # 挖矿程序
└── xxxigcc.log # 日志文件
```
**服务文件:**
- Alpine: `/etc/init.d/xxxigcc`
- Ubuntu/Debian: `/etc/systemd/system/xxxigcc.service`
### DEB 包安装
```
/etc/xxxigcc/
└── config.json # 配置文件
/var/log/xxxigcc/ # 日志目录
/opt/xxxigcc/
├── xxxigDaemon # 守护进程
├── xxxigMiner # 挖矿程序
└── xxxigServer # 控制服务器
```
**服务文件:**
- `/etc/systemd/system/xxxigcc-daemon.service`
- `/etc/systemd/system/xxxigcc-server.service`
## 服务管理
### Alpine Linux
```bash
# 查看状态
rc-service xxxigcc status
# 启动/停止/重启
rc-service xxxigcc start
rc-service xxxigcc stop
rc-service xxxigcc restart
# 查看日志
tail -f /etc/miner/xxxigcc/xxxigcc.log
```
### Ubuntu/Debian
#### tar.gz 安装
```bash
# 查看状态
systemctl status xxxigcc
# 启动/停止/重启
systemctl start xxxigcc
systemctl stop xxxigcc
systemctl restart xxxigcc
# 查看日志
journalctl -u xxxigcc -f
```
#### DEB 包安装
```bash
# 查看状态
systemctl status xxxigcc-daemon
# 启动/停止/重启
systemctl start xxxigcc-daemon
systemctl stop xxxigcc-daemon
systemctl restart xxxigcc-daemon
# 查看日志
journalctl -u xxxigcc-daemon -f
```
## 配置文件
配置文件为 JSON 格式,位于:
- tar.gz: `/etc/miner/xxxigcc/config.json`
- DEB: `/etc/xxxigcc/config.json`
修改配置后需要重启服务:
```bash
# Alpine
rc-service xxxigcc restart
# Ubuntu/Debian (tar.gz)
systemctl restart xxxigcc
# Ubuntu/Debian (DEB)
systemctl restart xxxigcc-daemon
```
## 升级版本
### tar.gz 安装
重新运行安装脚本,指定新版本:
```bash
sudo ./install.sh -v 3.4.7-xg1 -o pool.example.com:3333 -w YOUR_WALLET
```
### DEB 包安装
使用 APT 升级:
```bash
sudo apt-get update
sudo apt-get install xxxigcc
```
## 故障排查
### 检查服务状态
```bash
# Alpine
rc-service xxxigcc status
# Ubuntu/Debian
systemctl status xxxigcc # 或 xxxigcc-daemon
```
### 查看日志
```bash
# Alpine / tar.gz
tail -f /etc/miner/xxxigcc/xxxigcc.log
# Ubuntu/Debian (tar.gz)
journalctl -u xxxigcc -f
# Ubuntu/Debian (DEB)
journalctl -u xxxigcc-daemon -f
```
### 手动测试
```bash
# tar.gz 安装
/etc/miner/xxxigcc/xxxigDaemon -c /etc/miner/xxxigcc/config.json
# DEB 包安装
xxxigDaemon -c /etc/xxxigcc/config.json
```
### 常见问题
**问题: 下载失败**
```bash
# 检查网络连接
curl -I https://gitea.bcde.io
# 手动下载测试
curl -O https://gitea.bcde.io/api/packages/wangdefa/generic/xxxigcc/3.4.6-xg1/xxxigcc-amd64-ubuntu-3.4.6-xg1.tar.gz
```
**问题: 服务无法启动**
```bash
# 检查配置文件
cat /etc/miner/xxxigcc/config.json | jq .
# 检查权限
ls -la /etc/miner/xxxigcc/
```
**问题: APT 更新失败 (DEB)**
```bash
# 清理并重新添加源
sudo rm /etc/apt/sources.list.d/xxxigcc.list
sudo ./install_deb.sh -o pool.example.com:3333 -w YOUR_WALLET
```

273
script/install.deb.sh Executable file
View File

@@ -0,0 +1,273 @@
#!/bin/bash
#
# XXXigCC 安装脚本 - DEB 版本
# 通过 APT 从 Gitea Generic Package Registry 安装 XXXigCC
#
set -e
declare -r BLUE="\033[0;34m"
declare -r RED="\033[0;31m"
declare -r GREEN="\033[0;32m"
declare -r YELLOW="\033[0;33m"
declare -r RESET="\033[0m"
# 基本配置
CONFIG_DIR="/etc/xxxigcc"
LOG_DIR="/var/log/xxxigcc"
CONFIG_FILE="$CONFIG_DIR/config.json"
# Gitea 配置
GITEA_SERVER="gitea.bcde.io"
GITEA_OWNER="wangdefa"
# 默认参数
DEFAULT_VERSION="latest"
DEFAULT_THREADS=0
DEFAULT_POOL_ALGO="rx/0"
DEFAULT_POOL_TLS="false"
DEFAULT_POOL_KEEPALIVE="false"
DEFAULT_POOL_DAEMON="false"
DEFAULT_POOL_SUBMIT_TO_ORIGIN="false"
DEFAULT_POOL_NICEHASH="true"
DEFAULT_ONE_GB_PAGES="false"
DEFAULT_VERBOSE="true"
DEFAULT_CC_ENABLED="false"
DEFAULT_CC_TLS="false"
# 辅助函数
log() { echo -e "${1}${2}${RESET}"; }
error() { log "$RED" "错误: $1"; exit 1; }
check_os() {
grep -qiE 'debian|ubuntu' /etc/os-release || error "仅支持 Debian/Ubuntu 系统"
}
get_arch() {
case $(uname -m) in
x86_64) echo "amd64" ;;
aarch64) echo "arm64" ;;
*) error "不支持的架构: $(uname -m)" ;;
esac
}
# 添加 APT 源并更新
add_apt_repository() {
echo "deb [trusted=yes] https://${GITEA_SERVER}/api/packages/${GITEA_OWNER}/debian bookworm main" \
>/etc/apt/sources.list.d/xxxigcc.list
apt-get update -qq
}
# 卸载旧版本
uninstall_xxxigcc() {
systemctl stop xxxigcc-daemon xxxigcc-server 2>/dev/null || true
systemctl disable xxxigcc-daemon xxxigcc-server 2>/dev/null || true
apt-get remove -y xxxigcc 2>/dev/null || true
rm -rf "$CONFIG_DIR" "$LOG_DIR" /etc/apt/sources.list.d/xxxigcc.list
systemctl daemon-reload 2>/dev/null || true
}
# 安装并启动服务
install_and_start() {
log "$BLUE" "安装 XXXigCC $version..."
if [[ "$version" == "latest" ]]; then
apt-get install -y xxxigcc
else
apt-get install -y xxxigcc="$version"
fi
log "$BLUE" "启动服务..."
systemctl daemon-reload
systemctl enable --now xxxigcc-daemon.service
log "$GREEN" "安装完成"
}
# 配置 CPU 亲和性
configure_cpu_rx() {
local cpu_cores=$(nproc)
local rx_array="" step=1
[[ "$threads" -le $((cpu_cores / 2)) ]] && step=2
for ((i = 0; i < threads; i++)); do
[[ $i -gt 0 ]] && rx_array+=", "
rx_array+="$((i * step))"
done
local field="rx"
[[ "$pool_algo" == "panthera" ]] && field="panthera"
jq ".cpu.$field = [ $rx_array ]" "$CONFIG_FILE" >"$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
}
# 更新配置文件
replace_config() {
[[ ! -f "$CONFIG_FILE" ]] && error "配置文件缺失"
local jq_cmd=".\"log-file\" = \"\"
| .\"donate-level\" = 0
| .\"donate-over-proxy\" = 0
| .pools[0].algo = \"$pool_algo\"
| .pools[0].url = \"$pool_address\"
| .pools[0].user = \"$wallet_address\"
| .pools[0].pass = \"$pool_password\"
| .pools[0].tls = $pool_tls
| .pools[0].nicehash = $pool_nicehash
| .\"verbose\" = $verbose"
[[ "$one_gb_pages" == "true" ]] && jq_cmd+=" | .randomx.\"1gb-pages\" = true"
[[ "$pool_keepalive" == "true" ]] && jq_cmd+=" | .pools[0].keepalive = true"
[[ -n "$pool_tls_fingerprint" ]] && jq_cmd+=" | .pools[0].\"tls-fingerprint\" = \"$pool_tls_fingerprint\""
[[ "$pool_daemon" == "true" ]] && jq_cmd+=" | .pools[0].daemon = true"
if [[ "$pool_submit_to_origin" == "true" ]]; then
jq_cmd+=" | .pools[0].\"submit-to-origin\" = true | .pools[0].\"self-select\" = \"$pool_self_select\""
fi
if [[ "$cc_enabled" == "true" ]]; then
jq_cmd+=" | .\"cc-client\".enabled = true
| .\"cc-client\".servers[0].url = \"$cc_url\"
| .\"cc-client\".servers[0].\"access-token\" = \"$cc_token\"
| .\"cc-client\".servers[0].\"use-tls\" = $cc_tls
| .\"cc-client\".\"worker-id\" = \"$cc_work_id\""
else
jq_cmd+=" | .\"cc-client\".enabled = false"
fi
jq "$jq_cmd" "$CONFIG_FILE" >"$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
configure_cpu_rx
}
show_usage() {
cat <<EOF
用法: $0 [选项]
选项:
-v, --version <版本> XXXigCC 版本 (默认: $DEFAULT_VERSION)
-t, --threads <数字> 线程数 (默认: 自动)
-a, --algo <算法> 矿池算法 (默认: $DEFAULT_POOL_ALGO)
-o, --pool <地址> 矿池地址 (必需)
-w, --wallet <地址> 钱包地址
-p, --password <密码> 矿池密码 (默认自动生成)
--1gb-pages 启用 1GB 大页
--tls 启用 TLS
--keepalive 启用 KeepAlive
--daemon 启用 SOLO 挖矿
--nicehash 启用 NiceHash 模式 (默认: 启用)
--submit-to-origin 提交到原始矿池
--self-select <地址> 自选矿池地址
--verbose 启用详细输出 (默认: 启用)
--cc 启用 CC
--cc-url <地址> CC 服务器地址
--cc-work-id <ID> CC 工作 ID
--cc-token <令牌> CC 访问令牌
--cc-tls 启用 CC TLS
-h, --help 显示帮助信息
示例:
$0 -o pool.example.com:3333 -w YOUR_WALLET_ADDRESS
EOF
exit 1
}
parse_args() {
version=$DEFAULT_VERSION
threads=$DEFAULT_THREADS
pool_algo=$DEFAULT_POOL_ALGO
pool_tls=$DEFAULT_POOL_TLS
pool_keepalive=$DEFAULT_POOL_KEEPALIVE
pool_submit_to_origin=$DEFAULT_POOL_SUBMIT_TO_ORIGIN
pool_daemon=$DEFAULT_POOL_DAEMON
pool_nicehash=$DEFAULT_POOL_NICEHASH
pool_self_select=""
pool_address=""
wallet_address=""
pool_password=""
pool_tls_fingerprint=""
verbose=$DEFAULT_VERBOSE
cc_enabled=$DEFAULT_CC_ENABLED
cc_url=""
cc_work_id=""
cc_token=""
cc_tls=$DEFAULT_CC_TLS
one_gb_pages=$DEFAULT_ONE_GB_PAGES
while [[ $# -gt 0 ]]; do
case "$1" in
-v | --version) version="$2"; shift 2 ;;
-t | --threads) threads="$2"; shift 2 ;;
-a | --algo) pool_algo="$2"; shift 2 ;;
-o | --pool) pool_address="$2"; shift 2 ;;
-w | --wallet) wallet_address="$2"; shift 2 ;;
-p | --password) pool_password="$2"; shift 2 ;;
--1gb-pages) one_gb_pages="true"; shift ;;
--cc-url) cc_url="$2"; shift 2 ;;
--cc-work-id) cc_work_id="$2"; shift 2 ;;
--cc-token) cc_token="$2"; shift 2 ;;
--tls-fingerprint) pool_tls_fingerprint="$2"; shift 2 ;;
--tls) pool_tls="true"; shift ;;
--keepalive) pool_keepalive="true"; shift ;;
--daemon) pool_daemon="true"; shift ;;
--nicehash) pool_nicehash="true"; shift ;;
--submit-to-origin) pool_submit_to_origin="true"; shift ;;
--self-select) pool_self_select="$2"; shift 2 ;;
--verbose) verbose="true"; shift ;;
--cc) cc_enabled="true"; shift ;;
--cc-tls) cc_tls="true"; shift ;;
-h | --help) show_usage ;;
*) error "无效选项: $1" ;;
esac
done
# 验证必需参数
[[ -z "$pool_address" ]] && error "矿池地址不能为空"
[[ ! "$threads" =~ ^[0-9]+$ ]] && error "无效线程数"
[[ "$pool_submit_to_origin" == "true" && -z "$pool_self_select" ]] && \
error "启用 submit_to_origin 必须设置 self_select"
# 处理默认值
if [[ -z "$pool_password" ]]; then
local ip=$(curl -4s --retry 3 --connect-timeout 10 ifconfig.me 2>/dev/null || echo "0.0.0.0")
local random_str=$(tr -dc '0-9a-zA-Z' </dev/urandom | head -c 5)
pool_password=$(echo "$ip" | awk -F. '{print $3"_"$4}')"_$random_str"
fi
[[ -z "$cc_work_id" ]] && cc_work_id="$(get_arch)_$pool_password"
[[ -z "$wallet_address" ]] && wallet_address="empty_wallet_$(date +%s)"
if [[ "$threads" -le 0 ]]; then
threads=$(nproc)
elif [[ "$threads" -gt $(nproc) ]]; then
threads=$(nproc)
fi
}
main() {
parse_args "$@"
check_os
# 检查并安装依赖
command -v curl &>/dev/null || apt-get install -y curl
command -v jq &>/dev/null || apt-get install -y jq
log "$BLUE" "配置信息:"
echo " 版本: $version"
echo " 架构: $(get_arch)"
echo " 线程: $threads"
echo " 算法: $pool_algo"
echo " 矿池: $pool_address"
echo " 钱包: $wallet_address"
uninstall_xxxigcc
add_apt_repository
install_and_start
replace_config
systemctl restart xxxigcc-daemon.service
echo "管理命令:"
echo " systemctl status xxxigcc-daemon"
echo " journalctl -u xxxigcc-daemon -f"
echo " systemctl restart xxxigcc-daemon"
}
main "$@"

342
script/install.sh Normal file
View File

@@ -0,0 +1,342 @@
#!/bin/bash
#
# XXXigCC 安装脚本 - Gitea 版本
# 从 Gitea Generic Package Registry 下载并安装 XXXigCC
#
set -e
declare -r BLUE="\033[0;34m"
declare -r RED="\033[0;31m"
declare -r GREEN="\033[0;32m"
declare -r YELLOW="\033[0;33m"
declare -r RESET="\033[0m"
# 基本配置
INSTALL_DIR="/etc/miner/xxxigcc"
CONFIG_FILE="$INSTALL_DIR/config.json"
LOG_FILE="$INSTALL_DIR/xxxigcc.log"
# Gitea 配置
GITEA_SERVER="gitea.bcde.io"
GITEA_OWNER="wangdefa"
GITEA_REPO="xxxigcc"
PACKAGE_NAME="xxxigcc"
# 默认参数
DEFAULT_VERSION="latest"
DEFAULT_THREADS=0
DEFAULT_POOL_ALGO="rx/0"
DEFAULT_POOL_TLS="false"
DEFAULT_POOL_KEEPALIVE="false"
DEFAULT_POOL_DAEMON="false"
DEFAULT_POOL_SUBMIT_TO_ORIGIN="false"
DEFAULT_POOL_NICEHASH="true"
DEFAULT_ONE_GB_PAGES="false"
DEFAULT_VERBOSE="true"
DEFAULT_CC_ENABLED="false"
DEFAULT_CC_TLS="false"
# 辅助函数
log() { echo -e "${1}${2}${RESET}"; }
error() { log "$RED" "错误: $1"; exit 1; }
get_arch() {
case $(uname -m) in
x86_64) echo "amd64" ;;
aarch64) echo "arm64" ;;
*) error "不支持的架构: $(uname -m)" ;;
esac
}
get_os() {
grep -qi alpine /etc/os-release && echo "alpine" && return
grep -qiE 'debian|ubuntu' /etc/os-release && echo "ubuntu" && return
error "不支持的操作系统"
}
get_gitea_latest_version() {
local version
version=$(curl -s "https://${GITEA_SERVER}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases" | jq -r '.[0].tag_name')
[[ -z "$version" || "$version" == "null" ]] && error "获取版本失败"
echo "$version"
}
# 卸载旧版本
uninstall_xxxigcc() {
if [[ $os_type == "alpine" ]]; then
rc-service xxxigcc stop 2>/dev/null || true
rc-update del xxxigcc default 2>/dev/null || true
rm -rf "$INSTALL_DIR" /etc/init.d/xxxigcc
else
systemctl stop xxxigcc 2>/dev/null || true
systemctl disable xxxigcc 2>/dev/null || true
rm -rf "$INSTALL_DIR" /etc/systemd/system/xxxigcc.service
systemctl daemon-reload 2>/dev/null || true
fi
}
# 安装软件包
install_xxxigcc() {
local temp_dir=$(mktemp -d)
trap "rm -rf '$temp_dir'" EXIT
log "$BLUE" "下载 XXXigCC $version..."
curl -fsSL -o "$temp_dir/xxxigcc.tar.gz" "$download_url" || error "下载失败"
mkdir -p "$INSTALL_DIR"
tar -xzf "$temp_dir/xxxigcc.tar.gz" -C "$INSTALL_DIR" --strip-components=1 || error "解压失败"
chmod +x "$INSTALL_DIR/xxxigDaemon" "$INSTALL_DIR/xxxigMiner"
}
# 配置 CPU 亲和性
configure_cpu_rx() {
local cpu_cores=$(nproc)
local rx_array="" step=1
[[ "$threads" -le $((cpu_cores / 2)) ]] && step=2
for ((i = 0; i < threads; i++)); do
[[ $i -gt 0 ]] && rx_array+=", "
rx_array+="$((i * step))"
done
local field="rx"
[[ "$pool_algo" == "panthera" ]] && field="panthera"
jq ".cpu.$field = [ $rx_array ]" "$CONFIG_FILE" >"$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
}
# 更新配置文件
replace_config() {
[[ ! -f "$CONFIG_FILE" ]] && error "配置文件缺失"
local jq_cmd=".\"log-file\" = \"$LOG_FILE\"
| .\"donate-level\" = 0
| .\"donate-over-proxy\" = 0
| .pools[0].algo = \"$pool_algo\"
| .pools[0].url = \"$pool_address\"
| .pools[0].user = \"$wallet_address\"
| .pools[0].pass = \"$pool_password\"
| .pools[0].tls = $pool_tls
| .pools[0].nicehash = $pool_nicehash
| .\"verbose\" = $verbose"
[[ "$one_gb_pages" == "true" ]] && jq_cmd+=" | .randomx.\"1gb-pages\" = true"
[[ "$pool_keepalive" == "true" ]] && jq_cmd+=" | .pools[0].keepalive = true"
[[ -n "$pool_tls_fingerprint" ]] && jq_cmd+=" | .pools[0].\"tls-fingerprint\" = \"$pool_tls_fingerprint\""
[[ "$pool_daemon" == "true" ]] && jq_cmd+=" | .pools[0].daemon = true"
if [[ "$pool_submit_to_origin" == "true" ]]; then
jq_cmd+=" | .pools[0].\"submit-to-origin\" = true | .pools[0].\"self-select\" = \"$pool_self_select\""
fi
if [[ "$cc_enabled" == "true" ]]; then
jq_cmd+=" | .\"cc-client\".enabled = true
| .\"cc-client\".servers[0].url = \"$cc_url\"
| .\"cc-client\".servers[0].\"access-token\" = \"$cc_token\"
| .\"cc-client\".servers[0].\"use-tls\" = $cc_tls
| .\"cc-client\".\"worker-id\" = \"$cc_work_id\""
else
jq_cmd+=" | .\"cc-client\".enabled = false"
fi
jq "$jq_cmd" "$CONFIG_FILE" >"$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
configure_cpu_rx
}
# 创建并启动服务
create_service() {
if [[ "$os_type" == "alpine" ]]; then
cat >/etc/init.d/xxxigcc <<'EOF'
#!/sbin/openrc-run
name="XXXigCC Miner"
description="XXXigCC Miner Service"
command="/etc/miner/xxxigcc/xxxigDaemon"
command_args="-c /etc/miner/xxxigcc/config.json"
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
rc_ulimit="-n 65535"
depend() {
need net
after network
}
EOF
chmod +x /etc/init.d/xxxigcc
rc-update add xxxigcc default
rc-service xxxigcc start
else
cat >/etc/systemd/system/xxxigcc.service <<EOF
[Unit]
Description=XXXigCC Miner
After=network.target
[Service]
User=root
ExecStart=$INSTALL_DIR/xxxigDaemon -c $CONFIG_FILE
Restart=always
RestartSec=10
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now xxxigcc.service
fi
}
show_usage() {
cat <<EOF
用法: $0 [选项]
选项:
-v, --version <版本> XXXigCC 版本 (默认: $DEFAULT_VERSION)
-t, --threads <数字> 线程数 (默认: 自动)
-a, --algo <算法> 矿池算法 (默认: $DEFAULT_POOL_ALGO)
-o, --pool <地址> 矿池地址 (必需)
-w, --wallet <地址> 钱包地址
-p, --password <密码> 矿池密码 (默认自动生成)
--1gb-pages 启用 1GB 大页
--tls 启用 TLS
--keepalive 启用 KeepAlive
--daemon 启用 SOLO 挖矿
--nicehash 启用 NiceHash 模式 (默认: 启用)
--submit-to-origin 提交到原始矿池
--self-select <地址> 自选矿池地址
--verbose 启用详细输出 (默认: 启用)
--cc 启用 CC
--cc-url <地址> CC 服务器地址
--cc-work-id <ID> CC 工作 ID
--cc-token <令牌> CC 访问令牌
--cc-tls 启用 CC TLS
-h, --help 显示帮助信息
示例:
$0 -o pool.example.com:3333 -w YOUR_WALLET_ADDRESS
EOF
exit 1
}
parse_args() {
version=$DEFAULT_VERSION
threads=$DEFAULT_THREADS
pool_algo=$DEFAULT_POOL_ALGO
pool_tls=$DEFAULT_POOL_TLS
pool_keepalive=$DEFAULT_POOL_KEEPALIVE
pool_submit_to_origin=$DEFAULT_POOL_SUBMIT_TO_ORIGIN
pool_daemon=$DEFAULT_POOL_DAEMON
pool_nicehash=$DEFAULT_POOL_NICEHASH
pool_self_select=""
pool_address=""
wallet_address=""
pool_password=""
pool_tls_fingerprint=""
verbose=$DEFAULT_VERBOSE
cc_enabled=$DEFAULT_CC_ENABLED
cc_url=""
cc_work_id=""
cc_token=""
cc_tls=$DEFAULT_CC_TLS
one_gb_pages=$DEFAULT_ONE_GB_PAGES
while [[ $# -gt 0 ]]; do
case "$1" in
-v | --version) version="$2"; shift 2 ;;
-t | --threads) threads="$2"; shift 2 ;;
-a | --algo) pool_algo="$2"; shift 2 ;;
-o | --pool) pool_address="$2"; shift 2 ;;
-w | --wallet) wallet_address="$2"; shift 2 ;;
-p | --password) pool_password="$2"; shift 2 ;;
--1gb-pages) one_gb_pages="true"; shift ;;
--cc-url) cc_url="$2"; shift 2 ;;
--cc-work-id) cc_work_id="$2"; shift 2 ;;
--cc-token) cc_token="$2"; shift 2 ;;
--tls-fingerprint) pool_tls_fingerprint="$2"; shift 2 ;;
--tls) pool_tls="true"; shift ;;
--keepalive) pool_keepalive="true"; shift ;;
--daemon) pool_daemon="true"; shift ;;
--nicehash) pool_nicehash="true"; shift ;;
--submit-to-origin) pool_submit_to_origin="true"; shift ;;
--self-select) pool_self_select="$2"; shift 2 ;;
--verbose) verbose="true"; shift ;;
--cc) cc_enabled="true"; shift ;;
--cc-tls) cc_tls="true"; shift ;;
-h | --help) show_usage ;;
*) error "无效选项: $1" ;;
esac
done
# 验证必需参数
[[ -z "$pool_address" ]] && error "矿池地址不能为空"
[[ ! "$threads" =~ ^[0-9]+$ ]] && error "无效线程数"
[[ "$pool_submit_to_origin" == "true" && -z "$pool_self_select" ]] && \
error "启用 submit_to_origin 必须设置 self_select"
# 处理默认值
if [[ -z "$pool_password" ]]; then
local ip=$(curl -4s --retry 3 --connect-timeout 10 ifconfig.me 2>/dev/null || echo "0.0.0.0")
local random_str=$(tr -dc '0-9a-zA-Z' </dev/urandom | head -c 5)
pool_password=$(echo "$ip" | awk -F. '{print $3"_"$4}')"_$random_str"
fi
[[ -z "$cc_work_id" ]] && cc_work_id="$(get_arch)_$pool_password"
[[ -z "$wallet_address" ]] && wallet_address="empty_wallet_$(date +%s)"
if [[ "$threads" -le 0 ]]; then
threads=$(nproc)
elif [[ "$threads" -gt $(nproc) ]]; then
threads=$(nproc)
fi
}
main() {
parse_args "$@"
# 检查并安装依赖
local deps=(curl jq file)
if command -v apt-get &>/dev/null; then
for pkg in "${deps[@]}"; do
command -v "$pkg" &>/dev/null || apt-get install -y "$pkg"
done
elif command -v apk &>/dev/null; then
for pkg in "${deps[@]}"; do
command -v "$pkg" &>/dev/null || apk add "$pkg"
done
fi
os_type=$(get_os)
[[ "$version" == "latest" ]] && version=$(get_gitea_latest_version)
download_url="https://${GITEA_SERVER}/api/packages/${GITEA_OWNER}/generic/${PACKAGE_NAME}/${version}/${PACKAGE_NAME}-$(get_arch)-$os_type-$version.tar.gz"
log "$BLUE" "配置信息:"
echo " 版本: $version"
echo " 架构: $(get_arch)"
echo " 系统: $os_type"
echo " 线程: $threads"
echo " 算法: $pool_algo"
echo " 矿池: $pool_address"
echo " 钱包: $wallet_address"
uninstall_xxxigcc
install_xxxigcc
replace_config
create_service
echo "管理命令:"
if [[ "$os_type" == "alpine" ]]; then
echo " rc-service xxxigcc status"
echo " tail -f $LOG_FILE"
echo " rc-service xxxigcc restart"
else
echo " systemctl status xxxigcc"
echo " journalctl -u xxxigcc -f"
echo " systemctl restart xxxigcc"
fi
}
main "$@"

165
script/uninstall.sh Executable file
View File

@@ -0,0 +1,165 @@
#!/bin/bash
#
# XXXigCC 卸载脚本
# 支持 tar.gz 和 DEB 包安装方式
#
set -e
declare -r RED="\033[0;31m"
declare -r GREEN="\033[0;32m"
declare -r YELLOW="\033[0;33m"
declare -r RESET="\033[0m"
# 安装路径配置
INSTALL_DIR_TARBALL="/etc/miner/xxxigcc"
INSTALL_DIR_DEB="/etc/xxxigcc"
LOG_DIR_DEB="/var/log/xxxigcc"
log() { echo -e "${1}${2}${RESET}"; }
error() { log "$RED" "错误: $1"; exit 1; }
get_os() {
grep -qi alpine /etc/os-release && echo "alpine" && return
grep -qiE 'debian|ubuntu' /etc/os-release && echo "ubuntu" && return
error "不支持的操作系统"
}
detect_installation() {
local install_type=""
# 检测 DEB 包安装
if command -v dpkg &>/dev/null && dpkg -l | grep -q "^ii.*xxxigcc"; then
install_type="deb"
# 检测 tar.gz 安装
elif [[ -d "$INSTALL_DIR_TARBALL" ]]; then
install_type="tarball"
# 检测 DEB 配置目录
elif [[ -d "$INSTALL_DIR_DEB" ]]; then
install_type="deb"
fi
echo "$install_type"
}
uninstall_alpine_tarball() {
log "$YELLOW" "卸载 Alpine tar.gz 安装..."
rc-service xxxigcc stop 2>/dev/null || true
rc-update del xxxigcc default 2>/dev/null || true
rm -rf "$INSTALL_DIR_TARBALL" /etc/init.d/xxxigcc
log "$GREEN" "Alpine tar.gz 安装已卸载"
}
uninstall_ubuntu_tarball() {
log "$YELLOW" "卸载 Ubuntu/Debian tar.gz 安装..."
systemctl stop xxxigcc 2>/dev/null || true
systemctl disable xxxigcc 2>/dev/null || true
rm -rf "$INSTALL_DIR_TARBALL" /etc/systemd/system/xxxigcc.service
systemctl daemon-reload 2>/dev/null || true
log "$GREEN" "Ubuntu/Debian tar.gz 安装已卸载"
}
uninstall_deb_package() {
log "$YELLOW" "卸载 DEB 包..."
# 停止并禁用服务
systemctl stop xxxigcc-daemon xxxigcc-server 2>/dev/null || true
systemctl disable xxxigcc-daemon xxxigcc-server 2>/dev/null || true
# 卸载包
apt-get remove -y xxxigcc 2>/dev/null || true
# 清理配置(可选)
if [[ "$PURGE_CONFIG" == "true" ]]; then
apt-get purge -y xxxigcc 2>/dev/null || true
rm -rf "$INSTALL_DIR_DEB" "$LOG_DIR_DEB"
fi
# 清理 APT 源
rm -f /etc/apt/sources.list.d/xxxigcc.list
apt-get update -qq 2>/dev/null || true
systemctl daemon-reload 2>/dev/null || true
log "$GREEN" "DEB 包已卸载"
}
show_usage() {
cat <<EOF
用法: $0 [选项]
选项:
--purge 完全清除配置文件和日志 (仅 DEB 包)
-y, --yes 跳过确认提示
-h, --help 显示帮助信息
示例:
$0 # 交互式卸载
$0 -y # 直接卸载,不确认
$0 --purge -y # 完全清除所有文件
EOF
exit 0
}
main() {
local SKIP_CONFIRM=false
PURGE_CONFIG=false
# 解析参数
while [[ $# -gt 0 ]]; do
case "$1" in
--purge) PURGE_CONFIG=true; shift ;;
-y | --yes) SKIP_CONFIRM=true; shift ;;
-h | --help) show_usage ;;
*) error "无效选项: $1" ;;
esac
done
local os_type=$(get_os)
local install_type=$(detect_installation)
if [[ -z "$install_type" ]]; then
log "$YELLOW" "未检测到 XXXigCC 安装"
exit 0
fi
# 显示检测信息
log "$YELLOW" "检测到的安装方式: $install_type ($os_type)"
# 确认卸载
if [[ "$SKIP_CONFIRM" != "true" ]]; then
echo -n "确认卸载 XXXigCC? (y/N): "
read -r confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
log "$YELLOW" "已取消卸载"
exit 0
fi
fi
# 根据安装类型执行卸载
case "$install_type" in
deb)
uninstall_deb_package
;;
tarball)
if [[ "$os_type" == "alpine" ]]; then
uninstall_alpine_tarball
else
uninstall_ubuntu_tarball
fi
;;
esac
log "$GREEN" "XXXigCC 已成功卸载"
if [[ "$PURGE_CONFIG" != "true" && "$install_type" == "deb" ]]; then
log "$YELLOW" "提示: 使用 '$0 --purge' 可完全清除配置文件"
fi
}
main "$@"

406
templates/BlockTemplate.cpp Normal file
View File

@@ -0,0 +1,406 @@
/* XMRig
* Copyright (c) 2012-2013 The Cryptonote developers
* Copyright (c) 2014-2021 The Monero Project
* Copyright (c) 2018-2023 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2023 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base/tools/cryptonote/BlockTemplate.h"
#include "3rdparty/rapidjson/document.h"
#include "base/crypto/keccak.h"
#include "base/tools/cryptonote/BlobReader.h"
#include "base/tools/Cvt.h"
void xmrig::BlockTemplate::calculateMinerTxHash(const uint8_t *prefix_begin, const uint8_t *prefix_end, uint8_t *hash)
{
uint8_t hashes[kHashSize * 3];
// Calculate 3 partial hashes
// 1. Prefix
keccak(prefix_begin, static_cast<int>(prefix_end - prefix_begin), hashes, kHashSize);
// 2. Base RCT, single 0 byte in miner tx
static const uint8_t known_second_hash[kHashSize] = {
188,54,120,158,122,30,40,20,54,70,66,41,130,143,129,125,102,18,247,180,119,214,101,145,255,150,169,224,100,188,201,138
};
memcpy(hashes + kHashSize, known_second_hash, kHashSize);
// 3. Prunable RCT, empty in miner tx
memset(hashes + kHashSize * 2, 0, kHashSize);
// Calculate miner transaction hash
keccak(hashes, sizeof(hashes), hash, kHashSize);
}
void xmrig::BlockTemplate::calculateRootHash(const uint8_t *prefix_begin, const uint8_t *prefix_end, const Buffer &miner_tx_merkle_tree_branch, uint8_t *root_hash)
{
calculateMinerTxHash(prefix_begin, prefix_end, root_hash);
for (size_t i = 0; i < miner_tx_merkle_tree_branch.size(); i += kHashSize) {
uint8_t h[kHashSize * 2];
memcpy(h, root_hash, kHashSize);
memcpy(h + kHashSize, miner_tx_merkle_tree_branch.data() + i, kHashSize);
keccak(h, kHashSize * 2, root_hash, kHashSize);
}
}
void xmrig::BlockTemplate::calculateMerkleTreeHash()
{
m_minerTxMerkleTreeBranch.clear();
const uint64_t count = m_numHashes + 1;
const uint8_t *h = m_hashes.data();
if (count == 1) {
memcpy(m_rootHash, h, kHashSize);
}
else if (count == 2) {
m_minerTxMerkleTreeBranch.insert(m_minerTxMerkleTreeBranch.end(), h + kHashSize, h + kHashSize * 2);
keccak(h, kHashSize * 2, m_rootHash, kHashSize);
}
else {
size_t i = 0;
size_t j = 0;
size_t cnt = 0;
for (i = 0, cnt = 1; cnt <= count; ++i, cnt <<= 1) {}
cnt >>= 1;
m_minerTxMerkleTreeBranch.reserve(kHashSize * (i - 1));
Buffer ints(cnt * kHashSize);
memcpy(ints.data(), h, (cnt * 2 - count) * kHashSize);
for (i = cnt * 2 - count, j = cnt * 2 - count; j < cnt; i += 2, ++j) {
if (i == 0) {
m_minerTxMerkleTreeBranch.insert(m_minerTxMerkleTreeBranch.end(), h + kHashSize, h + kHashSize * 2);
}
keccak(h + i * kHashSize, kHashSize * 2, ints.data() + j * kHashSize, kHashSize);
}
while (cnt > 2) {
cnt >>= 1;
for (i = 0, j = 0; j < cnt; i += 2, ++j) {
if (i == 0) {
m_minerTxMerkleTreeBranch.insert(m_minerTxMerkleTreeBranch.end(), ints.data() + kHashSize, ints.data() + kHashSize * 2);
}
keccak(ints.data() + i * kHashSize, kHashSize * 2, ints.data() + j * kHashSize, kHashSize);
}
}
m_minerTxMerkleTreeBranch.insert(m_minerTxMerkleTreeBranch.end(), ints.data() + kHashSize, ints.data() + kHashSize * 2);
keccak(ints.data(), kHashSize * 2, m_rootHash, kHashSize);
}
}
bool xmrig::BlockTemplate::parse(const Buffer &blocktemplate, const Coin &coin, bool hashes)
{
if (blocktemplate.size() < kMinSize) {
return false;
}
m_blob = blocktemplate;
m_coin = coin;
bool rc = false;
try {
rc = parse(hashes);
} catch (...) {}
return rc;
}
bool xmrig::BlockTemplate::parse(const char *blocktemplate, size_t size, const Coin &coin, bool hashes)
{
if (size < (kMinSize * 2) || !Cvt::fromHex(m_blob, blocktemplate, size)) {
return false;
}
m_coin = coin;
bool rc = false;
try {
rc = parse(hashes);
} catch (...) {}
return rc;
}
bool xmrig::BlockTemplate::parse(const rapidjson::Value &blocktemplate, const Coin &coin, bool hashes)
{
return blocktemplate.IsString() && parse(blocktemplate.GetString(), blocktemplate.GetStringLength(), coin, hashes);
}
bool xmrig::BlockTemplate::parse(const String &blocktemplate, const Coin &coin, bool hashes)
{
return parse(blocktemplate.data(), blocktemplate.size(), coin, hashes);
}
void xmrig::BlockTemplate::generateHashingBlob(Buffer &out) const
{
out.clear();
out.reserve(offset(MINER_TX_PREFIX_OFFSET) + kHashSize + 3);
out.assign(m_blob.begin(), m_blob.begin() + offset(MINER_TX_PREFIX_OFFSET));
out.insert(out.end(), m_rootHash, m_rootHash + kHashSize);
uint64_t k = m_numHashes + 1;
while (k >= 0x80) {
out.emplace_back((static_cast<uint8_t>(k) & 0x7F) | 0x80);
k >>= 7;
}
out.emplace_back(static_cast<uint8_t>(k));
}
bool xmrig::BlockTemplate::parse(bool hashes)
{
// Detect Tari solo mining format (76 bytes)
// Format: 3 bytes header + 32 bytes mining_hash + 8 bytes nonce + 33 bytes pow
if (m_blob.size() == 76) {
// Tari solo mining format - use fixed-size parsing (no varint)
BlobReader<false> ar(m_blob.data(), m_blob.size());
// Skip 3-byte header (major_version, minor_version, timestamp - all 0 for Tari)
ar.skip(3);
// Skip 32-byte mining_hash
ar.skip(32);
// Nonce is at offset 35 (3 + 32)
setOffset(NONCE_OFFSET, 35);
ar.skip(8); // Skip nonce (8 bytes, big-endian)
// Skip 33-byte PoW data
ar.skip(33);
// For Tari, we don't need to parse miner tx or other Monero-specific fields
// Just accept the template and let XMRig modify the nonce
return true;
}
// Original Monero varint parsing for non-Tari formats
BlobReader<true> ar(m_blob.data(), m_blob.size());
// Block header
ar(m_version.first);
ar(m_version.second);
ar(m_timestamp);
ar(m_prevId, kHashSize);
setOffset(NONCE_OFFSET, ar.index());
ar.skip(kNonceSize);
// Wownero block template has miner signature starting from version 18
if (m_coin == Coin::WOWNERO && majorVersion() >= 18) {
ar(m_minerSignature, kSignatureSize);
ar(m_vote);
}
if (m_coin == Coin::ZEPHYR) {
uint8_t pricing_record[120];
ar(pricing_record);
}
// Miner transaction begin
// Prefix begin
setOffset(MINER_TX_PREFIX_OFFSET, ar.index());
ar(m_txVersion);
if (m_coin != Coin::TOWNFORGE) {
ar(m_unlockTime);
}
ar(m_numInputs);
// must be 1 input
if (m_numInputs != 1) {
return false;
}
ar(m_inputType);
// input type must be txin_gen (0xFF)
if (m_inputType != 0xFF) {
return false;
}
ar(m_height);
ar(m_numOutputs);
if (m_coin == Coin::ZEPHYR) {
if (m_numOutputs < 2) {
return false;
}
}
else if (m_numOutputs != 1) {
return false;
}
ar(m_amount);
ar(m_outputType);
// output type must be txout_to_key (2) or txout_to_tagged_key (3)
if ((m_outputType != 2) && (m_outputType != 3)) {
return false;
}
setOffset(EPH_PUBLIC_KEY_OFFSET, ar.index());
ar(m_ephPublicKey, kKeySize);
if (m_coin == Coin::ZEPHYR) {
if (m_outputType != 2) {
return false;
}
uint64_t asset_type_len;
ar(asset_type_len);
ar.skip(asset_type_len);
ar(m_viewTag);
for (uint64_t k = 1; k < m_numOutputs; ++k) {
uint64_t amount2;
ar(amount2);
uint8_t output_type2;
ar(output_type2);
if (output_type2 != 2) {
return false;
}
Span key2;
ar(key2, kKeySize);
ar(asset_type_len);
ar.skip(asset_type_len);
uint8_t view_tag2;
ar(view_tag2);
}
}
else if (m_outputType == 3) {
ar(m_viewTag);
}
if (m_coin == Coin::TOWNFORGE) {
ar(m_unlockTime);
}
ar(m_extraSize);
setOffset(TX_EXTRA_OFFSET, ar.index());
BlobReader<true> ar_extra(blob(TX_EXTRA_OFFSET), m_extraSize);
ar.skip(m_extraSize);
bool pubkey_offset_first = true;
while (ar_extra.index() < m_extraSize) {
uint64_t extra_tag = 0;
uint64_t size = 0;
ar_extra(extra_tag);
switch (extra_tag) {
case 0x01: // TX_EXTRA_TAG_PUBKEY
if (pubkey_offset_first) {
pubkey_offset_first = false;
setOffset(TX_PUBKEY_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index());
}
ar_extra.skip(kKeySize);
break;
case 0x02: // TX_EXTRA_NONCE
ar_extra(size);
setOffset(TX_EXTRA_NONCE_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index());
ar_extra(m_txExtraNonce, size);
break;
case 0x03: // TX_EXTRA_MERGE_MINING_TAG
ar_extra(size);
setOffset(TX_EXTRA_MERGE_MINING_TAG_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index());
ar_extra(m_txMergeMiningTag, size);
break;
default:
return false; // TODO(SChernykh): handle other tags
}
}
if (m_coin == Coin::ZEPHYR) {
uint64_t pricing_record_height, amount_burnt, amount_minted;
ar(pricing_record_height);
ar(amount_burnt);
ar(amount_minted);
}
setOffset(MINER_TX_PREFIX_END_OFFSET, ar.index());
// Prefix end
// RCT signatures (empty in miner transaction)
uint8_t vin_rct_type = 0;
ar(vin_rct_type);
// no way I'm parsing a full game update here
if (m_coin == Coin::TOWNFORGE && m_height % 720 == 0) {
return true;
}
// must be RCTTypeNull (0)
if (vin_rct_type != 0) {
return false;
}
const size_t miner_tx_end = ar.index();
// Miner transaction end
// Miner transaction must have exactly 1 byte with value 0 after the prefix
if ((miner_tx_end != offset(MINER_TX_PREFIX_END_OFFSET) + 1) || (*blob(MINER_TX_PREFIX_END_OFFSET) != 0)) {
return false;
}
// Other transaction hashes
ar(m_numHashes);
if (hashes) {
m_hashes.resize((m_numHashes + 1) * kHashSize);
calculateMinerTxHash(blob(MINER_TX_PREFIX_OFFSET), blob(MINER_TX_PREFIX_END_OFFSET), m_hashes.data());
for (uint64_t i = 1; i <= m_numHashes; ++i) {
Span h;
ar(h, kHashSize);
memcpy(m_hashes.data() + i * kHashSize, h.data(), kHashSize);
}
calculateMerkleTreeHash();
}
return true;
}