Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 782d9e05bb | |||
| 5545b76e0b | |||
| 9142021f26 | |||
| 8100b2f2e5 | |||
| 877ba3d3bb | |||
| 47c0c4de32 |
@@ -9,7 +9,7 @@ on:
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
PRODUCT_NAME: "xxxigcc"
|
||||
PACKAGE_VERSION: "3.4.6-xg1"
|
||||
PACKAGE_VERSION: "3.4.6-xg2"
|
||||
BUILDX_NO_DEFAULT_ATTESTATIONS: "1"
|
||||
|
||||
jobs:
|
||||
@@ -70,85 +70,28 @@ jobs:
|
||||
test/xxxigDaemon --version 2>/dev/null || echo "⚠️ 跳过版本检查"
|
||||
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
|
||||
with:
|
||||
name: binaries-${{ matrix.arch }}-${{ matrix.distro }}
|
||||
path: "*.tar.gz"
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.deb
|
||||
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:
|
||||
runs-on: ubuntu-latest-amd64
|
||||
needs: build-and-test
|
||||
@@ -164,47 +107,115 @@ jobs:
|
||||
env:
|
||||
TOKEN: ${{ secrets.BUILD_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
REGISTRY: ${{ gitea.server_url }}
|
||||
OWNER: ${{ gitea.repository_owner }}
|
||||
REPO: ${{ gitea.repository }}
|
||||
run: |
|
||||
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 " Registry: ${REGISTRY}"
|
||||
echo " Owner: ${OWNER}"
|
||||
echo " Package: ${PRODUCT_NAME}"
|
||||
echo " Version: ${TAG}"
|
||||
|
||||
# 上传所有 tar.gz 包到 Generic Package Registry
|
||||
for file in *.tar.gz; do
|
||||
[ ! -f "$file" ] && continue
|
||||
echo " ⬆️ $file"
|
||||
curl -fsSL -X POST \
|
||||
curl -fsSL -X PUT \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
-F "file=@$file" \
|
||||
"${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/$file" || {
|
||||
--upload-file "$file" \
|
||||
"https://${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/$file" || {
|
||||
echo "❌ 上传失败: $file"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
# 生成 Release 描述
|
||||
echo "📝 生成 Release 描述..."
|
||||
BODY="## Release ${TAG}\n\n### 📥 下载链接\n"
|
||||
for file in *.tar.gz; do
|
||||
[ -f "$file" ] && BODY="${BODY}- [${file}](${REGISTRY}/api/packages/${OWNER}/generic/${PRODUCT_NAME}/${TAG}/${file})\n"
|
||||
|
||||
# 上传 Debian 包到 Debian Package Registry (支持多个发行版)
|
||||
echo ""
|
||||
echo "📦 上传 Debian 包到 Debian Package Registry..."
|
||||
for file in *.deb; do
|
||||
[ ! -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
|
||||
|
||||
|
||||
# 生成 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
|
||||
echo ""
|
||||
echo "🎉 创建 Release..."
|
||||
curl -fsSL -X POST \
|
||||
RESPONSE=$(curl -fsSL -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${REGISTRY}/api/v1/repos/${REPO}/releases" \
|
||||
-d @- << EOF || echo "⚠️ Release 可能已存在"
|
||||
{
|
||||
"tag_name": "${TAG}",
|
||||
"name": "Release ${TAG}",
|
||||
"body": "${BODY}",
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}
|
||||
EOF
|
||||
"https://${REGISTRY}/api/v1/repos/${{ gitea.repository }}/releases" \
|
||||
-d "${RELEASE_DATA}")
|
||||
|
||||
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
|
||||
183
README.md
Normal file
183
README.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# XXXigCC
|
||||
|
||||
> 禁用捐赠功能的 XMRigCC 修改版本。
|
||||
|
||||
[](LICENSE)
|
||||
[](.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
|
||||
# 使用 trixie 替换上述命令中的 bookworm
|
||||
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
|
||||
```
|
||||
|
||||
### 方式二:通用二进制包
|
||||
|
||||
```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
91
debian/build-deb.sh
vendored
Executable 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
18
debian/control.template
vendored
Normal 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
82
debian/postinst
vendored
Executable 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
30
debian/postrm
vendored
Executable 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
17
debian/prerm
vendored
Executable 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
38
debian/xxxigcc-daemon.service
vendored
Normal 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
38
debian/xxxigcc-server.service
vendored
Normal 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
|
||||
@@ -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"]
|
||||
@@ -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"]
|
||||
@@ -33,6 +33,9 @@ RUN git clone --recursive https://github.com/Bendr0id/xmrigCC.git && \
|
||||
|
||||
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
|
||||
|
||||
# 根据目标架构优化编译
|
||||
|
||||
@@ -37,6 +37,9 @@ RUN git clone --recursive https://github.com/Bendr0id/xmrigCC.git && \
|
||||
|
||||
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
|
||||
|
||||
# 根据目标架构设置编译环境和参数
|
||||
|
||||
406
templates/BlockTemplate.cpp
Normal file
406
templates/BlockTemplate.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user