create git

This commit is contained in:
lzx 2025-09-03 16:00:42 +08:00
commit 953a76439a
55 changed files with 29879 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
rel
config
*.json
*.conf
/*.go

146
README.md Normal file
View File

@ -0,0 +1,146 @@
# tari-server
一个基于 Go 的轻量化挖矿池服务内核,包含 Job 生成/分发与 Stratum 矿工端接入两大模块:
- gbt区块模板生成与同步GetBlockTemplate/Job Producer通过 ZMQ 向服务端发布新任务
- serverStratum 挖矿服务(矿工接入、难度调整、提交校验、统计与缓存)
当前代码启用了 `sha3x` 币种实现(其他如 `nexa`、`monero` 的代码结构已准备但默认关闭/注释)。
---
## 功能特性
- Stratum 协议接入,支持 `mining.subscribe`、`mining.authorize`/`login`、`mining.submit`、`mining.ping/pong`
- 可配置的难度策略(含卡尔曼滤波驱动的 VarDiff 逻辑,按提交间隔动态调整)
- 任务分发与同步gbt 通过 ZMQ 发布server 订阅并向在线矿工广播
- 连接数/同 IP 限流、存活监测、超时与心跳处理
- Redis 用于在线状态与速率缓存DB 持久化矿工/用户/池端统计
- 日志zap + 日志轮转
- 内置 pprof 端口(从配置读取)
---
## 目录结构
```
cmd/
gbt/gbt.go # 区块模板生成/任务发布入口
server/server.go # 挖矿池服务入口Stratum 服务)
internal/
server/ # 矿工接入、会话、难度、任务处理
gbt/ # GBT/任务管线,各币种对接
db/ # 数据库上下文与表结构
cache/ # Redis 缓存读写
stratum/ # Stratum 协议与消息结构
utility/ # 工具、日志、ZMQ 初始化等
config/
nexa/
server/server.conf # server 示例配置(按需拷贝/修改)
gbt/gbt.conf # gbt 示例配置(按需拷贝/修改)
db/db.conf # DB 配置MySQL/SQLite
```
---
## 环境依赖
- Go 1.23+go.mod 声明 `toolchain go1.23.1`
- Redis作为状态/速率缓存)
- 数据库MySQL 或 SQLite`config/<coin>/db/db.conf` 配置)
- ZMQ用于 gbt → server 的 Job 发布/订阅)
- 可选本地 C 库:目录 `internal/server/lib/` 下包含部分 `.so`/`.a`,用于特定算法;`sha3x` 默认主要为 Go 实现。建议在 Linux 环境下构建、运行Windows 可能需要适配或禁用相关 C 扩展。
---
## 快速开始
1) 准备配置文件(以 `sha3x` 为例)
- 将以下文件拷贝到运行目录(项目根或二进制同目录):
- `config/nexa/server/server.conf``server.conf`
- `config/nexa/gbt/gbt.conf``gbt.conf`
- `config/nexa/db/db.conf``db.conf`
- 打开并修改以上配置以匹配你的 Redis、DB、ZMQ 与监听地址。例如:`server.conf` 中的 Stratum 监听端口、pprof 端口,`gbt.conf` 中的上游节点与发布地址。
2) 构建
```
# 在项目根目录执行
go build -o bin/server ./cmd/server
go build -o bin/gbt ./cmd/gbt
```
3) 运行
```
# 先启动 gbt负责产生并发布 Job
./bin/gbt
# 再启动 server负责矿工接入与提交校验
./bin/server
```
- 两个进程均会在工作目录读取同名配置:`gbt` 读取 `gbt.conf``server` 读取 `server.conf`
- `server` 会根据配置启动一个 pprof HTTP 端口,便于性能分析。
4) 矿工连接
- 在矿工端配置你的 Stratum 地址,即 `server.conf` 中的 `Host.Listen`(例如:`stratum+tcp://<ip>:<port>`)。
- 账户名与 Miner 名按池的约定填写,对应鉴权在 `internal/stratum``internal/server/coin/*` 中处理。
---
## 配置说明(概览)
- server.conf读取于工作目录
- Host.ListenStratum 监听地址,形如 `0.0.0.0:端口`
- Redis`Addr/Password/DB`
- ZMQ`Pub`(向外发布)、`Sub`(订阅 gbt 发布的 Job
- Diff难度相关参数起始、最小/最大、调整间隔、滤波模式等)
- Zaplog/Logrotate日志级别、输出与轮转策略
- pprof 端口:由 `cmd/server``utility.GetCoin("server.conf")` 返回的第二个值决定
- gbt.conf读取于工作目录
- 上游节点/RPC 或 gRPC/GRPC/Tari/Monero 等对接参数
- ZMQ对外发布 Job 的地址(需与 server 的 `Zmq.Sub` 对应)
- db.conf
- MySQL 或 SQLite 连接信息(`internal/db` 负责加载与建表)
注意:项目内示例配置位于 `config/nexa/...`,请根据目标币种复制调整;`sha3x` 仅需要确保 ZMQ/Redis/DB 与监听端口正常。
---
## 运行时行为要点
- gbt → server通过 ZMQ 发布/订阅通道传递新 Job`server` 收到后同步标志并向矿工广播
- 存活与心跳:`server` 为连接设置超时、心跳ping/pong并清理无效连接
- 动态难度:根据提交间隔、方差与配置策略更新矿工难度
- 速率与统计:接受/拒绝、哈希率、区块、孤块等统计通过内存与 Redis/DB 维护
- 退出流程:`Stop()` 会清理连接、关闭 ZMQ、Redis、日志并回收内存结构
---
## 常见问题
- 端口不通:确认 `server.conf` 中监听端口开放(防火墙/安全组ZMQ 地址能互通
- 配置找不到:`server` 与 `gbt` 均在工作目录读取 `*.conf`,请确保以正确的工作目录启动或将配置拷贝到同一目录
- 构建失败Windows如遇 `.so/.a` 相关链接问题,建议在 Linux 构建或禁用/移除对应 C 扩展;`sha3x` 模块通常不依赖这些库
- Redis/DB 未就绪:请先启动并配置正确连接串;否则启动会失败或无法持久化统计
---
## 开发与调试
- 使用 pprof根据 `server.conf` 暴露的地址访问 `http://<ip>:<pprof_port>/debug/pprof/`
- 日志:默认使用 zap`Zaplog``Logrotate` 配置输出与轮转
- 关键位置:
- `internal/server/server.go`连接处理、心跳、难度调整、Job 处理主流程
- `internal/gbt/*`:各币种 GBT 接入与 Job 生成
- `internal/stratum/*`:协议与消息体
---
## 构建与运行示例Windows PowerShell
```
# 构建
$env:CGO_ENABLED=0
go build -o bin/server.exe ./cmd/server
go build -o bin/gbt.exe ./cmd/gbt
# 运行前将 *.conf 复制到当前目录
./bin/gbt.exe
./bin/server.exe
```
> 注:如需使用依赖本地 C 库的算法实现,建议在 Linux 环境构建并确保工具链与库依赖可用。
---
## 许可证
本项目未在仓库根目录明确声明许可证。如需开源发布,请在根目录新增 LICENSE 并注明授权条款。

33
cmd/gbt/gbt.go Normal file
View File

@ -0,0 +1,33 @@
// gbt.go
package main
import (
"os"
"pool/internal/db"
"pool/internal/gbt"
"pool/internal/utility"
)
func start(coin string, DbCtx *db.DbContext) {
gbt.Start(coin, DbCtx)
}
func stop(coin string) {
gbt.Stop(coin)
}
func main() {
coin, _ := utility.GetCoin("gbt.conf")
dbctx := db.InitDb(coin, "gbt")
start(coin, dbctx)
stop(coin)
db.StopDb(coin, "gbt")
os.Exit(0)
}

41
cmd/server/server.go Normal file
View File

@ -0,0 +1,41 @@
// server.go
package main
import (
"os"
"pool/internal/db"
"pool/internal/server"
"log"
"net/http"
_ "net/http/pprof"
"pool/internal/utility"
)
func start(coin string, DbCtx *db.DbContext) {
server.Start(coin, DbCtx)
}
func stop() {
server.Stop()
}
func main() {
coin, pp := utility.GetCoin("server.conf")
go func() {
//log.Println(http.ListenAndServe("localhost:6060", nil))
log.Println(http.ListenAndServe(pp, nil))
}()
dbctx := db.InitDb(coin, "server")
start(coin, dbctx)
stop()
db.StopDb(coin, "server")
os.Exit(0)
}

46
go.mod Normal file
View File

@ -0,0 +1,46 @@
module pool
go 1.23.0
toolchain go1.23.1
require (
github.com/btcsuite/btcd v0.24.2
github.com/golang/protobuf v1.5.4
github.com/zeromq/goczmq v4.1.0+incompatible
go.uber.org/zap v1.27.0
google.golang.org/protobuf v1.36.6
)
require (
golang.org/x/net v0.41.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
github.com/btcsuite/btcd/btcutil v1.1.5 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-sql-driver/mysql v1.8.1
github.com/google/uuid v1.6.0
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.22
github.com/redis/go-redis/v9 v9.5.4
github.com/rs/zerolog v1.33.0
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/sys v0.33.0
google.golang.org/grpc v1.75.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)

194
go.sum Normal file
View File

@ -0,0 +1,194 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY=
github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg=
github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=
github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=
github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8=
github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/chaincfg/chainhash v1.0.4 h1:zRCv6tdncLfLTKYqu7hrXvs7hW+8FO/NvwoFvGsrluU=
github.com/decred/dcrd/chaincfg/chainhash v1.0.4/go.mod h1:hA86XxlBWwHivMvxzXTSD0ZCG/LoYsFdWnCekkTMCqY=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.5.4 h1:vOFYDKKVgrI5u++QvnMT7DksSMYg7Aw/Np4vLJLKLwY=
github.com/redis/go-redis/v9 v9.5.4/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/zeromq/goczmq v4.1.0+incompatible h1:cGVQaU6kIwwrGso0Pgbl84tzAz/h7FJ3wYQjSonjFFc=
github.com/zeromq/goczmq v4.1.0+incompatible/go.mod h1:1uZybAJoSRCvZMH2rZxEwWBSmC4T7CB/xQOfChwPEzg=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

548
internal/cache/cache.go vendored Normal file
View File

@ -0,0 +1,548 @@
// cache.go
package cache
import (
"context"
"encoding/json"
"log"
"strconv"
"time"
"github.com/redis/go-redis/v9"
)
// reference, do not delete that
/*type CacheServer struct {
Submits int64 `json:"submits"`
Blocks int64 `json:"blocks"`
Accepts float64 `json:"accepts"`
Rejects int64 `json:"rejects"`
Shares int64 `json:"shares"`
Rewards float64 `json:"reward"`
Fees float64 `json:"fee"`
RefDiff float64 `json:"refdiff"`
//LastSubmit int64 `json:"lastsubmit"`
}
type CacheUser struct {
Submits int64 `json:"submits"`
Blocks int64 `json:"blocks"`
Accepts float64 `json:"accepts"`
Rejects int64 `json:"rejects"`
Shares int64 `json:"shares"`
Rewards float64 `json:"reward"`
Fees float64 `json:"fee"`
User string `json:"user"`
}
type CacheMhs struct {
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
Accepts []CacheMhsItem `json:"accepts"`
Rejects []CacheMhsItem `json:"rejects"`
StartDayTime string `json:"startday"`
}
type CacheMiner struct {
Submits int64 `json:"submits"`
Blocks int64 `json:"blocks"`
Accepts float64 `json:"accepts"`
Rejects int64 `json:"rejects"`
Shares int64 `json:"shares"`
LastDiff float64 `json:"diff"`
Rewards float64 `json:"reward"`
Fees float64 `json:"fee"`
Retry int `json:"retry"`
LastSubmit int64 `json:"lastsubmit"`
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
ErrStaleds int64 `json:"staleds"`
ErrLowDiffs int64 `json:"lowdiffs"`
ErrDuplicates int64 `json:"duplicates"`
ErrFormats int64 `json:"formats"`
ErrOthers int64 `json:"others"`
}*/
// need used
type CacheMhsItem struct {
Tt string `json:"Tt"`
Diff float64 `json:"diff"`
}
/*
type CacheMinerItem struct {
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
}*/
func LoadIntCache(client *redis.Client, key_int string) int64 {
val, err := client.Get(context.Background(), key_int).Result()
if err != nil {
log.Printf("[LoadIntCache]Error retrieving data from Redis: %s, %v\n", key_int, err)
return 0
}
val_int, err := strconv.ParseInt(val, 10, 64)
if err != nil {
log.Printf("[LoadIntCache]Error parsing integer from string: %v\n", err)
return 0
}
return val_int
}
func StoreIntCache(client *redis.Client, key string, intNumber int64) bool {
numberStr := strconv.FormatInt(intNumber, 10)
expiration := 1 * 24 * time.Hour
err := client.Set(context.Background(), key, numberStr, expiration).Err()
if err != nil {
log.Printf("[StoreIntCache]Error storing data in Redis: %s, %v\n", key, err)
return false
}
return true
}
func LoadFloatCache(client *redis.Client, key_float string) float64 {
val, err := client.Get(context.Background(), key_float).Result()
if err != nil {
log.Printf("[LoadFloatCache]Error retrieving data from Redis: %s, %v\n", key_float, err)
return 0
}
val_f, err := strconv.ParseFloat(val, 64)
if err != nil {
log.Printf("[LoadFloatCache]Error parsing float from string: %v\n", err)
return 0
}
return val_f
}
func StoreFloatCache(client *redis.Client, key string, floatNumber float64) bool {
numberStr := strconv.FormatFloat(floatNumber, 'f', -1, 64)
expiration := 1 * 24 * time.Hour
err := client.Set(context.Background(), key, numberStr, expiration).Err()
if err != nil {
log.Printf("[StoreFloatCache]Error storing data in Redis: %s, %v\n", key, err)
return false
}
return true
}
func LoadStringCache(client *redis.Client, keyStr string) string {
val, err := client.Get(context.Background(), keyStr).Result()
if err != nil {
log.Printf("[LoadStringCache]Error retrieving data from Redis: %s, %v\n", keyStr, err)
return ""
}
return val
}
func StoreStringCache(client *redis.Client, key string, strValue string) bool {
expiration := 1 * 24 * time.Hour
err := client.Set(context.Background(), key, strValue, expiration).Err()
if err != nil {
log.Printf("[StoreStringCache]Error storing data in Redis: %s, %v\n", key, err)
return false
}
return true
}
func LoadTimeCache(client *redis.Client, keyTime string) (time.Time, bool) {
val, err := client.Get(context.Background(), keyTime).Result()
if err != nil {
log.Printf("[LoadTimeCache]Error retrieving data from Redis: %s, %v\n", keyTime, err)
return time.Time{}, false
}
t, err := time.Parse(time.RFC3339, val)
if err != nil {
log.Printf("[LoadTimeCache]Error parsing time from string: %v\n", err)
return time.Time{}, false
}
return t, true
}
func StoreTimeCache(client *redis.Client, key string, timeValue time.Time) bool {
numberStr := timeValue.Format(time.RFC3339)
expiration := 1 * 24 * time.Hour
err := client.Set(context.Background(), key, numberStr, expiration).Err()
if err != nil {
log.Printf("[StoreTimeCache]Error storing data in Redis: %s, %v\n", key, err)
return false
}
return true
}
func LoadPoolCache(client *redis.Client, coin string, pool_key string) interface{} {
k := "pool_" + coin + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects":
return LoadIntCache(client, k)
case "accepts", "rewards", "fee", "refdiff":
return LoadFloatCache(client, k)
default:
log.Printf("[LoadPoolCache]Unknown pool_key: %s\n", pool_key)
return nil
}
}
func StorePoolCache(client *redis.Client, coin string, pool_key string, val interface{}) bool {
k := "pool_" + coin + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects":
if pool_key == "rejects" {
if intVal, ok := val.(float64); ok {
return StoreIntCache(client, k, int64(intVal))
}
} else {
if intVal, ok := val.(int64); ok {
return StoreIntCache(client, k, intVal)
}
}
log.Printf("[StorePoolCache]Invalid type for key %s: expected int64, got %T\n", pool_key, val)
return false
case "accepts", "rewards", "fee", "refdiff":
if floatVal, ok := val.(float64); ok {
return StoreFloatCache(client, k, floatVal)
}
log.Printf("[StorePoolCache]Invalid type for key %s: expected float64, got %T\n", pool_key, val)
return false
default:
log.Printf("[StorePoolCache]Unknown pool_key: %s\n", pool_key)
return false
}
}
/*
func LoadUserCache(client *redis.Client, coin string, user string, pool_key string) interface{} {
k := "pool_" + coin + "_" + user + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects":
return LoadIntCache(client, k)
case "accepts", "rewards", "fee":
return LoadFloatCache(client, k)
default:
log.Printf("Unknown pool_key: %s\n", pool_key)
return nil
}
}
func StoreUserCache(client *redis.Client, coin string, user string, pool_key string, val interface{}) bool {
k := "pool_" + coin + "_" + user + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects":
if intVal, ok := val.(int64); ok {
return StoreIntCache(client, k, intVal)
}
log.Printf("Invalid type for key %s: expected int64, got %T\n", pool_key, val)
return false
case "accepts", "rewards", "fee":
if floatVal, ok := val.(float64); ok {
return StoreFloatCache(client, k, floatVal)
}
log.Printf("Invalid type for key %s: expected float64, got %T\n", pool_key, val)
return false
default:
log.Printf("Unknown pool_key: %s\n", pool_key)
return false
}
}*/
func LoadMinerCache(client *redis.Client, coin string, user string, miner string, index string, pool_key string) interface{} {
k := "pool_" + coin + "_" + user + "_" + miner + "_" + index + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects", "retry", "staleds", "lowdiffs", "duplicates", "formats", "others":
return LoadIntCache(client, k)
case "accepts", "rewards", "fee", "diff":
return LoadFloatCache(client, k)
case "lastsubmit", "startsubmit":
tT, ok := LoadTimeCache(client, k)
if ok {
return tT
}
return nil
default:
log.Printf("[LoadMinerCache]Unknown pool_key: %s\n", pool_key)
return nil
}
}
func StoreMinerCache(client *redis.Client, coin string, user string, miner string, index string, pool_key string, val interface{}) bool {
k := "pool_" + coin + "_" + user + "_" + miner + "_" + index + "_" + pool_key
switch pool_key {
case "submits", "blocks", "rejects", "retry", "staleds", "lowdiffs", "duplicates", "formats", "others":
if intVal, ok := val.(int64); ok {
return StoreIntCache(client, k, intVal)
}
log.Printf("[StoreMinerCache]Invalid type for %s: expected int64, got %T\n", pool_key, val)
return false
case "accepts", "rewards", "fee", "diff":
if floatVal, ok := val.(float64); ok {
return StoreFloatCache(client, k, floatVal)
}
log.Printf("[StoreMinerCache]Invalid type for %s: expected float64, got %T\n", pool_key, val)
return false
case "lastsubmit", "startsubmit":
if timeVal, ok := val.(time.Time); ok {
return StoreTimeCache(client, k, timeVal)
}
log.Printf("[StoreMinerCache]Invalid type for %s: expected time.Time, got %T\n", pool_key, val)
return false
default:
log.Printf("[StoreMinerCache]Unknown pool_key: %s\n", pool_key)
return false
}
}
func StoreCacheMhsItem(client *redis.Client, key string, item CacheMhsItem) bool {
data, err := json.Marshal(item)
if err != nil {
log.Printf("[StoreCacheMhsItem]Error marshalling CacheMhsItem to JSON: %v\n", err)
return false
}
err = client.RPush(context.Background(), key, data).Err()
if err != nil {
log.Printf("[StoreCacheMhsItem]Error pushing data to Redis list: %v\n", err)
return false
}
expiration := 1 * 24 * time.Hour
err = client.Expire(context.Background(), key, expiration).Err()
if err != nil {
log.Printf("[StoreCacheMhsItem] Error setting expiration for Redis key: %v\n", err)
return false
}
return true
}
func PopCacheMhsItem(client *redis.Client, key string) (*CacheMhsItem, bool) {
data, err := client.LPop(context.Background(), key).Result()
if err != nil {
log.Printf("[PopCacheMhsItem]Error retrieving data from Redis list: %v\n", err)
return nil, false
}
var item CacheMhsItem
if err = json.Unmarshal([]byte(data), &item); err != nil {
log.Printf("[PopCacheMhsItem]Error unmarshalling JSON to CacheMhsItem: %v\n", err)
return nil, false
}
return &item, true
}
func RemoveMhsCache(client *redis.Client, coin string, user string, miner string, index string, key string) bool {
k := "mhs_" + coin + "_" + user + "_" + miner + "_" + index + "_" + key
switch key {
case "accepts", "rejects":
PopCacheMhsItem(client, k)
return true
}
return false
}
func LoadMhsCache(client *redis.Client, coin string, user string, miner string, index string, key string) interface{} {
k := "mhs_" + coin + "_" + user + "_" + miner + "_" + index + "_" + key
switch key {
case "starttime":
tT, ok := LoadTimeCache(client, k)
if ok {
return tT
}
return nil
case "accepts", "rejects":
/*listLength, err := client.LLen(context.Background(), k).Result()
if err != nil {
log.Printf("Error getting list length: %v\n", err)
return nil
}*/
values, err := client.LRange(context.Background(), k, 0, -1).Result()
if err != nil {
log.Printf("[LoadMhsCache]Error getting list values: %v\n", err)
}
var items []CacheMhsItem
for _, value := range values {
var item CacheMhsItem
if err = json.Unmarshal([]byte(value), &item); err != nil {
continue
}
temp_time, _ := time.Parse(time.RFC3339, item.Tt)
if temp_time.After(time.Now().Add(-24 * time.Hour)) {
items = append(items, item)
}
}
return &items
default:
return nil
}
}
func StoreMhsCache(client *redis.Client, coin string, user string, miner string, index string, key string, val interface{}) bool {
k := "mhs_" + coin + "_" + user + "_" + miner + "_" + index + "_" + key
switch key {
case "starttime":
if t, ok := val.(time.Time); ok {
return StoreTimeCache(client, k, t)
}
log.Printf("[StoreMhsCache]Invalid type for starttime: expected time.Time, got %T\n", val)
return false
case "accepts", "rejects":
if item, ok := val.(CacheMhsItem); ok {
return StoreCacheMhsItem(client, k, item)
}
log.Printf("[StoreMhsCache]Invalid type for CacheMhsItem: expected CacheMhsItem, got %T\n", val)
return false
default:
log.Printf("[StoreMhsCache]Unknown key: %s\n", key)
return false
}
}
/*
func StoreStringToSet(client *redis.Client, setKey string, value string) bool {
err := client.SAdd(context.Background(), setKey, value).Err()
if err != nil {
log.Printf("Error adding value to Redis set: %v\n", err)
return false
}
return true
}
func LoadStringsFromSet(client *redis.Client, setKey string) ([]string, bool) {
members, err := client.SMembers(context.Background(), setKey).Result()
if err != nil {
log.Printf("Error retrieving data from Redis set: %v\n", err)
return nil, false
}
return members, true
}
func RemoveStringFromSet(client *redis.Client, setKey string, value string) bool {
err := client.SRem(context.Background(), setKey, value).Err()
if err != nil {
log.Printf("Error removing value from Redis set: %v\n", err)
return false
}
return true
}
func LoadUsersCache(client *redis.Client, coin string) []string {
k := "pool_" + coin + "_users"
users, ok := LoadStringsFromSet(client, k)
if !ok {
log.Printf("Error loading users slice from Redis for coin: %s\n", coin)
return []string{}
}
return users
}
func StoreUsersCache(client *redis.Client, coin string, user string) bool {
k := "pool_" + coin + "_users"
ok := StoreStringToSet(client, k, user)
if !ok {
log.Printf("Error storing users slice to Redis for coin: %s\n", coin)
return false
}
return true
}
*/
/*
func StoreCacheMinerItem(client *redis.Client, setKey string, item CacheMinerItem) bool {
data, err := json.Marshal(item)
if err != nil {
log.Printf("Error marshalling CacheMinerItem to JSON: %v\n", err)
return false
}
err = client.SAdd(context.Background(), setKey, data).Err()
if err != nil {
log.Printf("Error adding data to Redis set: %v\n", err)
return false
}
return true
}
func LoadCacheMinerItems(client *redis.Client, setKey string) ([]CacheMinerItem, bool) {
data, err := client.SMembers(context.Background(), setKey).Result()
if err != nil {
log.Printf("Error retrieving data from Redis set: %v\n", err)
return nil, false
}
var items []CacheMinerItem
for _, itemData := range data {
var item CacheMinerItem
err := json.Unmarshal([]byte(itemData), &item)
if err != nil {
log.Printf("Error unmarshalling JSON to CacheMinerItem: %v\n", err)
return nil, false
}
items = append(items, item)
}
return items, true
}
func RemoveCacheMinerItem(client *redis.Client, setKey string, item CacheMinerItem) bool {
data, err := json.Marshal(item)
if err != nil {
log.Printf("Error marshalling CacheMinerItem to JSON: %v\n", err)
return false
}
err = client.SRem(context.Background(), setKey, data).Err()
if err != nil {
log.Printf("Error removing data from Redis set: %v\n", err)
return false
}
return true
}
func LoadMinersCache(client *redis.Client, coin string) []CacheMinerItem {
k := "pool_" + coin + "_miners"
miners, ok := LoadCacheMinerItems(client, k)
if !ok {
log.Printf("Error loading miners set from Redis for coin: %s\n", coin)
return []CacheMinerItem{}
}
return miners
}
func StoreMinersCache(client *redis.Client, coin string, miner CacheMinerItem) bool {
k := "pool_" + coin + "_miners"
ok := StoreCacheMinerItem(client, k, miner)
if !ok {
log.Printf("Error storing miners slice to Redis for coin: %s\n", coin)
return false
}
return true
}
*/

2996
internal/db/db.go Normal file

File diff suppressed because it is too large Load Diff

85
internal/gbt/coin/coin.go Normal file
View File

@ -0,0 +1,85 @@
// coin.go
package coin
import (
"pool/internal/db"
monero_rpc "pool/internal/gbt/monero/rpc"
"pool/internal/gbt/tari"
"pool/internal/utility"
"github.com/btcsuite/btcd/rpcclient"
"github.com/redis/go-redis/v9"
"github.com/zeromq/goczmq"
"go.uber.org/zap"
"gopkg.in/natefinch/lumberjack.v2"
)
type RpcConfig struct {
Host string `json:"host"`
Testnet string `json:"testnet"`
Type string `json:"type"`
User string `json:"user"`
Pass string `json:"pass"`
ZmqSub string `json:"zmqsub"`
Timeout int `json:"timeout"`
}
type ZmqConfig struct {
Pub string `json:"pub"`
Sub string `json:"sub"`
}
type ProfitConfig struct {
Push string `json:"push"`
}
type GbtConfig struct {
Rpc RpcConfig `json:"rpc"`
Zmq ZmqConfig `json:"zmq"`
Redis utility.RedisConfig `json:"redis"`
Profit ProfitConfig `json:"profit"`
Zaplog zap.Config `json:"zap"`
Logrotae utility.LogRotateConfig `json:"logrotate"`
}
type GbtContext struct {
DbCtx *db.DbContext
NodeSubCh *goczmq.Sock
PubCh *goczmq.Sock
SubCh *goczmq.Sock
MoneroNewBlockPubCh *goczmq.Sock // monero gbt有新块产生时发送消息队列
MoneroNewBlockSubCh *goczmq.Sock // 模仿自带zmq通知的币
PushCh *goczmq.Sock
Started bool
Config GbtConfig
Client *rpcclient.Client
MoneroClinet *monero_rpc.HttpClient
TariClient *tari.BaseNodeClient
MoneroAddr string // monero报块地址
TariAddr string // tari报块地址
ExitNotifyChan chan bool
ExitGbtChan chan bool
ExitBlockChan chan bool
//AlivingChan chan bool
FlagAliving int32
FlagAlivingExit int32
Log *zap.Logger
LogR *lumberjack.Logger
RedisClient *redis.Client
Coin string
MinerAddrs []string
MinerAddrIndex int
/*Blocks int64
Reward float64
Fee float64*/
}

198
internal/gbt/dbif/dbif.go Normal file
View File

@ -0,0 +1,198 @@
// dbif.go
package dbif
import (
"pool/internal/db"
"pool/internal/gbt/coin"
"time"
)
func NotifyBlkDetailSuccess(gbt *coin.GbtContext, height int64, hash string, nonce string, subidx int64) {
var msg db.BlkDetail_db_msg
msg.Id = 0
msg.Msg = "blk_detail"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.Height = height
msg.Hash = hash
msg.Success = 1
msg.Nonce = nonce
msg.SubIdx = subidx
//gbt.DbCtx.BlkDetail_ch <- msg
db.Save_blk_detail(gbt.DbCtx, &msg)
}
/*func NotifyMinerSuccess(gbt *coin.GbtContext, user string, miner string, minerid string, height int64, hash string, nonce string, subidx int64, reward float64, fee float64) {
var msg db.Miner_db_msg
msg.Id = 0
msg.Msg = "miner"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.User = user
msg.Miner = miner
msg.Index = minerid
msg.Height = height
msg.Hash = hash
msg.Success = 1
msg.Nonce = nonce
msg.SubIdx = subidx
msg.Reward = reward
msg.Fee = fee
gbt.DbCtx.Miner_ch <- msg
}*/
/*func NotifyUsersBlkStatsSuccess(gbt *coin.GbtContext, user string, height int64, hash string, nonce string, subidx int64, reward float64, fee float64) {
var msg db.UsersBlkStats_db_msg
msg.Id = 0
msg.Msg = "users_blkstats"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.User = user
msg.Height = height
msg.Hash = hash
msg.Success = 1
msg.Nonce = nonce
msg.SubIdx = subidx
msg.Reward = reward
msg.Fee = fee
gbt.DbCtx.UsersBlkStats_ch <- msg
}*/
func NotifyPoolBlkStatsSuccess(gbt *coin.GbtContext, height int64, hash string, nonce string, subidx int64, reward float64, fee float64) {
var msg db.PoolBlkStats_db_msg
msg.Id = 0
msg.Msg = "pool_blkstats"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.Height = height
msg.Hash = hash
msg.Success = 1
msg.Nonce = nonce
msg.SubIdx = subidx
msg.Submit = ""
msg.Reward = reward
msg.Fee = fee
gbt.DbCtx.PoolBlkStats_ch <- msg
}
/*func NotifyMinerSubmitResult(gbt *coin.GbtContext, user string, miner string, minerid string, height int64, hash string, result string, nonce string, subidx int64) {
var msg db.Miner_db_msg
msg.Id = 0
msg.Msg = "miner"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.User = user
msg.Miner = miner
msg.Index = minerid
msg.Height = height
msg.Hash = hash
msg.Submit = result
msg.Nonce = nonce
msg.SubIdx = subidx
gbt.DbCtx.Miner_ch <- msg
}*/
/*func NotifyUsersBlkStatsSubmitResult(gbt *coin.GbtContext, user string, height int64, hash string, result string, nonce string, subidx int64) {
var msg db.UsersBlkStats_db_msg
msg.Id = 0
msg.Msg = "users_blkstats"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.User = user
msg.Height = height
msg.Hash = hash
msg.Submit = result
msg.Nonce = nonce
msg.SubIdx = subidx
gbt.DbCtx.UsersBlkStats_ch <- msg
}*/
func NotifyPoolBlkStatsSubmitResult(gbt *coin.GbtContext, height int64, hash string, result string, nonce string, subidx int64) {
var msg db.PoolBlkStats_db_msg
msg.Id = 0
msg.Msg = "pool_blkstats"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.Height = height
msg.Hash = hash
msg.Submit = result
msg.Nonce = nonce
msg.SubIdx = subidx
gbt.DbCtx.PoolBlkStats_ch <- msg
}
func NotifyBlkNewDb(gbt *coin.GbtContext, height int64, hash string, success bool, nonce string, subidx int64) {
var msg db.BlkNew_db_msg
msg.Id = 0
msg.Msg = "blk_new"
msg.Date = time.Now()
msg.MinerType = gbt.Coin
msg.Height = height
msg.Hash = hash
if success {
msg.Success = 1
} else {
msg.Success = 0
}
msg.Nonce = nonce
msg.SubIdx = subidx
gbt.DbCtx.BlkNew_ch <- msg
}
/*func NotifyBlockStat(gbt *coin.GbtContext, user string, miner string, minerid string, reward float64, fee float64) {
var miners_msg db.Miners_db_msg
miners_msg.Id = 0
miners_msg.Msg = "miners"
miners_msg.Date = time.Now()
miners_msg.MinerType = gbt.Coin
miners_msg.User = user
miners_msg.Miner = miner
miners_msg.Index = minerid
gbt.DbCtx.Miners_ch <- miners_msg
var users_msg db.Users_db_msg
users_msg.Id = 0
users_msg.Msg = "users"
users_msg.Date = time.Now()
users_msg.MinerType = gbt.Coin
users_msg.User = user
gbt.DbCtx.Users_ch <- users_msg
var pool_msg db.Pool_db_msg
pool_msg.Id = 0
pool_msg.Msg = "pool"
pool_msg.Date = time.Now()
pool_msg.MinerType = gbt.Coin
pool_msg.Reward = reward
pool_msg.Fee = fee
gbt.DbCtx.Pool_ch <- pool_msg
}*/

300
internal/gbt/gbt.go Normal file
View File

@ -0,0 +1,300 @@
// gbt.go
package gbt
import (
"encoding/json"
"fmt"
"log"
"io/ioutil"
"pool/internal/db"
"sync/atomic"
//"pool/internal/cache"
"pool/internal/gbt/coin"
monero_rpc "pool/internal/gbt/monero/rpc"
"pool/internal/gbt/tari"
"pool/internal/gbt/tari/sha3x"
"pool/internal/utility"
"os"
"os/signal"
"syscall"
"time"
"github.com/btcsuite/btcd/rpcclient"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
var logg *zap.Logger
var GbtCtx coin.GbtContext
func InitConfig(config *coin.GbtConfig) {
data, err := ioutil.ReadFile("gbt.conf")
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
}
func InitClient(gbt *coin.GbtContext) error {
fmt.Println(gbt.Coin)
switch gbt.Coin {
case "monero":
url := "http://" + gbt.Config.Rpc.Host
rpcClient := monero_rpc.NewHttpClient(url, 10*time.Second)
gbt.MoneroClinet = rpcClient
gbt.MoneroAddr = gbt.Config.Rpc.User
case "sha3x":
url := gbt.Config.Rpc.Host
grpcClient, err := tari.NewBaseNodeClient(url)
if err != nil {
fmt.Println("tari创建grpc服务失败", err)
return err
}
gbt.TariClient = grpcClient
gbt.TariAddr = gbt.Config.Rpc.Host
default:
var config rpcclient.ConnConfig
if gbt.Config.Rpc.Type == "testnet" {
config.Host = gbt.Config.Rpc.Testnet
} else {
config.Host = gbt.Config.Rpc.Host
}
config.User = gbt.Config.Rpc.User
config.Pass = gbt.Config.Rpc.Pass
config.HTTPPostMode = true
config.DisableTLS = true
client, err := rpcclient.New(&config, nil)
if err != nil {
logg.Info("[gbt]", zap.String("rpcclient new ", err.Error()))
return err
}
gbt.Client = client
blockCount, err := client.GetBlockCount()
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockCount ", err.Error()))
return err
}
logg.Info("[gbt]", zap.Int64("Block count ", blockCount))
}
return nil
}
/*func GbtLivingHandler(gbt *coin.GbtContext) {
timer := time.NewTimer(time.Duration(600) * time.Second)
for {
select {
case aliving := <-gbt.AlivingChan:
if !aliving {
timer.Stop()
//log.Println("gbt aliving", aliving)
return
} else {
timer.Reset(time.Duration(600) * time.Second)
}
case <-time.After(time.Duration(600) * time.Second):
gbt.ExitGbtChan <- true
return
}
}
}*/
func GbtLivingHandler(gbt *coin.GbtContext) {
var to_cnt int = 0
for {
flagAliving := atomic.LoadInt32(&(gbt.FlagAliving))
flagExit := atomic.LoadInt32(&(gbt.FlagAlivingExit))
if flagExit == 1 {
logg.Error("[server]", zap.String("GbtLivingHandler exited", "exit"))
break
}
if flagAliving == 0 {
//if to_cnt > 240 {
if to_cnt > gbt.Config.Rpc.Timeout*3/1000 {
logg.Error("[server]", zap.String("GbtLivingHandler exited", "timer expired"))
cmd := "killall gbt_" + gbt.Coin + " &"
utility.ExecShellCmd(cmd)
gbt.ExitGbtChan <- true
break
}
to_cnt++
} else {
to_cnt = 0
atomic.StoreInt32(&(gbt.FlagAliving), 0)
}
time.Sleep(time.Second)
}
}
type coinobj struct {
Coin string
Init func(GbtCtx *coin.GbtContext, DbCtx *db.DbContext)
Start func()
Stop func()
}
var coinobjs = []coinobj{
// {Coin: "nexa", Init: nexa.Init, Start: nexa.Start, Stop: nexa.Stop},
// {Coin: "monero", Init: monero.Init, Start: monero.Start, Stop: monero.Stop},
{Coin: "sha3x", Init: sha3x.Init, Start: sha3x.Start, Stop: sha3x.Stop},
}
func register_signal(dbctx *db.DbContext) {
signal_ch := make(chan os.Signal, 1)
signal.Notify(signal_ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go signal_handle(signal_ch, dbctx)
}
func signal_handle(signal_ch chan os.Signal, dbctx *db.DbContext) {
for s := range signal_ch {
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
log.Println("stop!")
dbctx.AppExit <- true
default:
//fmt.Println("other signal", s)
}
}
}
/*func LoadCache(gbt *coin.GbtContext) {
val := cache.LoadPoolCache(gbt.RedisClient, gbt.Coin, "blocks")
if val != nil {
if intVal, ok := val.(int64); ok {
gbt.Blocks = intVal
}
}
val_f := cache.LoadPoolCache(gbt.RedisClient, gbt.Coin, "rewards")
if val_f != nil {
if fVal, ok := val_f.(float64); ok {
gbt.Reward = fVal
}
}
val_f = cache.LoadPoolCache(gbt.RedisClient, gbt.Coin, "fee")
if val_f != nil {
if fVal, ok := val_f.(float64); ok {
gbt.Fee = fVal
}
}
}*/
func Start(Coin string, DbCtx *db.DbContext) {
GbtCtx.DbCtx = DbCtx
GbtCtx.Coin = Coin
atomic.StoreInt32(&(GbtCtx.FlagAliving), 0)
atomic.StoreInt32(&(GbtCtx.FlagAlivingExit), 0)
InitConfig(&GbtCtx.Config)
l, lr, err := utility.InitLogg(&(GbtCtx.Config.Zaplog), &(GbtCtx.Config.Logrotae), Coin, "gbt")
logg = l
//defer logg.Sync()
GbtCtx.Log = l
GbtCtx.LogR = lr
GbtCtx.RedisClient = redis.NewClient(&redis.Options{
Addr: GbtCtx.Config.Redis.Addr,
Password: GbtCtx.Config.Redis.Password,
DB: GbtCtx.Config.Redis.DB,
})
register_signal(DbCtx)
GbtCtx.PubCh = utility.InitZmqPub(GbtCtx.Config.Zmq.Pub)
GbtCtx.SubCh = utility.InitZmqSub(GbtCtx.Config.Zmq.Sub, "blk"+Coin)
GbtCtx.MoneroNewBlockPubCh = utility.InitZmqPub(GbtCtx.Config.Rpc.ZmqSub)
GbtCtx.MoneroNewBlockSubCh = utility.InitZmqSub(GbtCtx.Config.Rpc.ZmqSub, "hashblock")
//GbtCtx.PushCh = utility.InitZmqPush(GbtCtx.Config.Profit.Push)
for {
err = InitClient(&GbtCtx)
if err != nil {
logg.Error("[gbt]", zap.String("InitClient", err.Error()))
time.Sleep(time.Duration(5) * time.Second)
continue
}
break
}
if len(GbtCtx.Config.Rpc.ZmqSub) > 0 {
GbtCtx.NodeSubCh = utility.InitZmqSub(GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
}
GbtCtx.Started = true
GbtCtx.ExitGbtChan = make(chan bool, 256)
//GbtCtx.AlivingChan = make(chan bool, 256)
GbtCtx.MinerAddrs = db.GetAddressFromTable(DbCtx)
GbtCtx.MinerAddrIndex = 0
//LoadCache(&GbtCtx)
for _, coinobj := range coinobjs {
if coinobj.Coin == Coin {
coinobj.Init(&GbtCtx, DbCtx)
go coinobj.Start()
break
}
}
go GbtLivingHandler(&GbtCtx)
<-DbCtx.AppExit
}
func Stop(Coin string) {
GbtCtx.Started = false
GbtCtx.ExitGbtChan <- true
//GbtCtx.AlivingChan <- false
atomic.StoreInt32(&(GbtCtx.FlagAlivingExit), 1)
for _, coinobj := range coinobjs {
if coinobj.Coin == Coin {
coinobj.Stop()
break
}
}
//time.Sleep(1 * time.Second)
defer close(GbtCtx.ExitGbtChan)
//defer close(GbtCtx.AlivingChan)
if GbtCtx.NodeSubCh != nil {
defer GbtCtx.NodeSubCh.Destroy()
}
if GbtCtx.PubCh != nil {
defer GbtCtx.PubCh.Destroy()
}
if GbtCtx.SubCh != nil {
defer GbtCtx.SubCh.Destroy()
}
/*if GbtCtx.PushCh != nil {
defer GbtCtx.PushCh.Destroy()
}*/
defer GbtCtx.RedisClient.Close()
defer logg.Sync()
}

View File

@ -0,0 +1,495 @@
package monero
import (
"crypto/rand"
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math"
"pool/internal/db"
"pool/internal/gbt/coin"
"pool/internal/gbt/dbif"
"pool/internal/msg"
"pool/internal/utility"
"sync/atomic"
"time"
"go.uber.org/zap"
)
const GBT_MONERO_VERSION string = "monero v1.0"
type MoneroAddrConfig struct {
Addr string `json:"addr"`
}
type MoneroConfig struct {
Monero MoneroAddrConfig `json:"nexa"`
}
type GetBlockTemplateResponse struct {
ID string `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Result msg.MoneroStratumJob `json:"result"`
Error *RpcError `json:"error,omitempty"`
}
type RpcError struct {
Code int `json:"code"`
Message string `json:"message"`
}
// RPCError 用于描述 RPC 返回的错误
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
}
// 通用 RPC 响应结构
type MoneroRPCResponse[T any] struct {
ID string `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Result *T `json:"result,omitempty"` // 成功时使用
Error *RPCError `json:"error,omitempty"` // 失败时使用
}
type SubmitSuccess struct {
BlockId string `json:"block_id"`
Status string `json:"status"`
Untrusted bool `json:"untrusted"`
}
type GbtMoneroContext struct {
Config MoneroConfig
GbtCtx *coin.GbtContext
last_time time.Time
last_gbt msg.MoneroStratumJob
last_blockhash string
last_height uint32
Submits float64
addressIndex int
Target []byte
Header []byte
last_body string
new_block_chan chan int
new_block_index int
}
var logg *zap.Logger
var GbtMoneroCtx GbtMoneroContext
func configInit(config *MoneroConfig) {
data, err := ioutil.ReadFile("gbt.conf")
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {
GbtMoneroCtx.GbtCtx = GbtCtx
GbtMoneroCtx.last_height = 0
configInit(&GbtMoneroCtx.Config)
GbtMoneroCtx.Target = make([]byte, 32)
GbtMoneroCtx.Header = make([]byte, 49)
GbtMoneroCtx.last_time = time.Now()
logg = GbtCtx.Log
GbtMoneroCtx.new_block_chan = make(chan int, 256)
GbtMoneroCtx.new_block_index = 0
logg.Info("[gbt]", zap.String("gbt_monero_version", GBT_MONERO_VERSION))
}
func Start() {
go gbt_running(&GbtMoneroCtx)
go gbt_notify_running(&GbtMoneroCtx)
go submit_block_running(&GbtMoneroCtx)
}
func Stop() {
defer close(GbtMoneroCtx.new_block_chan)
}
type BlockCheckData struct {
Height int
Nonce string
User string
Miner string
MinerId string
Hash string
SubIdx int
}
type GetBlockHeaderResp struct {
Id string `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Error any `json:"error"`
Result GetBlockHeaderMsg `json:"result"`
}
type GetBlockHeaderMsg struct {
Result struct {
BlockHeader struct {
Nonce uint64 `json:"nonce"`
PowHash string `json:"pow_hash"`
Reward uint64 `json:"reward"`
} `json:"block_header"`
Status string `json:"status"`
Untrusted bool `json:"untrusted"`
} `json:"result"`
}
func update_block_confirm(gbt *GbtMoneroContext) {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
//log.Printf("Error opening database: %v", err)
logg.Error("[gbt]", zap.String("Error opening database", err.Error()))
return
}
defer db.Close()
query := "SELECT user,miner,minerid,height,nonce,hash,subidx FROM blocks WHERE checked=0 AND created_at >= datetime('now', '-30 minutes') order by id desc limit 2"
rows, err := db.Query(query)
if err != nil {
//log.Printf("Error executing query from blocks: %v", err)
logg.Error("[gbt]", zap.String("Error executing query from blocks:", err.Error()))
return
}
defer rows.Close()
var blocks []BlockCheckData
for rows.Next() {
var height int
var nonce string
var user string
var miner string
var minerid string
var hash string
var subidx int
if err := rows.Scan(&user, &miner, &minerid, &height, &nonce, &hash, &subidx); err != nil {
//log.Printf("Error scanning row in blocks: %v", err)
logg.Error("[gbt]", zap.String("Error scanning row in blocks:", err.Error()))
return
}
var blockdata BlockCheckData
blockdata.Height = height
blockdata.Nonce = nonce
blockdata.User = user
blockdata.Miner = miner
blockdata.MinerId = minerid
blockdata.Hash = hash
blockdata.SubIdx = subidx
blocks = append(blocks, blockdata)
//fmt.Printf("blocks - Height: %d, Nonce: %d\n", height, nonce)
//log.Printf("update block height %d nonce %s, subidx %d, user %s", height, nonce, subidx, user+"."+miner+"_"+minerid)
}
for _, block := range blocks {
var blockHeaderResp GetBlockHeaderResp
resp, err := gbt.GbtCtx.MoneroClinet.GetBlockByHash(block.Hash)
err = json.Unmarshal(resp, &blockHeaderResp)
if err != nil {
logg.Error("[gbt]", zap.String("getblockheader Unmarshal ", fmt.Sprint(block.Height)+" "+err.Error()))
continue
}
if blockHeaderResp.Error != nil {
fmt.Println("[check block]:", blockHeaderResp.Error)
update_sql := `UPDATE blocks SET checked = 2 WHERE height = ? AND nonce = ? AND checked = 0`
_, err = db.Exec(update_sql, block.Height, block.Nonce)
if err != nil {
//log.Printf("Error updating blk_new: %v", err)
logg.Error("[gbt]", zap.String("Error updating blk_new:", err.Error()))
}
return
}
blockHeader := blockHeaderResp.Result
block_height := int64(block.Height)
// nonceHex := fmt.Sprintf("%x", block.Nonce)
dbif.NotifyPoolBlkStatsSuccess(gbt.GbtCtx, block_height, "", block.Nonce, int64(block.SubIdx), float64(blockHeader.Result.BlockHeader.Reward)/math.Pow(10, 12), 0)
dbif.NotifyBlkDetailSuccess(gbt.GbtCtx, block_height, "", block.Nonce, int64(block.SubIdx))
dbif.NotifyBlkNewDb(gbt.GbtCtx, block_height, block.Hash, true, block.Nonce, int64(block.SubIdx))
updateSQL := `UPDATE blocks SET checked = 1 WHERE height = ? AND nonce = ? AND checked = 0`
_, err = db.Exec(updateSQL, block.Height, block.Nonce)
if err != nil {
//log.Printf("Error updating blk_new: %v", err)
logg.Error("[gbt]", zap.String("Error updating blk_new:", err.Error()))
continue
}
logg.Warn("[gbt]", zap.String("update block success:", fmt.Sprint(block.Height)+" "+block.Nonce))
}
}
func randomxJobId() string {
// 生成4个字节
bytes := make([]byte, 4)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
// 转成 hex 字符串
hexStr := hex.EncodeToString(bytes)
return hexStr
}
var start_count int = 0
var start_height uint64 = 0
func gbt_running(gbt *GbtMoneroContext) {
ticker := time.NewTicker(1000 * time.Millisecond)
defer ticker.Stop()
for gbt.GbtCtx.Started {
select {
case <-ticker.C:
resp, err := gbt.GbtCtx.MoneroClinet.GetBlockTemplate(gbt.GbtCtx.MoneroAddr, 0)
if err != nil {
fmt.Println("调用失败:", err)
continue
}
if resp != nil {
if gbt.GbtCtx.PubCh == nil {
gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
}
if gbt.GbtCtx.PubCh != nil {
var responseJson GetBlockTemplateResponse
err = json.Unmarshal(resp, &responseJson)
if err != nil {
fmt.Println("[gbt]:get block template response to json error\n", err)
return
}
sendJobMonero := func(job msg.MoneroStratumJob) {
for trycnt := 0; trycnt < 3; trycnt++ {
job.JobId = randomxJobId()
bt, err := json.Marshal(job)
if err != nil {
fmt.Println(err)
return
}
err = gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobmonero"), bt})
if err != nil {
if !gbt.GbtCtx.Started {
return
}
logg.Warn("[gbt]", zap.String("job", err.Error()))
} else {
logg.Warn("[gbt]", zap.String("job", "sent"))
start_height = job.Height
start_count = 0
break
}
}
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
}
if responseJson.Result.Height != start_height {
// 高度变化,先发 hashblock
if start_height != 0 {
topic := []byte("hashblock")
_msg := []byte("")
_ = gbt.GbtCtx.MoneroNewBlockPubCh.SendMessage([][]byte{topic, _msg})
}
// 再发 jobmonero
sendJobMonero(responseJson.Result)
} else if start_count >= 30 {
// 高度未变,但计数达到阈值,只发 jobmonero
sendJobMonero(responseJson.Result)
} else {
start_count += 1
}
} else {
logg.Warn("[gbt]", zap.String("job ", "sent failed! PubCh nil"))
}
} else {
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
}
case blkIdx := <-gbt.new_block_chan:
log.Println("new block chan", blkIdx)
update_block_confirm(gbt)
case <-gbt.GbtCtx.ExitGbtChan:
logg.Error("[gbt]", zap.String("gbt", "exit"))
return
}
}
}
func gbt_notify_running(gbt *GbtMoneroContext) {
for {
if !gbt.GbtCtx.Started {
break
}
if gbt.GbtCtx.MoneroNewBlockSubCh == nil {
gbt.GbtCtx.MoneroNewBlockSubCh = utility.InitZmqSub(gbt.GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
}
if gbt.GbtCtx.MoneroNewBlockSubCh != nil {
// fmt.Println("gbt_notify_running 开始接收消息")
cmsg_sub, err := gbt.GbtCtx.MoneroNewBlockSubCh.RecvMessage()
if err != nil {
if !gbt.GbtCtx.Started {
break
}
gbt.GbtCtx.MoneroNewBlockSubCh.SetSubscribe(utility.BITCOIND_ZMQ_HASHBLOCK)
gbt.GbtCtx.MoneroNewBlockSubCh.Connect(gbt.GbtCtx.Config.Rpc.ZmqSub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "hashblock" {
GbtMoneroCtx.new_block_index = GbtMoneroCtx.new_block_index + 1
//log.Println("gbt_notify_running", hex.EncodeToString(cmsg_sub[1]), GbtNexaCtx.new_block_index)
gbt.new_block_chan <- GbtMoneroCtx.new_block_index
}
}
} else {
logg.Error("[gbt]", zap.String("notify", "NodeSubCh fail!"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
func submit_block_running(block *GbtMoneroContext) {
logg.Info("[block]", zap.String("submit_block_running", "Start."))
for {
if !block.GbtCtx.Started {
break
}
if block.GbtCtx.SubCh == nil {
block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
}
if block.GbtCtx.SubCh != nil {
cmsg_sub, err := block.GbtCtx.SubCh.RecvMessage()
if err != nil {
if !block.GbtCtx.Started {
break
}
time.Sleep(time.Duration(1) * time.Second)
block.GbtCtx.SubCh.SetSubscribe("blk" + block.GbtCtx.Coin)
block.GbtCtx.SubCh.Connect(block.GbtCtx.Config.Zmq.Sub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "blkmonero" {
cmsg := cmsg_sub[1]
//block data
msgb := make([]byte, len(cmsg)-16)
copy(msgb, cmsg)
var moneroblock msg.BlockMoneroMsg
if err := json.Unmarshal(msgb, &moneroblock); err != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to Unmarshal job", err.Error()))
continue
}
// heightb, err := hex.DecodeString(string(cmsg[len(msgb) : len(msgb)+8]))
// if err != nil {
// //block.Consumer.MarkOffset(cmsg, "")
// logg.Error("[block]", zap.String("failed to decode height", err.Error()))
// continue
// }
var height uint32 = uint32(moneroblock.Height)
logg.Warn("[block]", zap.Uint32("height", height))
if height <= block.last_height {
continue
}
block.last_height = height
indexb, err1 := hex.DecodeString(string(cmsg[len(msgb)+8:]))
if err1 != nil {
logg.Error("[block]", zap.String("failed to decode index", err1.Error()))
continue
}
var index uint32 = utility.ByteToUint32(indexb)
logg.Warn("[block]", zap.Uint32("index", index))
logg.Debug("[block]", zap.String("msg", string(cmsg)), zap.String("blk", string(msgb)))
result, _ := block.GbtCtx.MoneroClinet.SubmitBlock(moneroblock.Header)
var submitResp MoneroRPCResponse[SubmitSuccess]
if err2 := json.Unmarshal(result, &submitResp); err2 != nil {
logg.Error("[submit block]", zap.String("unmarshal error", err2.Error()))
return
}
if submitResp.Error != nil {
logg.Error("[submit block]", zap.String("submit failed reason", submitResp.Error.Message))
return
}
if submitResp.Result != nil {
logg.Info("[submit block]", zap.String("submit status", submitResp.Result.Status))
}
logg.Info("[block]", zap.String("result", string(result)))
//}
blockHash, success_msg := submitResp.Result.BlockId, submitResp.Result.Status
// nonceHex := fmt.Sprintf("%x", moneroblock.Nonce)
dbif.NotifyPoolBlkStatsSubmitResult(block.GbtCtx, int64(height), blockHash, success_msg, moneroblock.Nonce, moneroblock.SubIdx)
block.Submits += 1
//log.Printf("[block] height %d subidx %d nonce %s\n", height, nexablock.SubIdx, nexablock.Nonce)
logg.Warn("[block]", zap.Float64("total submits", block.Submits), zap.Int64("SubIdx", moneroblock.SubIdx))
// nonce, err := strconv.ParseUint(moneroblock.Nonce, 16, 32)
// if err != nil {
// return
// }
new_block_into_db(block, moneroblock.User, moneroblock.Miner, moneroblock.Index, int64(height), moneroblock.Nonce, blockHash, moneroblock.SubIdx)
}
}
} else {
logg.Error("[block]", zap.String("block", "SubCh failed! retry"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
func new_block_into_db(block *GbtMoneroContext, user string, miner string, minerid string, height int64, nonce string, hash string, subidx int64) bool {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
log.Printf("Error opening database: %v", err)
return false
}
defer db.Close()
createTableSQL := `
CREATE TABLE IF NOT EXISTS blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
miner TEXT NOT NULL,
minerid TEXT NOT NULL,
height INTEGER,
nonce TEXT NOT NULL,
hash TEXT NOT NULL,
subidx INTEGER,
checked INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Printf("Error creating table: %v", err)
return false
}
insertSQL := `INSERT INTO blocks (user, miner, minerid, height, nonce, checked, hash, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
_, err = db.Exec(insertSQL, user, miner, minerid, height, nonce, 0, hash, subidx)
if err != nil {
log.Printf("Error inserting data from blocks %s: %v", fmt.Sprint(height), err)
return false
}
return true
}

View File

@ -0,0 +1,179 @@
package monero_rpc
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
)
// HttpClient 封装
type HttpClient struct {
Client *http.Client
Url string
}
func NewHttpClient(url string, timeout time.Duration) *HttpClient {
return &HttpClient{
Client: &http.Client{
Timeout: timeout,
},
Url: url,
}
}
// GET 请求params 可为 nil
func (hc *HttpClient) Get(api string, params map[string]interface{}, headers map[string]string) ([]byte, error) {
rawURL := hc.Url + "/json_rpc" + api
// 处理 URL 参数
if params != nil {
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
q := u.Query()
for k, v := range params {
q.Set(k, fmt.Sprintf("%v", v))
}
u.RawQuery = q.Encode()
rawURL = u.String()
}
// 创建请求
req, err := http.NewRequest("GET", rawURL, nil)
if err != nil {
return nil, err
}
// 设置头
for k, v := range headers {
req.Header.Set(k, v)
}
// 发送请求
resp, err := hc.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
// POST 请求params 可为 nil
func (hc *HttpClient) Post(api string, params interface{}, headers map[string]string) ([]byte, error) {
rawURL := hc.Url + "/json_rpc" + api
var body io.Reader
if params != nil {
jsonBytes, err := json.Marshal(params)
if err != nil {
return nil, err
}
body = bytes.NewBuffer(jsonBytes)
}
req, err := http.NewRequest("POST", rawURL, body)
if err != nil {
return nil, err
}
// 设置默认 Content-Type
if _, ok := headers["Content-Type"]; !ok {
req.Header.Set("Content-Type", "application/json")
}
// 设置额外头
for k, v := range headers {
req.Header.Set(k, v)
}
resp, err := hc.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
type RPCRequest struct {
JsonRPC string `json:"jsonrpc"`
ID string `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
func (hc *HttpClient) GetBlockTemplate(address string, size int) ([]byte, error) {
params := map[string]any{
"wallet_address": address,
"reserve_size": size,
}
req := RPCRequest{
JsonRPC: "2.0",
ID: "0",
Method: "get_block_template",
Params: params,
}
resp, err := hc.Post("", req, nil)
if err != nil {
fmt.Println("[gbt]: getblocktemplate error:", err)
return nil, err
}
return resp, nil
}
func (hc *HttpClient) GetBlockHeader(height uint64) ([]byte, error) {
params := map[string]any{
"height": height,
"fill_pow_hash": true,
}
req := RPCRequest{
JsonRPC: "2.0",
ID: "0",
Method: "get_block_header_by_height",
Params: params,
}
resp, err := hc.Post("", req, nil)
if err != nil {
fmt.Println("[gbt]: getblockheader error:", err)
return nil, err
}
return resp, nil
}
func (hc *HttpClient) GetBlockByHash(hash string) ([]byte, error) {
params := map[string]any{
"hash": hash,
}
req := RPCRequest{
JsonRPC: "2.0",
ID: "0",
Method: "get_block_header_by_hash",
Params: params,
}
resp, err := hc.Post("", req, nil)
if err != nil {
fmt.Println("[gbt]: getblockheader error:", err)
return nil, err
}
return resp, nil
}
func (hc *HttpClient) SubmitBlock(blob string) ([]byte, error) {
params := []string{blob}
req := RPCRequest{
JsonRPC: "2.0",
ID: "0",
Method: "submit_block",
Params: params,
}
resp, err := hc.Post("", req, nil)
if err != nil {
fmt.Println("[gbt]: getblockheader error:", err)
return nil, err
}
return resp, nil
}

627
internal/gbt/nexa/nexa.go Normal file
View File

@ -0,0 +1,627 @@
// nexa.go
package nexa
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"sync/atomic"
//"pool/internal/cache"
"pool/internal/db"
"pool/internal/gbt/coin"
"pool/internal/gbt/dbif"
"pool/internal/msg"
"pool/internal/utility"
"time"
"database/sql"
//"github.com/btcsuite/btcd/rpcclient"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
const GBT_NEXA_VERSION string = "nexa v2.0m"
type NexaAddrConfig struct {
Addr string `json:"addr"`
}
type NexaConfig struct {
Nexa NexaAddrConfig `json:"nexa"`
}
type GbtNexaContext struct {
Config NexaConfig
GbtCtx *coin.GbtContext
last_time time.Time
last_gbt GbtNexaMsg
last_blockhash string
last_height uint32
Submits float64
addressIndex int
Target []byte
Header []byte
last_body string
new_block_chan chan int
new_block_index int
}
var logg *zap.Logger
var GbtNexaCtx GbtNexaContext
type GbtNexaMsg struct {
Id uint64 `json:"id"`
HeaderCommitment string `json:"headerCommitment"`
NBits string `json:"nBits"`
}
type GetBlockHeaderMsg struct {
Height int `json:"height"`
Nonce string `json:"nonce"`
Confirmations int `json:"confirmations"`
}
type GetBlockStatsMsg struct {
Height int `json:"height"`
Subsidy float64 `json:"subsidy"`
Totalfee float64 `json:"totalfee"`
}
type BlockCheckData struct {
Height int
Nonce string
User string
Miner string
MinerId string
Hash string
SubIdx int
}
/*type NewBlockMsg struct {
Height int `json:"height"`
Nonce int `json:"nonce"`
}*/
type PushBlkNewMsg struct {
Coin string `json:"coin"`
Height int `json:"height"`
Nonce string `json:"nonce"`
}
func update_block_confirm(gbt *GbtNexaContext) {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
//log.Printf("Error opening database: %v", err)
logg.Error("[gbt]", zap.String("Error opening database", err.Error()))
return
}
defer db.Close()
query := "SELECT user,miner,minerid,height,nonce,hash,subidx FROM blocks WHERE checked=0 AND created_at >= datetime('now', '-30 minutes') order by id desc limit 2"
rows, err := db.Query(query)
if err != nil {
//log.Printf("Error executing query from blocks: %v", err)
logg.Error("[gbt]", zap.String("Error executing query from blocks:", err.Error()))
return
}
defer rows.Close()
var blocks []BlockCheckData
for rows.Next() {
var height int
var nonce string
var user string
var miner string
var minerid string
var hash string
var subidx int
if err := rows.Scan(&user, &miner, &minerid, &height, &nonce, &hash, &subidx); err != nil {
//log.Printf("Error scanning row in blocks: %v", err)
logg.Error("[gbt]", zap.String("Error scanning row in blocks:", err.Error()))
return
}
var blockdata BlockCheckData
blockdata.Height = height
blockdata.Nonce = nonce
blockdata.User = user
blockdata.Miner = miner
blockdata.MinerId = minerid
blockdata.Hash = hash
blockdata.SubIdx = subidx
blocks = append(blocks, blockdata)
//fmt.Printf("blocks - Height: %d, Nonce: %d\n", height, nonce)
//log.Printf("update block height %d nonce %s, subidx %d, user %s", height, nonce, subidx, user+"."+miner+"_"+minerid)
}
for _, block := range blocks {
block_hash, err := gbt.GbtCtx.Client.GetBlockHash(int64(block.Height))
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockHash ", err.Error()))
continue
}
rawmsgs := make([]json.RawMessage, 1)
param_str := `"` + block_hash.String() + `"`
rawmsgs[0] = json.RawMessage(param_str)
result, err := gbt.GbtCtx.Client.RawRequest("getblockheader", rawmsgs)
if err != nil {
//log.Printf("getblockheader %s", err.Error())
logg.Error("[gbt]", zap.String("getblockheader", err.Error()))
continue
}
//log.Printf("getblockheader %d %s:%v", block.Height, block_hash, result)
var blockHeader GetBlockHeaderMsg
err = json.Unmarshal(result, &blockHeader)
if err != nil {
//log.Printf("getblockheader Unmarshal %s", err.Error())
logg.Error("[gbt]", zap.String("getblockheader Unmarshal ", fmt.Sprint(block.Height)+" "+err.Error()))
continue
}
rawmsgs_stats := make([]json.RawMessage, 1)
rawmsgs_stats[0] = json.RawMessage(param_str)
result_stats, err := gbt.GbtCtx.Client.RawRequest("getblockstats", rawmsgs_stats)
if err != nil {
//log.Printf("getblockstats %s", err.Error())
logg.Error("[gbt]", zap.String("getblockstats", err.Error()))
continue
}
//log.Printf("getblockheader %d %s:%v", block.Height, block_hash, result)
var blockStats GetBlockStatsMsg
err = json.Unmarshal(result_stats, &blockStats)
if err != nil {
//log.Printf("getblockstats Unmarshal %s", err.Error())
logg.Error("[gbt]", zap.String("getblockstats Unmarshal ", fmt.Sprint(block.Height)+" "+err.Error()))
continue
}
if blockHeader.Confirmations > 3 {
//log.Printf("cmp block: %d %s vs %s %s", block.Height, block.Nonce, string(result), blockHeader.Nonce)
//log.Printf("cmp block: %d %s %s_%s_%s vs %s\n", block.Height, block.Nonce, block.User, block.Miner, block.MinerId, blockHeader.Nonce)
if blockHeader.Nonce == block.Nonce {
block_height := int64(block.Height)
/*dbif.NotifyMinerSuccess(gbt.GbtCtx, block.User, block.Miner, block.MinerId, block_height, "", block.Nonce, int64(block.SubIdx), blockStats.Subsidy, blockStats.Totalfee)
dbif.NotifyUsersBlkStatsSuccess(gbt.GbtCtx, block.User, block_height, "", block.Nonce, int64(block.SubIdx), blockStats.Subsidy, blockStats.Totalfee)*/
dbif.NotifyPoolBlkStatsSuccess(gbt.GbtCtx, block_height, "", block.Nonce, int64(block.SubIdx), blockStats.Subsidy, blockStats.Totalfee)
dbif.NotifyBlkDetailSuccess(gbt.GbtCtx, block_height, "", block.Nonce, int64(block.SubIdx))
/*dbif.NotifyBlockStat(gbt.GbtCtx, block.User, block.Miner, block.MinerId, blockStats.Subsidy, blockStats.Totalfee)*/
//dbif.NotifyBlkNewSuccess(gbt.GbtCtx, block_height, "", block.Nonce, -1)
dbif.NotifyBlkNewDb(gbt.GbtCtx, block_height, block.Hash, true, block.Nonce, int64(block.SubIdx))
//gbt.GbtCtx.Blocks += 1
//cache.StorePoolCache(gbt.GbtCtx.RedisClient, gbt.GbtCtx.Coin, "blocks", gbt.GbtCtx.Blocks)
//gbt.GbtCtx.Reward += blockStats.Subsidy
//cache.StorePoolCache(gbt.GbtCtx.RedisClient, gbt.GbtCtx.Coin, "reward", gbt.GbtCtx.Reward)
//gbt.GbtCtx.Fee += blockStats.Totalfee
//cache.StorePoolCache(gbt.GbtCtx.RedisClient, gbt.GbtCtx.Coin, "fee", gbt.GbtCtx.Fee)
/*var pushmsg PushBlkNewMsg
pushmsg.Coin = gbt.GbtCtx.Coin
pushmsg.Height = block.Height
pushmsg.Nonce = block.Nonce
jsonData, err := json.Marshal(pushmsg)
if err != nil {
//log.Printf("Failed to marshal JSON: %v", err)
logg.Error("[gbt]", zap.String("Failed to marshal JSON:", err.Error()))
continue
}
if gbt.GbtCtx.PushCh == nil {
gbt.GbtCtx.PushCh = utility.InitZmqPush(gbt.GbtCtx.Config.Profit.Push)
}
if gbt.GbtCtx.PushCh != nil {
err = gbt.GbtCtx.PushCh.SendMessage([][]byte{[]byte("blk_new"), jsonData})
if err != nil {
//log.Printf("Failed to send data: %v", err)
logg.Error("[gbt]", zap.String("Failed to SendMessage:", err.Error()))
continue
}
}*/
updateSQL := `UPDATE blocks SET checked = 1 WHERE height = ? AND nonce = ? AND checked = 0`
_, err = db.Exec(updateSQL, block.Height, block.Nonce)
if err != nil {
//log.Printf("Error updating blk_new: %v", err)
logg.Error("[gbt]", zap.String("Error updating blk_new:", err.Error()))
continue
}
//log.Printf("update block success: %d %s", block.Height, block.Nonce)
logg.Warn("[gbt]", zap.String("update block success:", fmt.Sprint(block.Height)+" "+block.Nonce))
}
}
}
}
func get_gbt_msg(gbt *GbtNexaContext) []byte {
height, err := gbt.GbtCtx.Client.GetBlockCount()
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockCount ", err.Error()))
return nil
}
height = height + 1
rawmsgs := make([]json.RawMessage, 3)
param_str1 := `"` + "1000" + `"`
param_str2 := `"` + gbt.Config.Nexa.Addr + `"`
if len(gbt.GbtCtx.MinerAddrs) > 0 {
param_str2 = `"` + gbt.GbtCtx.MinerAddrs[gbt.GbtCtx.MinerAddrIndex] + `"`
gbt.GbtCtx.MinerAddrIndex = gbt.GbtCtx.MinerAddrIndex + 1
if gbt.GbtCtx.MinerAddrIndex >= len(gbt.GbtCtx.MinerAddrs) {
gbt.GbtCtx.MinerAddrIndex = 0
}
}
param_str3 := `"` + " / m2pool.com / " + `"`
//logg.Debug("[gbt]", zap.String("option", param_str))
rawmsgs[0] = json.RawMessage(param_str1)
rawmsgs[1] = json.RawMessage(param_str2)
rawmsgs[2] = json.RawMessage(param_str3)
result, err := gbt.GbtCtx.Client.RawRequest("getminingcandidate", rawmsgs)
//log.Printf("[gbt] getminingcandidate %v %s\n", err, result)
if err != nil {
logg.Error("[gbt]", zap.String("getminingcandidate", err.Error()))
return nil
}
var rxmsg GbtNexaMsg
err = json.Unmarshal(result, &rxmsg)
if err != nil {
logg.Error("[gbt]", zap.String("getminingcandidate", err.Error()))
return nil
}
gbtstr := fmt.Sprintf("[gbt] height %d, id %d, header %s, nBits %s", height, rxmsg.Id, rxmsg.HeaderCommitment, rxmsg.NBits)
//logg.Debug("[gbt]", zap.String(" ", gbtstr))
if rxmsg.Id == gbt.last_gbt.Id {
return nil
}
gbt.last_gbt = rxmsg
gbt.last_time = time.Now()
nbits_b, _ := hex.DecodeString(rxmsg.NBits)
var nbits_i uint32 = binary.BigEndian.Uint32(nbits_b)
bigdiff := utility.CompactToBig(nbits_i)
targetdiff := fmt.Sprintf("%064x", bigdiff.Bytes())
//logg.Debug("[gbt]", zap.String("target", targetdiff))
logg.Debug("[gbt]", zap.String(" ", gbtstr), zap.String("target", targetdiff))
var job msg.NexaStratumJob
job.Id = rxmsg.Id
job.Header = utility.Reverse_string(rxmsg.HeaderCommitment)
job.NBits = rxmsg.NBits
job.CurTime = uint64(time.Now().Unix())
job.Height = uint32(height)
job.Nonce = ""
job.Target = targetdiff
job.Extranonce1 = ""
job.Extranonce2_size = 8
job.Extranonce2 = ""
body, err := json.Marshal(job)
if err != nil {
logg.Error("[gbt]", zap.String("failed to Marshal jobmsg", err.Error()))
return nil
}
return body
}
func gbt_notify_running(gbt *GbtNexaContext) {
for {
if !gbt.GbtCtx.Started {
break
}
if gbt.GbtCtx.NodeSubCh == nil {
gbt.GbtCtx.NodeSubCh = utility.InitZmqSub(gbt.GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
}
if gbt.GbtCtx.NodeSubCh != nil {
cmsg_sub, err := gbt.GbtCtx.NodeSubCh.RecvMessage()
if err != nil {
if !gbt.GbtCtx.Started {
break
}
gbt.GbtCtx.NodeSubCh.SetSubscribe(utility.BITCOIND_ZMQ_HASHBLOCK)
gbt.GbtCtx.NodeSubCh.Connect(gbt.GbtCtx.Config.Rpc.ZmqSub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "hashblock" {
GbtNexaCtx.new_block_index = GbtNexaCtx.new_block_index + 1
//log.Println("gbt_notify_running", hex.EncodeToString(cmsg_sub[1]), GbtNexaCtx.new_block_index)
gbt.new_block_chan <- GbtNexaCtx.new_block_index
}
}
} else {
logg.Error("[gbt]", zap.String("notify", "NodeSubCh fail!"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
func gbt_running(gbt *GbtNexaContext) {
gbtmsg := get_gbt_msg(gbt)
if gbtmsg != nil {
if gbt.GbtCtx.PubCh == nil {
gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
}
if gbt.GbtCtx.PubCh != nil {
for trycnt := 0; trycnt < 3; trycnt++ {
err := gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobnexa"), gbtmsg})
if err != nil {
if !gbt.GbtCtx.Started {
return
}
//gbt.GbtCtx.PubCh.Bind(gbt.GbtCtx.Config.Zmq.Pub)
logg.Warn("[gbt]", zap.String("job ", err.Error()))
} else {
//gbt.GbtCtx.PubCh.SendChan <- [][]byte{[]byte("jobnexa"), gbtmsg}
logg.Warn("[gbt]", zap.String("job ", "sent"))
break
}
}
//gbt.GbtCtx.AlivingChan <- true
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
} else {
logg.Warn("[gbt]", zap.String("job ", "sent failed! PubCh nil"))
}
} else {
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
}
timer := time.NewTimer(time.Duration(gbt.GbtCtx.Config.Rpc.Timeout) * time.Millisecond)
defer timer.Stop()
for {
if !gbt.GbtCtx.Started {
break
}
new_block_notify := false
select {
case blk_idx := <-gbt.new_block_chan:
log.Println("new block chan", blk_idx)
new_block_notify = true
if !timer.Stop() {
<-timer.C
}
timer.Reset(time.Duration(gbt.GbtCtx.Config.Rpc.Timeout) * time.Millisecond)
case <-gbt.GbtCtx.ExitGbtChan:
logg.Error("[gbt]", zap.String("gbt", "exit"))
return
case <-time.After(time.Duration(gbt.GbtCtx.Config.Rpc.Timeout) * time.Millisecond):
log.Println("poll gbt timeout")
timer.Reset(time.Duration(gbt.GbtCtx.Config.Rpc.Timeout) * time.Millisecond)
}
/*if check_bestblockhash(gbt) {*/
gbtmsg := get_gbt_msg(gbt)
if gbtmsg != nil {
//check_preblock(gbt, DbCtx)
if gbt.GbtCtx.PubCh == nil {
gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
}
if gbt.GbtCtx.PubCh != nil {
for trycnt := 0; trycnt < 3; trycnt++ {
err := gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobnexa"), gbtmsg})
if err != nil {
logg.Warn("[gbt]", zap.String("job ", err.Error()))
continue
} else {
//gbt.GbtCtx.PubCh.SendChan <- [][]byte{[]byte("jobnexa"), gbtmsg}
logg.Warn("[gbt]", zap.String("job ", "sent"))
break
}
}
//gbt.GbtCtx.AlivingChan <- true
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
} else {
logg.Warn("[gbt]", zap.String("job ", "sent failed! PubCh nil"))
}
} else {
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
}
if new_block_notify {
update_block_confirm(gbt)
}
}
}
func nexaInit(config *NexaConfig) {
data, err := ioutil.ReadFile("gbt.conf")
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {
GbtNexaCtx.GbtCtx = GbtCtx
GbtNexaCtx.last_height = 0
nexaInit(&GbtNexaCtx.Config)
GbtNexaCtx.Target = make([]byte, 32)
GbtNexaCtx.Header = make([]byte, 49)
GbtNexaCtx.last_time = time.Now()
logg = GbtCtx.Log
GbtNexaCtx.new_block_chan = make(chan int, 256)
GbtNexaCtx.new_block_index = 0
logg.Info("[gbt]", zap.String("gbt_nexa_version", GBT_NEXA_VERSION))
rawmsgs := make([]json.RawMessage, 1)
pool_tag := " / m2pool.com / "
param_str := `"` + pool_tag + `"`
rawmsgs[0] = json.RawMessage(param_str)
_, err := GbtNexaCtx.GbtCtx.Client.RawRequest("setminercomment", rawmsgs)
if err != nil {
//log.Printf("setminercomment %s", err.Error())
logg.Error("[gbt]", zap.String("setminercomment", err.Error()))
}
}
func Start() {
go gbt_running(&GbtNexaCtx)
go gbt_notify_running(&GbtNexaCtx)
go submit_block_running(&GbtNexaCtx)
}
func Stop() {
defer close(GbtNexaCtx.new_block_chan)
}
func new_block_into_db(block *GbtNexaContext, user string, miner string, minerid string, height int64, nonce string, hash string, subidx int64) bool {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
log.Printf("Error opening database: %v", err)
return false
}
defer db.Close()
createTableSQL := `
CREATE TABLE IF NOT EXISTS blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
miner TEXT NOT NULL,
minerid TEXT NOT NULL,
height INTEGER,
nonce TEXT NOT NULL,
hash TEXT NOT NULL,
subidx INTEGER,
checked INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Printf("Error creating table: %v", err)
return false
}
insertSQL := `INSERT INTO blocks (user, miner, minerid, height, nonce, checked, hash, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
_, err = db.Exec(insertSQL, user, miner, minerid, height, nonce, 0, hash, subidx)
if err != nil {
log.Printf("Error inserting data from blocks %s: %v", fmt.Sprint(height), err)
return false
}
return true
}
func submit_block_running(block *GbtNexaContext) {
logg.Info("[block]", zap.String("submit_block_running", "Start."))
for {
if !block.GbtCtx.Started {
break
}
if block.GbtCtx.SubCh == nil {
block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
}
if block.GbtCtx.SubCh != nil {
cmsg_sub, err := block.GbtCtx.SubCh.RecvMessage()
if err != nil {
if !block.GbtCtx.Started {
break
}
time.Sleep(time.Duration(1) * time.Second)
/*block.GbtCtx.SubCh.Destroy()
block.GbtCtx.SubCh = nil*/
block.GbtCtx.SubCh.SetSubscribe("blk" + block.GbtCtx.Coin)
block.GbtCtx.SubCh.Connect(block.GbtCtx.Config.Zmq.Sub)
//block.GbtCtx.SubCh.Destroy()
//block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
continue
}
//log.Println(cmsg_sub, len(cmsg_sub), block.GbtCtx.SubCh)
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "blknexa" {
cmsg := cmsg_sub[1]
//block data
msgb := make([]byte, len(cmsg)-16)
copy(msgb, cmsg)
//height
//heightb := make([]byte, 4)
heightb, err := hex.DecodeString(string(cmsg[len(msgb) : len(msgb)+8]))
if err != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to decode height", err.Error()))
continue
}
var height uint32 = utility.ByteToUint32(heightb)
logg.Warn("[block]", zap.Uint32("height", height))
if height <= block.last_height {
continue
}
block.last_height = height
//index
//indexb := make([]byte, 4)
indexb, err1 := hex.DecodeString(string(cmsg[len(msgb)+8:]))
if err1 != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to decode index", err1.Error()))
continue
}
//copy(indexb, cmsg.Value[len(msgb)+4:])
var index uint32 = utility.ByteToUint32(indexb)
logg.Warn("[block]", zap.Uint32("index", index))
logg.Debug("[block]", zap.String("msg", string(cmsg)), zap.String("blk", string(msgb)))
var nexablock msg.BlockNexaMsg
if err := json.Unmarshal(msgb, &nexablock); err != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to Unmarshal job", err.Error()))
continue
}
blk := fmt.Sprintf(`{"id":%d,"nonce":"%s"}`, nexablock.Id, nexablock.Nonce)
rawmsgs := make([]json.RawMessage, 1)
logg.Info("[block]", zap.String("blk", blk))
rawmsgs[0] = json.RawMessage(blk)
//var last_result json.RawMessage
//for i := 0; i < len(block.Client); i++ {
result, err := block.GbtCtx.Client.RawRequest("submitminingsolution", rawmsgs)
if err != nil {
logg.Error("[block]", zap.String("submitminingsolution", err.Error()))
} else {
//last_result = result
}
logg.Info("[block]", zap.String("result", string(result)))
//}
/*dbif.NotifyMinerSubmitResult(block.GbtCtx, nexablock.User, nexablock.Miner, nexablock.Index, int64(height), nexablock.Pow, string(result), nexablock.Nonce, nexablock.SubIdx)
dbif.NotifyUsersBlkStatsSubmitResult(block.GbtCtx, nexablock.User, int64(height), nexablock.Pow, string(result), nexablock.Nonce, nexablock.SubIdx)*/
dbif.NotifyPoolBlkStatsSubmitResult(block.GbtCtx, int64(height), nexablock.Pow, string(result), nexablock.Nonce, nexablock.SubIdx)
block.Submits += 1
//log.Printf("[block] height %d subidx %d nonce %s\n", height, nexablock.SubIdx, nexablock.Nonce)
logg.Warn("[block]", zap.Float64("total submits", block.Submits), zap.Int64("SubIdx", nexablock.SubIdx))
new_block_into_db(block, nexablock.User, nexablock.Miner, nexablock.Index, int64(height), nexablock.Nonce, nexablock.Pow, nexablock.SubIdx)
}
}
} else {
logg.Error("[block]", zap.String("block", "SubCh failed! retry"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,600 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "types.proto";
import "transaction.proto";
import "block.proto";
import "network.proto";
import "sidechain_types.proto";
package tari.rpc;
// The gRPC interface for interacting with the base node.
service BaseNode {
// Lists headers in the current best chain
rpc ListHeaders(ListHeadersRequest) returns (stream BlockHeaderResponse);
// Get header by hash
rpc GetHeaderByHash(GetHeaderByHashRequest) returns (BlockHeaderResponse);
// Returns blocks in the current best chain. Currently only supports querying by height
rpc GetBlocks(GetBlocksRequest) returns (stream HistoricalBlock);
// Returns the block timing for the chain heights
rpc GetBlockTiming(HeightRequest) returns (BlockTimingResponse);
// Returns the network Constants
rpc GetConstants(BlockHeight) returns (ConsensusConstants);
// Returns Block Sizes
rpc GetBlockSize (BlockGroupRequest) returns (BlockGroupResponse);
// Returns Block Fees
rpc GetBlockFees (BlockGroupRequest) returns (BlockGroupResponse);
// Get Version
rpc GetVersion(Empty) returns (StringValue);
// Check for new updates
rpc CheckForUpdates(Empty) returns (SoftwareUpdate);
// Get coins in circulation
rpc GetTokensInCirculation(GetBlocksRequest) returns (stream ValueAtHeightResponse);
// Get network difficulties
rpc GetNetworkDifficulty(HeightRequest) returns (stream NetworkDifficultyResponse);
// Get the block template
rpc GetNewBlockTemplate(NewBlockTemplateRequest) returns (NewBlockTemplateResponse);
// Construct a new block from a provided template
rpc GetNewBlock(NewBlockTemplate) returns (GetNewBlockResult);
// Construct a new block from a provided template
rpc GetNewBlockWithCoinbases(GetNewBlockWithCoinbasesRequest) returns (GetNewBlockResult);
// Construct a new block from a provided template
rpc GetNewBlockTemplateWithCoinbases(GetNewBlockTemplateWithCoinbasesRequest) returns (GetNewBlockResult);
// Construct a new block and header blob from a provided template
rpc GetNewBlockBlob(NewBlockTemplate) returns (GetNewBlockBlobResult);
// Submit a new block for propagation
rpc SubmitBlock(Block) returns (SubmitBlockResponse);
// Submit a new mined block blob for propagation
rpc SubmitBlockBlob(BlockBlobRequest) returns (SubmitBlockResponse);
// Submit a transaction for propagation
rpc SubmitTransaction(SubmitTransactionRequest) returns (SubmitTransactionResponse);
// Get the base node sync information
rpc GetSyncInfo(Empty) returns (SyncInfoResponse);
// Get the base node sync information
rpc GetSyncProgress(Empty) returns (SyncProgressResponse);
// Get the base node tip information
rpc GetTipInfo(Empty) returns (TipInfoResponse);
// Search for blocks containing the specified kernels
rpc SearchKernels(SearchKernelsRequest) returns (stream HistoricalBlock);
// Search for blocks containing the specified commitments
rpc SearchUtxos(SearchUtxosRequest) returns (stream HistoricalBlock);
// Fetch any utxos that exist in the main chain
rpc FetchMatchingUtxos(FetchMatchingUtxosRequest) returns (stream FetchMatchingUtxosResponse);
// get all peers from the base node
rpc GetPeers(GetPeersRequest) returns (stream GetPeersResponse);
rpc GetMempoolTransactions(GetMempoolTransactionsRequest) returns (stream GetMempoolTransactionsResponse);
rpc TransactionState(TransactionStateRequest) returns (TransactionStateResponse);
// This returns the node's network identity
rpc Identify (Empty) returns (NodeIdentity);
// Get Base Node network connectivity status
rpc GetNetworkStatus(Empty) returns (NetworkStatusResponse);
// List currently connected peers
rpc ListConnectedPeers(Empty) returns (ListConnectedPeersResponse);
// Get mempool stats
rpc GetMempoolStats(Empty) returns (MempoolStatsResponse);
// Get VNs
rpc GetActiveValidatorNodes(GetActiveValidatorNodesRequest) returns (stream GetActiveValidatorNodesResponse);
rpc GetShardKey(GetShardKeyRequest) returns (GetShardKeyResponse);
// Get templates
rpc GetTemplateRegistrations(GetTemplateRegistrationsRequest) returns (stream GetTemplateRegistrationResponse);
rpc GetSideChainUtxos(GetSideChainUtxosRequest) returns (stream GetSideChainUtxosResponse);
rpc GetNetworkState(GetNetworkStateRequest) returns (GetNetworkStateResponse);
// PayRef (Payment Reference) lookup for block explorers and external services
rpc SearchPaymentReferences(SearchPaymentReferencesRequest) returns (stream PaymentReferenceResponse);
}
message GetAssetMetadataRequest {
bytes asset_public_key = 1;
}
message GetAssetMetadataResponse {
string name = 2;
string description =3;
string image = 4;
bytes owner_commitment = 5;
OutputFeatures features = 6;
uint64 mined_height = 7;
bytes mined_in_block = 8;
}
message ListAssetRegistrationsRequest {
uint64 offset = 2;
uint64 count = 3;
}
message ListAssetRegistrationsResponse {
bytes asset_public_key = 1;
bytes unique_id = 2;
bytes owner_commitment = 3;
uint64 mined_height = 4;
bytes mined_in_block = 5;
OutputFeatures features = 6;
bytes script = 7;
}
message GetTokensRequest {
bytes asset_public_key = 1;
// Optionally get a set of specific unique_ids
repeated bytes unique_ids = 2;
}
message GetTokensResponse {
bytes unique_id = 1;
bytes asset_public_key = 2;
bytes owner_commitment = 3;
bytes mined_in_block = 4;
uint64 mined_height = 5;
OutputFeatures features = 6;
bytes script = 7;
}
message SubmitBlockResponse {
bytes block_hash = 1;
}
message BlockBlobRequest{
bytes header_blob = 1;
bytes body_blob = 2;
}
/// return type of GetTipInfo
message TipInfoResponse {
MetaData metadata = 1;
bool initial_sync_achieved = 2;
BaseNodeState base_node_state = 3;
bool failed_checkpoints = 4;
}
enum BaseNodeState{
START_UP = 0;
HEADER_SYNC = 1;
HORIZON_SYNC = 2;
CONNECTING = 3;
BLOCK_SYNC = 4;
LISTENING = 5;
SYNC_FAILED = 6;
}
/// return type of GetNewBlockTemplate
message NewBlockTemplateResponse {
NewBlockTemplate new_block_template = 1;
bool initial_sync_achieved = 3;
MinerData miner_data = 4;
}
/// return type of NewBlockTemplateRequest
message NewBlockTemplateRequest{
PowAlgo algo = 1;
//This field should be moved to optional once optional keyword is standard
uint64 max_weight = 2;
}
/// return type of NewBlockTemplateRequest
message GetNewBlockTemplateWithCoinbasesRequest{
PowAlgo algo = 1;
//This field should be moved to optional once optional keyword is standard
uint64 max_weight = 2;
repeated NewBlockCoinbase coinbases = 3;
}
/// request type of GetNewBlockWithCoinbasesRequest
message GetNewBlockWithCoinbasesRequest{
NewBlockTemplate new_template = 1;
repeated NewBlockCoinbase coinbases = 2;
}
message NewBlockCoinbase{
string address = 1;
uint64 value = 2;
bool stealth_payment= 3;
bool revealed_value_proof= 4;
bytes coinbase_extra =5;
}
// Network difficulty response
message NetworkDifficultyResponse {
uint64 difficulty = 1;
uint64 estimated_hash_rate = 2;
uint64 height = 3;
uint64 timestamp = 4;
uint64 pow_algo = 5;
uint64 sha3x_estimated_hash_rate = 6;
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
uint64 num_coinbases = 8;
repeated bytes coinbase_extras = 9;
}
// A generic single value response for a specific height
message ValueAtHeightResponse {
// uint64 circulating_supply = 1; // No longer used
// uint64 spendable_supply = 2; // No longer used
uint64 height = 3;
uint64 mined_rewards = 4;
uint64 spendable_rewards = 5;
uint64 spendable_pre_mine = 6;
uint64 total_spendable = 7;
}
// A generic uint value
message IntegerValue {
uint64 value = 1;
}
// A generic String value
message StringValue {
string value = 1;
}
/// GetBlockSize / GetBlockFees Request
/// Either the starting and ending heights OR the from_tip param must be specified
message BlockGroupRequest {
// The height from the chain tip (optional)
uint64 from_tip = 1;
// The starting height (optional)
uint64 start_height = 2;
// The ending height (optional)
uint64 end_height = 3;
/// The type of calculation required (optional)
/// Defaults to median
/// median, mean, quartile, quantile
CalcType calc_type = 4;
}
/// GetBlockSize / GetBlockFees Response
message BlockGroupResponse {
repeated double value = 1;
CalcType calc_type = 2;
}
enum CalcType {
MEAN = 0;
MEDIAN = 1;
QUANTILE = 2;
QUARTILE = 3;
}
// The request used for querying a function that requires a height, either between 2 points or from the chain tip
// If start_height and end_height are set and > 0, they take precedence, otherwise from_tip is used
message HeightRequest {
// The height from the chain tip (optional)
uint64 from_tip = 1;
// The starting height (optional)
uint64 start_height = 2;
// The ending height (optional)
uint64 end_height = 3;
}
// The return type of the rpc GetBlockTiming
message BlockTimingResponse {
uint64 max = 1;
uint64 min = 2;
double avg = 3;
}
// Request that returns a header based by hash
message GetHeaderByHashRequest {
// The hash of the block header
bytes hash = 1;
}
message BlockHeaderResponse {
// The block header
BlockHeader header = 1;
// The number of blocks from the tip of this block (a.k.a depth)
uint64 confirmations = 2;
// The block reward i.e mining reward + fees
uint64 reward = 3;
// Achieved difficulty
uint64 difficulty = 4;
// The number of transactions contained in the block
uint32 num_transactions = 5;
}
// The request used for querying headers from the base node. The parameters `from_height` and `num_headers` can be used
// to page through the current best chain.
message ListHeadersRequest {
// The height to start at. Depending on sorting, will either default to use the tip or genesis block, for `SORTING_DESC`
// and `SORTING_ASC` respectively, if a value is not provided. The first header returned will be at this height
// followed by `num_headers` - 1 headers in the direction specified by `sorting`. If greater than the current tip,
// the current tip will be used.
uint64 from_height = 1;
// The number of headers to return. If not specified, it will default to 10
uint64 num_headers = 2;
// The ordering to return the headers in. If not specified will default to SORTING_DESC. Note that if `from_height`
// is not specified or is 0, if `sorting` is SORTING_DESC, the tip will be used as `from_height`, otherwise the
// block at height 0 will be used.
Sorting sorting = 3;
}
// The request used for querying blocks in the base node's current best chain. Currently only querying by height is
// available. Multiple blocks may be queried.e.g. [189092,100023,122424]. The order in which they are returned is not
// guaranteed.
message GetBlocksRequest {
repeated uint64 heights = 1;
}
// The return type of the rpc GetBlocks. Blocks are not guaranteed to be returned in the order requested.
message GetBlocksResponse {
repeated HistoricalBlock blocks = 1;
}
enum Sorting {
SORTING_DESC = 0;
SORTING_ASC = 1;
}
message MetaData {
// The current chain height, or the block number of the longest valid chain, or `None` if there is no chain
uint64 best_block_height = 1;
// The block hash of the current tip of the longest valid chain, or `None` for an empty chain
bytes best_block_hash = 2;
// The current geometric mean of the pow of the chain tip, or `None` if there is no chain
bytes accumulated_difficulty = 5;
// This is the min height this node can provide complete blocks for. A 0 here means this node is archival and can provide complete blocks for every height.
uint64 pruned_height = 6;
uint64 timestamp = 7;
}
message SyncInfoResponse {
uint64 tip_height = 1;
uint64 local_height = 2;
repeated bytes peer_node_id = 3;
}
message SyncProgressResponse {
uint64 tip_height = 1;
uint64 local_height = 2;
SyncState state = 3;
string short_desc = 4;
uint64 initial_connected_peers = 5;
}
enum SyncState {
STARTUP = 0;
HEADER_STARTING = 1;
HEADER = 2;
BLOCK_STARTING = 3;
BLOCK = 4;
DONE = 5;
}
// This is the message that is returned for a miner after it asks for a new block.
message GetNewBlockResult{
// This is the header hash of the completed block
bytes block_hash = 1;
// This is the completed block
Block block = 2;
bytes merge_mining_hash =3;
bytes tari_unique_id =4;
MinerData miner_data = 5;
bytes vm_key = 6;
}
// This is the message that is returned for a miner after it asks for a new block.
message GetNewBlockBlobResult{
// This is the header hash of the completed block
bytes block_hash = 1;
// This is the completed block's header
bytes header = 2;
// This is the completed block's body
bytes block_body = 3;
bytes merge_mining_hash =4;
bytes utxo_mr = 5;
bytes tari_unique_id =6;
}
// This is mining data for the miner asking for a new block
message MinerData{
PowAlgo algo = 1;
uint64 target_difficulty = 2;
uint64 reward = 3;
// bytes merge_mining_hash =4;
uint64 total_fees = 5;
}
// This is the request type for the Search Kernels rpc
message SearchKernelsRequest{
repeated Signature signatures = 1;
}
// This is the request type for the Search Utxo rpc
message SearchUtxosRequest{
repeated bytes commitments = 1;
}
message FetchMatchingUtxosRequest {
repeated bytes hashes = 1;
}
message FetchMatchingUtxosResponse {
TransactionOutput output = 1;
}
// This is the request type of the get all peers rpc call
message GetPeersResponse{
Peer peer = 1;
}
message GetPeersRequest{}
message SubmitTransactionRequest {
Transaction transaction = 1;
}
message SubmitTransactionResponse {
SubmitTransactionResult result =1;
}
enum SubmitTransactionResult {
NONE = 0;
ACCEPTED = 1;
NOT_PROCESSABLE_AT_THIS_TIME = 2;
ALREADY_MINED = 3;
REJECTED = 4;
}
message GetMempoolTransactionsRequest {
}
message GetMempoolTransactionsResponse {
Transaction transaction = 1;
}
message TransactionStateRequest {
Signature excess_sig = 1;
}
message TransactionStateResponse {
TransactionLocation result =1;
}
enum TransactionLocation {
UNKNOWN = 0;
MEMPOOL = 1;
MINED = 2;
NOT_STORED = 3;
}
message MempoolStatsResponse {
uint64 unconfirmed_txs = 2;
uint64 reorg_txs = 3;
uint64 unconfirmed_weight = 4;
}
message GetActiveValidatorNodesRequest {
uint64 height = 1;
}
message GetActiveValidatorNodesResponse {
bytes shard_key = 1;
bytes public_key = 2;
}
message GetShardKeyRequest {
uint64 height = 1;
bytes public_key = 2;
}
message GetShardKeyResponse {
bytes shard_key = 1;
bool found = 2;
}
message GetTemplateRegistrationsRequest {
bytes start_hash = 1;
uint64 count = 2;
}
message GetTemplateRegistrationResponse {
bytes utxo_hash = 1;
TemplateRegistration registration = 2;
}
message BlockInfo {
uint64 height = 1;
bytes hash = 2;
bytes next_block_hash = 3;
}
message GetSideChainUtxosRequest {
bytes start_hash = 1;
uint64 count = 2;
}
message GetSideChainUtxosResponse {
BlockInfo block_info = 1;
repeated TransactionOutput outputs = 2;
}
message GetNetworkStateRequest {
}
message GetNetworkStateResponse {
// metadata
MetaData metadata = 1;
// has the base node synced
bool initial_sync_achieved = 2;
//current state of the base node
BaseNodeState base_node_state = 3;
// do we have failed checkpoints
bool failed_checkpoints = 4;
// The block reward of the next tip
uint64 reward = 5;
// estimate sha3x hash rate
uint64 sha3x_estimated_hash_rate = 6;
// estimate randomx hash rate
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
// number of connections
uint64 num_connections = 8;
//liveness results
repeated LivenessResult liveness_results = 9;
}
message LivenessResult{
// node id
bytes peer_node_id = 1;
// time to discover
uint64 discover_latency = 2;
// Dial latency
uint64 ping_latency = 3;
}
// PayRef (Payment Reference) search and lookup messages
// Request to search for outputs by payment reference
message SearchPaymentReferencesRequest {
// Payment reference as hex string (64 characters)
repeated string payment_reference_hex = 1;
repeated bytes payment_reference_bytes = 2;
// Optional: include spent outputs in results
bool include_spent = 3;
}
// Response containing payment reference match
message PaymentReferenceResponse {
// The payment reference that was found
string payment_reference_hex = 1;
// Block height where the output was mined
uint64 block_height = 2;
// Block hash where the output was mined
bytes block_hash = 3;
// Timestamp when the output was mined
uint64 mined_timestamp = 4;
// Output commitment (32 bytes)
bytes commitment = 5;
// Whether this output has been spent
bool is_spent = 6;
// Height where output was spent (if spent)
uint64 spent_height = 7;
// Block hash where output was spent (if spent)
bytes spent_block_hash = 8;
// Transaction output amount will be 0 for non set a
uint64 min_value_promise = 9;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "transaction.proto";
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
message BlockHeader {
// The hash of the block
bytes hash = 1;
// Version of the block
uint32 version = 2;
// Height of this block since the genesis block (height 0)
uint64 height = 3;
// Hash of the block previous to this in the chain.
bytes prev_hash = 4;
// Timestamp at which the block was built.
uint64 timestamp = 5;
// This is the UTXO merkle root of the outputs in the blockchain
bytes output_mr = 6;
// This is the merkle root of all outputs in this block
bytes block_output_mr = 7;
// This is the MMR root of the kernels
bytes kernel_mr = 8;
// This is the Merkle root of the inputs in this block
bytes input_mr = 9;
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
bytes total_kernel_offset = 10;
// Nonce increment used to mine this block.
uint64 nonce = 11;
// Proof of work metadata
ProofOfWork pow = 12;
// Kernel MMR size
uint64 kernel_mmr_size = 13;
// Output MMR size
uint64 output_mmr_size = 14;
// Sum of script offsets for all kernels in this block.
bytes total_script_offset = 15;
// Merkle root of validator nodes
bytes validator_node_mr = 16;
// Validator size
uint64 validator_node_size = 17;
}
// The proof of work data structure that is included in the block header.
message ProofOfWork {
// The algorithm used to mine this block
// 0 = Monero
// 1 = Sha3X
uint64 pow_algo = 1;
// Supplemental proof of work data. For example for Sha3x, this would be empty (only the block header is
// required), but for Monero merge mining we need the Monero block header and RandomX seed hash.
bytes pow_data = 4;
}
//This is used to request the which pow algo should be used with the block template
message PowAlgo {
// The permitted pow algorithms
enum PowAlgos {
POW_ALGOS_RANDOMXM = 0; // Accessible as `grpc::pow_algo::PowAlgos::RandomxM`
POW_ALGOS_SHA3X = 1; // Accessible as `grpc::pow_algo::PowAlgos::Sha3x`
POW_ALGOS_RANDOMXT = 2; // Accessible as `grpc::pow_algo::PowAlgos::RandomxT`
}
// The pow algo to use
PowAlgos pow_algo = 1;
}
// A Minotari block. Blocks are linked together into a blockchain.
message Block {
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
BlockHeader header = 1;
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// blocks consist of inputs, outputs and kernels, rather than transactions.
AggregateBody body = 2;
}
// The representation of a historical block in the blockchain. It is essentially identical to a protocol-defined
// block but contains some extra metadata that clients such as Block Explorers will find interesting.
message HistoricalBlock {
// The number of blocks that have been mined since this block, including this one. The current tip will have one
// confirmation.
uint64 confirmations = 1;
// The underlying block
Block block = 2;
}
// The NewBlockHeaderTemplate is used for the construction of a new mine-able block. It contains all the metadata for the block that the Base Node is able to complete on behalf of a Miner.
message NewBlockHeaderTemplate {
// Version of the block
uint32 version = 1;
// Height of this block since the genesis block (height 0)
uint64 height = 2;
// Hash of the block previous to this in the chain.
bytes prev_hash = 3;
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
bytes total_kernel_offset = 4;
// Proof of work metadata
ProofOfWork pow = 5;
// Sum of script offsets for all kernels in this block.
bytes total_script_offset = 7;
}
// The new block template is used constructing a new partial block, allowing a miner to added the coinbase utxo and as a final step the Base node to add the MMR roots to the header.
message NewBlockTemplate {
// The NewBlockHeaderTemplate is used for the construction of a new mineable block. It contains all the metadata for
// the block that the Base Node is able to complete on behalf of a Miner.
NewBlockHeaderTemplate header = 1;
// This flag indicates if the inputs, outputs and kernels have been sorted internally, that is, the sort() method
// has been called. This may be false even if all components are sorted.
AggregateBody body = 2;
// Sometimes the mempool has not synced to the latest tip, this flag indicates if the mempool is out of sync.
// In most cases the next call to get_new_block_template will return a block with the mempool in sync.
bool is_mempool_in_sync = 3;
}

View File

@ -0,0 +1,783 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: block.proto
package block
import (
transaction "pool/internal/gbt/tari/proto/transaction"
reflect "reflect"
sync "sync"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// The permitted pow algorithms
type PowAlgo_PowAlgos int32
const (
PowAlgo_POW_ALGOS_RANDOMXM PowAlgo_PowAlgos = 0 // Accessible as `grpc::pow_algo::PowAlgos::RandomxM`
PowAlgo_POW_ALGOS_SHA3X PowAlgo_PowAlgos = 1 // Accessible as `grpc::pow_algo::PowAlgos::Sha3x`
PowAlgo_POW_ALGOS_RANDOMXT PowAlgo_PowAlgos = 2 // Accessible as `grpc::pow_algo::PowAlgos::RandomxT`
)
// Enum value maps for PowAlgo_PowAlgos.
var (
PowAlgo_PowAlgos_name = map[int32]string{
0: "POW_ALGOS_RANDOMXM",
1: "POW_ALGOS_SHA3X",
2: "POW_ALGOS_RANDOMXT",
}
PowAlgo_PowAlgos_value = map[string]int32{
"POW_ALGOS_RANDOMXM": 0,
"POW_ALGOS_SHA3X": 1,
"POW_ALGOS_RANDOMXT": 2,
}
)
func (x PowAlgo_PowAlgos) Enum() *PowAlgo_PowAlgos {
p := new(PowAlgo_PowAlgos)
*p = x
return p
}
func (x PowAlgo_PowAlgos) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (PowAlgo_PowAlgos) Descriptor() protoreflect.EnumDescriptor {
return file_block_proto_enumTypes[0].Descriptor()
}
func (PowAlgo_PowAlgos) Type() protoreflect.EnumType {
return &file_block_proto_enumTypes[0]
}
func (x PowAlgo_PowAlgos) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use PowAlgo_PowAlgos.Descriptor instead.
func (PowAlgo_PowAlgos) EnumDescriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{2, 0}
}
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
type BlockHeader struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The hash of the block
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
// Version of the block
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
// Height of this block since the genesis block (height 0)
Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
// Hash of the block previous to this in the chain.
PrevHash []byte `protobuf:"bytes,4,opt,name=prev_hash,json=prevHash,proto3" json:"prev_hash,omitempty"`
// Timestamp at which the block was built.
Timestamp uint64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// This is the UTXO merkle root of the outputs in the blockchain
OutputMr []byte `protobuf:"bytes,6,opt,name=output_mr,json=outputMr,proto3" json:"output_mr,omitempty"`
// This is the merkle root of all outputs in this block
BlockOutputMr []byte `protobuf:"bytes,7,opt,name=block_output_mr,json=blockOutputMr,proto3" json:"block_output_mr,omitempty"`
// This is the MMR root of the kernels
KernelMr []byte `protobuf:"bytes,8,opt,name=kernel_mr,json=kernelMr,proto3" json:"kernel_mr,omitempty"`
// This is the Merkle root of the inputs in this block
InputMr []byte `protobuf:"bytes,9,opt,name=input_mr,json=inputMr,proto3" json:"input_mr,omitempty"`
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
TotalKernelOffset []byte `protobuf:"bytes,10,opt,name=total_kernel_offset,json=totalKernelOffset,proto3" json:"total_kernel_offset,omitempty"`
// Nonce increment used to mine this block.
Nonce uint64 `protobuf:"varint,11,opt,name=nonce,proto3" json:"nonce,omitempty"`
// Proof of work metadata
Pow *ProofOfWork `protobuf:"bytes,12,opt,name=pow,proto3" json:"pow,omitempty"`
// Kernel MMR size
KernelMmrSize uint64 `protobuf:"varint,13,opt,name=kernel_mmr_size,json=kernelMmrSize,proto3" json:"kernel_mmr_size,omitempty"`
// Output MMR size
OutputMmrSize uint64 `protobuf:"varint,14,opt,name=output_mmr_size,json=outputMmrSize,proto3" json:"output_mmr_size,omitempty"`
// Sum of script offsets for all kernels in this block.
TotalScriptOffset []byte `protobuf:"bytes,15,opt,name=total_script_offset,json=totalScriptOffset,proto3" json:"total_script_offset,omitempty"`
// Merkle root of validator nodes
ValidatorNodeMr []byte `protobuf:"bytes,16,opt,name=validator_node_mr,json=validatorNodeMr,proto3" json:"validator_node_mr,omitempty"`
// Validator size
ValidatorNodeSize uint64 `protobuf:"varint,17,opt,name=validator_node_size,json=validatorNodeSize,proto3" json:"validator_node_size,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BlockHeader) Reset() {
*x = BlockHeader{}
mi := &file_block_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BlockHeader) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BlockHeader) ProtoMessage() {}
func (x *BlockHeader) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BlockHeader.ProtoReflect.Descriptor instead.
func (*BlockHeader) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{0}
}
func (x *BlockHeader) GetHash() []byte {
if x != nil {
return x.Hash
}
return nil
}
func (x *BlockHeader) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *BlockHeader) GetHeight() uint64 {
if x != nil {
return x.Height
}
return 0
}
func (x *BlockHeader) GetPrevHash() []byte {
if x != nil {
return x.PrevHash
}
return nil
}
func (x *BlockHeader) GetTimestamp() uint64 {
if x != nil {
return x.Timestamp
}
return 0
}
func (x *BlockHeader) GetOutputMr() []byte {
if x != nil {
return x.OutputMr
}
return nil
}
func (x *BlockHeader) GetBlockOutputMr() []byte {
if x != nil {
return x.BlockOutputMr
}
return nil
}
func (x *BlockHeader) GetKernelMr() []byte {
if x != nil {
return x.KernelMr
}
return nil
}
func (x *BlockHeader) GetInputMr() []byte {
if x != nil {
return x.InputMr
}
return nil
}
func (x *BlockHeader) GetTotalKernelOffset() []byte {
if x != nil {
return x.TotalKernelOffset
}
return nil
}
func (x *BlockHeader) GetNonce() uint64 {
if x != nil {
return x.Nonce
}
return 0
}
func (x *BlockHeader) GetPow() *ProofOfWork {
if x != nil {
return x.Pow
}
return nil
}
func (x *BlockHeader) GetKernelMmrSize() uint64 {
if x != nil {
return x.KernelMmrSize
}
return 0
}
func (x *BlockHeader) GetOutputMmrSize() uint64 {
if x != nil {
return x.OutputMmrSize
}
return 0
}
func (x *BlockHeader) GetTotalScriptOffset() []byte {
if x != nil {
return x.TotalScriptOffset
}
return nil
}
func (x *BlockHeader) GetValidatorNodeMr() []byte {
if x != nil {
return x.ValidatorNodeMr
}
return nil
}
func (x *BlockHeader) GetValidatorNodeSize() uint64 {
if x != nil {
return x.ValidatorNodeSize
}
return 0
}
// The proof of work data structure that is included in the block header.
type ProofOfWork struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The algorithm used to mine this block
//
// 0 = Monero
// 1 = Sha3X
PowAlgo uint64 `protobuf:"varint,1,opt,name=pow_algo,json=powAlgo,proto3" json:"pow_algo,omitempty"`
// Supplemental proof of work data. For example for Sha3x, this would be empty (only the block header is
// required), but for Monero merge mining we need the Monero block header and RandomX seed hash.
PowData []byte `protobuf:"bytes,4,opt,name=pow_data,json=powData,proto3" json:"pow_data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProofOfWork) Reset() {
*x = ProofOfWork{}
mi := &file_block_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProofOfWork) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProofOfWork) ProtoMessage() {}
func (x *ProofOfWork) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProofOfWork.ProtoReflect.Descriptor instead.
func (*ProofOfWork) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{1}
}
func (x *ProofOfWork) GetPowAlgo() uint64 {
if x != nil {
return x.PowAlgo
}
return 0
}
func (x *ProofOfWork) GetPowData() []byte {
if x != nil {
return x.PowData
}
return nil
}
// This is used to request the which pow algo should be used with the block template
type PowAlgo struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The pow algo to use
PowAlgo PowAlgo_PowAlgos `protobuf:"varint,1,opt,name=pow_algo,json=powAlgo,proto3,enum=tari.rpc.PowAlgo_PowAlgos" json:"pow_algo,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PowAlgo) Reset() {
*x = PowAlgo{}
mi := &file_block_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PowAlgo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PowAlgo) ProtoMessage() {}
func (x *PowAlgo) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PowAlgo.ProtoReflect.Descriptor instead.
func (*PowAlgo) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{2}
}
func (x *PowAlgo) GetPowAlgo() PowAlgo_PowAlgos {
if x != nil {
return x.PowAlgo
}
return PowAlgo_POW_ALGOS_RANDOMXM
}
// A Minotari block. Blocks are linked together into a blockchain.
type Block struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
// and the transaction kernels.
Header *BlockHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// blocks consist of inputs, outputs and kernels, rather than transactions.
Body *transaction.AggregateBody `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Block) Reset() {
*x = Block{}
mi := &file_block_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Block) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Block) ProtoMessage() {}
func (x *Block) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Block.ProtoReflect.Descriptor instead.
func (*Block) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{3}
}
func (x *Block) GetHeader() *BlockHeader {
if x != nil {
return x.Header
}
return nil
}
func (x *Block) GetBody() *transaction.AggregateBody {
if x != nil {
return x.Body
}
return nil
}
// The representation of a historical block in the blockchain. It is essentially identical to a protocol-defined
// block but contains some extra metadata that clients such as Block Explorers will find interesting.
type HistoricalBlock struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The number of blocks that have been mined since this block, including this one. The current tip will have one
// confirmation.
Confirmations uint64 `protobuf:"varint,1,opt,name=confirmations,proto3" json:"confirmations,omitempty"`
// The underlying block
Block *Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HistoricalBlock) Reset() {
*x = HistoricalBlock{}
mi := &file_block_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HistoricalBlock) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HistoricalBlock) ProtoMessage() {}
func (x *HistoricalBlock) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HistoricalBlock.ProtoReflect.Descriptor instead.
func (*HistoricalBlock) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{4}
}
func (x *HistoricalBlock) GetConfirmations() uint64 {
if x != nil {
return x.Confirmations
}
return 0
}
func (x *HistoricalBlock) GetBlock() *Block {
if x != nil {
return x.Block
}
return nil
}
// The NewBlockHeaderTemplate is used for the construction of a new mine-able block. It contains all the metadata for the block that the Base Node is able to complete on behalf of a Miner.
type NewBlockHeaderTemplate struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Version of the block
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
// Height of this block since the genesis block (height 0)
Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
// Hash of the block previous to this in the chain.
PrevHash []byte `protobuf:"bytes,3,opt,name=prev_hash,json=prevHash,proto3" json:"prev_hash,omitempty"`
// Total accumulated sum of kernel offsets since genesis block. We can derive the kernel offset sum for *this*
// block from the total kernel offset of the previous block header.
TotalKernelOffset []byte `protobuf:"bytes,4,opt,name=total_kernel_offset,json=totalKernelOffset,proto3" json:"total_kernel_offset,omitempty"`
// Proof of work metadata
Pow *ProofOfWork `protobuf:"bytes,5,opt,name=pow,proto3" json:"pow,omitempty"`
// Sum of script offsets for all kernels in this block.
TotalScriptOffset []byte `protobuf:"bytes,7,opt,name=total_script_offset,json=totalScriptOffset,proto3" json:"total_script_offset,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBlockHeaderTemplate) Reset() {
*x = NewBlockHeaderTemplate{}
mi := &file_block_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBlockHeaderTemplate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBlockHeaderTemplate) ProtoMessage() {}
func (x *NewBlockHeaderTemplate) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBlockHeaderTemplate.ProtoReflect.Descriptor instead.
func (*NewBlockHeaderTemplate) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{5}
}
func (x *NewBlockHeaderTemplate) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *NewBlockHeaderTemplate) GetHeight() uint64 {
if x != nil {
return x.Height
}
return 0
}
func (x *NewBlockHeaderTemplate) GetPrevHash() []byte {
if x != nil {
return x.PrevHash
}
return nil
}
func (x *NewBlockHeaderTemplate) GetTotalKernelOffset() []byte {
if x != nil {
return x.TotalKernelOffset
}
return nil
}
func (x *NewBlockHeaderTemplate) GetPow() *ProofOfWork {
if x != nil {
return x.Pow
}
return nil
}
func (x *NewBlockHeaderTemplate) GetTotalScriptOffset() []byte {
if x != nil {
return x.TotalScriptOffset
}
return nil
}
// The new block template is used constructing a new partial block, allowing a miner to added the coinbase utxo and as a final step the Base node to add the MMR roots to the header.
type NewBlockTemplate struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The NewBlockHeaderTemplate is used for the construction of a new mineable block. It contains all the metadata for
// the block that the Base Node is able to complete on behalf of a Miner.
Header *NewBlockHeaderTemplate `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
// This flag indicates if the inputs, outputs and kernels have been sorted internally, that is, the sort() method
// has been called. This may be false even if all components are sorted.
Body *transaction.AggregateBody `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
// Sometimes the mempool has not synced to the latest tip, this flag indicates if the mempool is out of sync.
// In most cases the next call to get_new_block_template will return a block with the mempool in sync.
IsMempoolInSync bool `protobuf:"varint,3,opt,name=is_mempool_in_sync,json=isMempoolInSync,proto3" json:"is_mempool_in_sync,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NewBlockTemplate) Reset() {
*x = NewBlockTemplate{}
mi := &file_block_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NewBlockTemplate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewBlockTemplate) ProtoMessage() {}
func (x *NewBlockTemplate) ProtoReflect() protoreflect.Message {
mi := &file_block_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NewBlockTemplate.ProtoReflect.Descriptor instead.
func (*NewBlockTemplate) Descriptor() ([]byte, []int) {
return file_block_proto_rawDescGZIP(), []int{6}
}
func (x *NewBlockTemplate) GetHeader() *NewBlockHeaderTemplate {
if x != nil {
return x.Header
}
return nil
}
func (x *NewBlockTemplate) GetBody() *transaction.AggregateBody {
if x != nil {
return x.Body
}
return nil
}
func (x *NewBlockTemplate) GetIsMempoolInSync() bool {
if x != nil {
return x.IsMempoolInSync
}
return false
}
var File_block_proto protoreflect.FileDescriptor
const file_block_proto_rawDesc = "" +
"\n" +
"\vblock.proto\x12\btari.rpc\x1a\x11transaction.proto\"\xd6\x04\n" +
"\vBlockHeader\x12\x12\n" +
"\x04hash\x18\x01 \x01(\fR\x04hash\x12\x18\n" +
"\aversion\x18\x02 \x01(\rR\aversion\x12\x16\n" +
"\x06height\x18\x03 \x01(\x04R\x06height\x12\x1b\n" +
"\tprev_hash\x18\x04 \x01(\fR\bprevHash\x12\x1c\n" +
"\ttimestamp\x18\x05 \x01(\x04R\ttimestamp\x12\x1b\n" +
"\toutput_mr\x18\x06 \x01(\fR\boutputMr\x12&\n" +
"\x0fblock_output_mr\x18\a \x01(\fR\rblockOutputMr\x12\x1b\n" +
"\tkernel_mr\x18\b \x01(\fR\bkernelMr\x12\x19\n" +
"\binput_mr\x18\t \x01(\fR\ainputMr\x12.\n" +
"\x13total_kernel_offset\x18\n" +
" \x01(\fR\x11totalKernelOffset\x12\x14\n" +
"\x05nonce\x18\v \x01(\x04R\x05nonce\x12'\n" +
"\x03pow\x18\f \x01(\v2\x15.tari.rpc.ProofOfWorkR\x03pow\x12&\n" +
"\x0fkernel_mmr_size\x18\r \x01(\x04R\rkernelMmrSize\x12&\n" +
"\x0foutput_mmr_size\x18\x0e \x01(\x04R\routputMmrSize\x12.\n" +
"\x13total_script_offset\x18\x0f \x01(\fR\x11totalScriptOffset\x12*\n" +
"\x11validator_node_mr\x18\x10 \x01(\fR\x0fvalidatorNodeMr\x12.\n" +
"\x13validator_node_size\x18\x11 \x01(\x04R\x11validatorNodeSize\"C\n" +
"\vProofOfWork\x12\x19\n" +
"\bpow_algo\x18\x01 \x01(\x04R\apowAlgo\x12\x19\n" +
"\bpow_data\x18\x04 \x01(\fR\apowData\"\x91\x01\n" +
"\aPowAlgo\x125\n" +
"\bpow_algo\x18\x01 \x01(\x0e2\x1a.tari.rpc.PowAlgo.PowAlgosR\apowAlgo\"O\n" +
"\bPowAlgos\x12\x16\n" +
"\x12POW_ALGOS_RANDOMXM\x10\x00\x12\x13\n" +
"\x0fPOW_ALGOS_SHA3X\x10\x01\x12\x16\n" +
"\x12POW_ALGOS_RANDOMXT\x10\x02\"c\n" +
"\x05Block\x12-\n" +
"\x06header\x18\x01 \x01(\v2\x15.tari.rpc.BlockHeaderR\x06header\x12+\n" +
"\x04body\x18\x02 \x01(\v2\x17.tari.rpc.AggregateBodyR\x04body\"^\n" +
"\x0fHistoricalBlock\x12$\n" +
"\rconfirmations\x18\x01 \x01(\x04R\rconfirmations\x12%\n" +
"\x05block\x18\x02 \x01(\v2\x0f.tari.rpc.BlockR\x05block\"\xf0\x01\n" +
"\x16NewBlockHeaderTemplate\x12\x18\n" +
"\aversion\x18\x01 \x01(\rR\aversion\x12\x16\n" +
"\x06height\x18\x02 \x01(\x04R\x06height\x12\x1b\n" +
"\tprev_hash\x18\x03 \x01(\fR\bprevHash\x12.\n" +
"\x13total_kernel_offset\x18\x04 \x01(\fR\x11totalKernelOffset\x12'\n" +
"\x03pow\x18\x05 \x01(\v2\x15.tari.rpc.ProofOfWorkR\x03pow\x12.\n" +
"\x13total_script_offset\x18\a \x01(\fR\x11totalScriptOffset\"\xa6\x01\n" +
"\x10NewBlockTemplate\x128\n" +
"\x06header\x18\x01 \x01(\v2 .tari.rpc.NewBlockHeaderTemplateR\x06header\x12+\n" +
"\x04body\x18\x02 \x01(\v2\x17.tari.rpc.AggregateBodyR\x04body\x12+\n" +
"\x12is_mempool_in_sync\x18\x03 \x01(\bR\x0fisMempoolInSyncB$Z\"pool/internal/gbt/tari/block;blockb\x06proto3"
var (
file_block_proto_rawDescOnce sync.Once
file_block_proto_rawDescData []byte
)
func file_block_proto_rawDescGZIP() []byte {
file_block_proto_rawDescOnce.Do(func() {
file_block_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_block_proto_rawDesc), len(file_block_proto_rawDesc)))
})
return file_block_proto_rawDescData
}
var file_block_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_block_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_block_proto_goTypes = []any{
(PowAlgo_PowAlgos)(0), // 0: tari.rpc.PowAlgo.PowAlgos
(*BlockHeader)(nil), // 1: tari.rpc.BlockHeader
(*ProofOfWork)(nil), // 2: tari.rpc.ProofOfWork
(*PowAlgo)(nil), // 3: tari.rpc.PowAlgo
(*Block)(nil), // 4: tari.rpc.Block
(*HistoricalBlock)(nil), // 5: tari.rpc.HistoricalBlock
(*NewBlockHeaderTemplate)(nil), // 6: tari.rpc.NewBlockHeaderTemplate
(*NewBlockTemplate)(nil), // 7: tari.rpc.NewBlockTemplate
(*transaction.AggregateBody)(nil), // 8: tari.rpc.AggregateBody
}
var file_block_proto_depIdxs = []int32{
2, // 0: tari.rpc.BlockHeader.pow:type_name -> tari.rpc.ProofOfWork
0, // 1: tari.rpc.PowAlgo.pow_algo:type_name -> tari.rpc.PowAlgo.PowAlgos
1, // 2: tari.rpc.Block.header:type_name -> tari.rpc.BlockHeader
8, // 3: tari.rpc.Block.body:type_name -> tari.rpc.AggregateBody
4, // 4: tari.rpc.HistoricalBlock.block:type_name -> tari.rpc.Block
2, // 5: tari.rpc.NewBlockHeaderTemplate.pow:type_name -> tari.rpc.ProofOfWork
6, // 6: tari.rpc.NewBlockTemplate.header:type_name -> tari.rpc.NewBlockHeaderTemplate
8, // 7: tari.rpc.NewBlockTemplate.body:type_name -> tari.rpc.AggregateBody
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_block_proto_init() }
func file_block_proto_init() {
if File_block_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_block_proto_rawDesc), len(file_block_proto_rawDesc)),
NumEnums: 1,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_block_proto_goTypes,
DependencyIndexes: file_block_proto_depIdxs,
EnumInfos: file_block_proto_enumTypes,
MessageInfos: file_block_proto_msgTypes,
}.Build()
File_block_proto = out.File
file_block_proto_goTypes = nil
file_block_proto_depIdxs = nil
}

View File

@ -0,0 +1,790 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: network.proto
package net_work
import (
_ "github.com/golang/protobuf/ptypes/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ConnectivityStatus int32
const (
ConnectivityStatus_Initializing ConnectivityStatus = 0
ConnectivityStatus_Online ConnectivityStatus = 1
ConnectivityStatus_Degraded ConnectivityStatus = 2
ConnectivityStatus_Offline ConnectivityStatus = 3
)
// Enum value maps for ConnectivityStatus.
var (
ConnectivityStatus_name = map[int32]string{
0: "Initializing",
1: "Online",
2: "Degraded",
3: "Offline",
}
ConnectivityStatus_value = map[string]int32{
"Initializing": 0,
"Online": 1,
"Degraded": 2,
"Offline": 3,
}
)
func (x ConnectivityStatus) Enum() *ConnectivityStatus {
p := new(ConnectivityStatus)
*p = x
return p
}
func (x ConnectivityStatus) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ConnectivityStatus) Descriptor() protoreflect.EnumDescriptor {
return file_network_proto_enumTypes[0].Descriptor()
}
func (ConnectivityStatus) Type() protoreflect.EnumType {
return &file_network_proto_enumTypes[0]
}
func (x ConnectivityStatus) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ConnectivityStatus.Descriptor instead.
func (ConnectivityStatus) EnumDescriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{0}
}
type NodeIdentity struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
PublicAddresses []string `protobuf:"bytes,2,rep,name=public_addresses,json=publicAddresses,proto3" json:"public_addresses,omitempty"`
NodeId []byte `protobuf:"bytes,3,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeIdentity) Reset() {
*x = NodeIdentity{}
mi := &file_network_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeIdentity) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeIdentity) ProtoMessage() {}
func (x *NodeIdentity) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeIdentity.ProtoReflect.Descriptor instead.
func (*NodeIdentity) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{0}
}
func (x *NodeIdentity) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *NodeIdentity) GetPublicAddresses() []string {
if x != nil {
return x.PublicAddresses
}
return nil
}
func (x *NodeIdentity) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
type Peer struct {
state protoimpl.MessageState `protogen:"open.v1"`
// / Public key of the peer
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
// / NodeId of the peer
NodeId []byte `protobuf:"bytes,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
// / Peer's addresses
Addresses []*Address `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"`
// / Last connection attempt to peer
LastConnection uint64 `protobuf:"varint,4,opt,name=last_connection,json=lastConnection,proto3" json:"last_connection,omitempty"`
// / Flags for the peer.
Flags uint32 `protobuf:"varint,5,opt,name=flags,proto3" json:"flags,omitempty"`
BannedUntil uint64 `protobuf:"varint,6,opt,name=banned_until,json=bannedUntil,proto3" json:"banned_until,omitempty"`
BannedReason string `protobuf:"bytes,7,opt,name=banned_reason,json=bannedReason,proto3" json:"banned_reason,omitempty"`
OfflineAt uint64 `protobuf:"varint,8,opt,name=offline_at,json=offlineAt,proto3" json:"offline_at,omitempty"`
// / Features supported by the peer
Features uint32 `protobuf:"varint,9,opt,name=features,proto3" json:"features,omitempty"`
// / used as information for more efficient protocol negotiation.
SupportedProtocols [][]byte `protobuf:"bytes,11,rep,name=supported_protocols,json=supportedProtocols,proto3" json:"supported_protocols,omitempty"`
// / User agent advertised by the peer
UserAgent string `protobuf:"bytes,12,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Peer) Reset() {
*x = Peer{}
mi := &file_network_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Peer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Peer) ProtoMessage() {}
func (x *Peer) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Peer.ProtoReflect.Descriptor instead.
func (*Peer) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{1}
}
func (x *Peer) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *Peer) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
func (x *Peer) GetAddresses() []*Address {
if x != nil {
return x.Addresses
}
return nil
}
func (x *Peer) GetLastConnection() uint64 {
if x != nil {
return x.LastConnection
}
return 0
}
func (x *Peer) GetFlags() uint32 {
if x != nil {
return x.Flags
}
return 0
}
func (x *Peer) GetBannedUntil() uint64 {
if x != nil {
return x.BannedUntil
}
return 0
}
func (x *Peer) GetBannedReason() string {
if x != nil {
return x.BannedReason
}
return ""
}
func (x *Peer) GetOfflineAt() uint64 {
if x != nil {
return x.OfflineAt
}
return 0
}
func (x *Peer) GetFeatures() uint32 {
if x != nil {
return x.Features
}
return 0
}
func (x *Peer) GetSupportedProtocols() [][]byte {
if x != nil {
return x.SupportedProtocols
}
return nil
}
func (x *Peer) GetUserAgent() string {
if x != nil {
return x.UserAgent
}
return ""
}
type NetworkStatusResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Status ConnectivityStatus `protobuf:"varint,1,opt,name=status,proto3,enum=tari.rpc.ConnectivityStatus" json:"status,omitempty"`
AvgLatencyMs uint32 `protobuf:"varint,2,opt,name=avg_latency_ms,json=avgLatencyMs,proto3" json:"avg_latency_ms,omitempty"`
NumNodeConnections uint32 `protobuf:"varint,3,opt,name=num_node_connections,json=numNodeConnections,proto3" json:"num_node_connections,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NetworkStatusResponse) Reset() {
*x = NetworkStatusResponse{}
mi := &file_network_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NetworkStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NetworkStatusResponse) ProtoMessage() {}
func (x *NetworkStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NetworkStatusResponse.ProtoReflect.Descriptor instead.
func (*NetworkStatusResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{2}
}
func (x *NetworkStatusResponse) GetStatus() ConnectivityStatus {
if x != nil {
return x.Status
}
return ConnectivityStatus_Initializing
}
func (x *NetworkStatusResponse) GetAvgLatencyMs() uint32 {
if x != nil {
return x.AvgLatencyMs
}
return 0
}
func (x *NetworkStatusResponse) GetNumNodeConnections() uint32 {
if x != nil {
return x.NumNodeConnections
}
return 0
}
type Address struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
LastSeen string `protobuf:"bytes,2,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"`
ConnectionAttempts uint32 `protobuf:"varint,3,opt,name=connection_attempts,json=connectionAttempts,proto3" json:"connection_attempts,omitempty"`
AvgLatency *AverageLatency `protobuf:"bytes,5,opt,name=avg_latency,json=avgLatency,proto3" json:"avg_latency,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Address) Reset() {
*x = Address{}
mi := &file_network_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Address) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Address) ProtoMessage() {}
func (x *Address) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Address.ProtoReflect.Descriptor instead.
func (*Address) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{3}
}
func (x *Address) GetAddress() []byte {
if x != nil {
return x.Address
}
return nil
}
func (x *Address) GetLastSeen() string {
if x != nil {
return x.LastSeen
}
return ""
}
func (x *Address) GetConnectionAttempts() uint32 {
if x != nil {
return x.ConnectionAttempts
}
return 0
}
func (x *Address) GetAvgLatency() *AverageLatency {
if x != nil {
return x.AvgLatency
}
return nil
}
type AverageLatency struct {
state protoimpl.MessageState `protogen:"open.v1"`
Latency uint64 `protobuf:"varint,1,opt,name=latency,proto3" json:"latency,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AverageLatency) Reset() {
*x = AverageLatency{}
mi := &file_network_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AverageLatency) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AverageLatency) ProtoMessage() {}
func (x *AverageLatency) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AverageLatency.ProtoReflect.Descriptor instead.
func (*AverageLatency) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{4}
}
func (x *AverageLatency) GetLatency() uint64 {
if x != nil {
return x.Latency
}
return 0
}
type ListConnectedPeersResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
ConnectedPeers []*Peer `protobuf:"bytes,1,rep,name=connected_peers,json=connectedPeers,proto3" json:"connected_peers,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListConnectedPeersResponse) Reset() {
*x = ListConnectedPeersResponse{}
mi := &file_network_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListConnectedPeersResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListConnectedPeersResponse) ProtoMessage() {}
func (x *ListConnectedPeersResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListConnectedPeersResponse.ProtoReflect.Descriptor instead.
func (*ListConnectedPeersResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{5}
}
func (x *ListConnectedPeersResponse) GetConnectedPeers() []*Peer {
if x != nil {
return x.ConnectedPeers
}
return nil
}
type SoftwareUpdate struct {
state protoimpl.MessageState `protogen:"open.v1"`
HasUpdate bool `protobuf:"varint,1,opt,name=has_update,json=hasUpdate,proto3" json:"has_update,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Sha string `protobuf:"bytes,3,opt,name=sha,proto3" json:"sha,omitempty"`
DownloadUrl string `protobuf:"bytes,4,opt,name=download_url,json=downloadUrl,proto3" json:"download_url,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SoftwareUpdate) Reset() {
*x = SoftwareUpdate{}
mi := &file_network_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SoftwareUpdate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SoftwareUpdate) ProtoMessage() {}
func (x *SoftwareUpdate) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SoftwareUpdate.ProtoReflect.Descriptor instead.
func (*SoftwareUpdate) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{6}
}
func (x *SoftwareUpdate) GetHasUpdate() bool {
if x != nil {
return x.HasUpdate
}
return false
}
func (x *SoftwareUpdate) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *SoftwareUpdate) GetSha() string {
if x != nil {
return x.Sha
}
return ""
}
func (x *SoftwareUpdate) GetDownloadUrl() string {
if x != nil {
return x.DownloadUrl
}
return ""
}
type GetIdentityRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetIdentityRequest) Reset() {
*x = GetIdentityRequest{}
mi := &file_network_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetIdentityRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetIdentityRequest) ProtoMessage() {}
func (x *GetIdentityRequest) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetIdentityRequest.ProtoReflect.Descriptor instead.
func (*GetIdentityRequest) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{7}
}
type GetIdentityResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
PublicAddress string `protobuf:"bytes,2,opt,name=public_address,json=publicAddress,proto3" json:"public_address,omitempty"`
NodeId []byte `protobuf:"bytes,3,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetIdentityResponse) Reset() {
*x = GetIdentityResponse{}
mi := &file_network_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetIdentityResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetIdentityResponse) ProtoMessage() {}
func (x *GetIdentityResponse) ProtoReflect() protoreflect.Message {
mi := &file_network_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetIdentityResponse.ProtoReflect.Descriptor instead.
func (*GetIdentityResponse) Descriptor() ([]byte, []int) {
return file_network_proto_rawDescGZIP(), []int{8}
}
func (x *GetIdentityResponse) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *GetIdentityResponse) GetPublicAddress() string {
if x != nil {
return x.PublicAddress
}
return ""
}
func (x *GetIdentityResponse) GetNodeId() []byte {
if x != nil {
return x.NodeId
}
return nil
}
var File_network_proto protoreflect.FileDescriptor
const file_network_proto_rawDesc = "" +
"\n" +
"\rnetwork.proto\x12\btari.rpc\x1a\x1fgoogle/protobuf/timestamp.proto\"q\n" +
"\fNodeIdentity\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12)\n" +
"\x10public_addresses\x18\x02 \x03(\tR\x0fpublicAddresses\x12\x17\n" +
"\anode_id\x18\x03 \x01(\fR\x06nodeId\"\x81\x03\n" +
"\x04Peer\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12\x17\n" +
"\anode_id\x18\x02 \x01(\fR\x06nodeId\x12/\n" +
"\taddresses\x18\x03 \x03(\v2\x11.tari.rpc.AddressR\taddresses\x12'\n" +
"\x0flast_connection\x18\x04 \x01(\x04R\x0elastConnection\x12\x14\n" +
"\x05flags\x18\x05 \x01(\rR\x05flags\x12!\n" +
"\fbanned_until\x18\x06 \x01(\x04R\vbannedUntil\x12#\n" +
"\rbanned_reason\x18\a \x01(\tR\fbannedReason\x12\x1d\n" +
"\n" +
"offline_at\x18\b \x01(\x04R\tofflineAt\x12\x1a\n" +
"\bfeatures\x18\t \x01(\rR\bfeatures\x12/\n" +
"\x13supported_protocols\x18\v \x03(\fR\x12supportedProtocols\x12\x1d\n" +
"\n" +
"user_agent\x18\f \x01(\tR\tuserAgent\"\xa5\x01\n" +
"\x15NetworkStatusResponse\x124\n" +
"\x06status\x18\x01 \x01(\x0e2\x1c.tari.rpc.ConnectivityStatusR\x06status\x12$\n" +
"\x0eavg_latency_ms\x18\x02 \x01(\rR\favgLatencyMs\x120\n" +
"\x14num_node_connections\x18\x03 \x01(\rR\x12numNodeConnections\"\xac\x01\n" +
"\aAddress\x12\x18\n" +
"\aaddress\x18\x01 \x01(\fR\aaddress\x12\x1b\n" +
"\tlast_seen\x18\x02 \x01(\tR\blastSeen\x12/\n" +
"\x13connection_attempts\x18\x03 \x01(\rR\x12connectionAttempts\x129\n" +
"\vavg_latency\x18\x05 \x01(\v2\x18.tari.rpc.AverageLatencyR\n" +
"avgLatency\"*\n" +
"\x0eAverageLatency\x12\x18\n" +
"\alatency\x18\x01 \x01(\x04R\alatency\"U\n" +
"\x1aListConnectedPeersResponse\x127\n" +
"\x0fconnected_peers\x18\x01 \x03(\v2\x0e.tari.rpc.PeerR\x0econnectedPeers\"~\n" +
"\x0eSoftwareUpdate\x12\x1d\n" +
"\n" +
"has_update\x18\x01 \x01(\bR\thasUpdate\x12\x18\n" +
"\aversion\x18\x02 \x01(\tR\aversion\x12\x10\n" +
"\x03sha\x18\x03 \x01(\tR\x03sha\x12!\n" +
"\fdownload_url\x18\x04 \x01(\tR\vdownloadUrl\"\x14\n" +
"\x12GetIdentityRequest\"t\n" +
"\x13GetIdentityResponse\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x12%\n" +
"\x0epublic_address\x18\x02 \x01(\tR\rpublicAddress\x12\x17\n" +
"\anode_id\x18\x03 \x01(\fR\x06nodeId*M\n" +
"\x12ConnectivityStatus\x12\x10\n" +
"\fInitializing\x10\x00\x12\n" +
"\n" +
"\x06Online\x10\x01\x12\f\n" +
"\bDegraded\x10\x02\x12\v\n" +
"\aOffline\x10\x03B*Z(pool/internal/gbt/tari/net_work;net_workb\x06proto3"
var (
file_network_proto_rawDescOnce sync.Once
file_network_proto_rawDescData []byte
)
func file_network_proto_rawDescGZIP() []byte {
file_network_proto_rawDescOnce.Do(func() {
file_network_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_network_proto_rawDesc), len(file_network_proto_rawDesc)))
})
return file_network_proto_rawDescData
}
var file_network_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_network_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_network_proto_goTypes = []any{
(ConnectivityStatus)(0), // 0: tari.rpc.ConnectivityStatus
(*NodeIdentity)(nil), // 1: tari.rpc.NodeIdentity
(*Peer)(nil), // 2: tari.rpc.Peer
(*NetworkStatusResponse)(nil), // 3: tari.rpc.NetworkStatusResponse
(*Address)(nil), // 4: tari.rpc.Address
(*AverageLatency)(nil), // 5: tari.rpc.AverageLatency
(*ListConnectedPeersResponse)(nil), // 6: tari.rpc.ListConnectedPeersResponse
(*SoftwareUpdate)(nil), // 7: tari.rpc.SoftwareUpdate
(*GetIdentityRequest)(nil), // 8: tari.rpc.GetIdentityRequest
(*GetIdentityResponse)(nil), // 9: tari.rpc.GetIdentityResponse
}
var file_network_proto_depIdxs = []int32{
4, // 0: tari.rpc.Peer.addresses:type_name -> tari.rpc.Address
0, // 1: tari.rpc.NetworkStatusResponse.status:type_name -> tari.rpc.ConnectivityStatus
5, // 2: tari.rpc.Address.avg_latency:type_name -> tari.rpc.AverageLatency
2, // 3: tari.rpc.ListConnectedPeersResponse.connected_peers:type_name -> tari.rpc.Peer
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_network_proto_init() }
func file_network_proto_init() {
if File_network_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_network_proto_rawDesc), len(file_network_proto_rawDesc)),
NumEnums: 1,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_network_proto_goTypes,
DependencyIndexes: file_network_proto_depIdxs,
EnumInfos: file_network_proto_enumTypes,
MessageInfos: file_network_proto_msgTypes,
}.Build()
File_network_proto = out.File
file_network_proto_goTypes = nil
file_network_proto_depIdxs = nil
}

View File

@ -0,0 +1,97 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "google/protobuf/timestamp.proto";
message NodeIdentity {
bytes public_key = 1;
repeated string public_addresses = 2;
bytes node_id = 3;
}
message Peer {
/// Public key of the peer
bytes public_key =1;
/// NodeId of the peer
bytes node_id =2;
/// Peer's addresses
repeated Address addresses = 3;
/// Last connection attempt to peer
uint64 last_connection = 4;
/// Flags for the peer.
uint32 flags = 5;
uint64 banned_until= 6;
string banned_reason= 7;
uint64 offline_at = 8;
/// Features supported by the peer
uint32 features = 9;
/// used as information for more efficient protocol negotiation.
repeated bytes supported_protocols = 11;
/// User agent advertised by the peer
string user_agent = 12;
}
enum ConnectivityStatus {
Initializing = 0;
Online = 1;
Degraded = 2;
Offline = 3;
}
message NetworkStatusResponse {
ConnectivityStatus status = 1;
uint32 avg_latency_ms = 2;
uint32 num_node_connections = 3;
}
message Address{
bytes address =1;
string last_seen = 2;
uint32 connection_attempts = 3;
AverageLatency avg_latency = 5;
}
message AverageLatency {
uint64 latency = 1;
}
message ListConnectedPeersResponse {
repeated Peer connected_peers = 1;
}
message SoftwareUpdate {
bool has_update = 1;
string version = 2;
string sha = 3;
string download_url = 4;
}
message GetIdentityRequest { }
message GetIdentityResponse {
bytes public_key = 1;
string public_address = 2;
bytes node_id = 3;
}

View File

@ -0,0 +1,61 @@
// Copyright 2024. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "base_node.proto";
import "block.proto";
service ShaP2Pool {
rpc GetTipInfo(GetTipInfoRequest) returns(GetTipInfoResponse);
rpc GetNewBlock(GetNewBlockRequest) returns(GetNewBlockResponse);
rpc SubmitBlock(SubmitBlockRequest) returns(tari.rpc.SubmitBlockResponse);
}
message GetTipInfoRequest {
}
message GetTipInfoResponse {
uint64 node_height = 1;
bytes node_tip_hash = 2;
uint64 p2pool_rx_height = 3;
bytes p2pool_rx_tip_hash = 4;
uint64 p2pool_sha_height = 5;
bytes p2pool_sha_tip_hash = 6;
}
message GetNewBlockRequest {
tari.rpc.PowAlgo pow = 1;
string coinbase_extra = 2;
string wallet_payment_address = 3;
}
message GetNewBlockResponse {
tari.rpc.GetNewBlockResult block = 1;
uint64 target_difficulty = 2;
}
message SubmitBlockRequest {
tari.rpc.Block block = 1;
string wallet_payment_address = 2;
}

View File

@ -0,0 +1,77 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "types.proto";
message SideChainFeature {
oneof side_chain_feature {
ValidatorNodeRegistration validator_node_registration = 1;
TemplateRegistration template_registration = 2;
ConfidentialOutputData confidential_output = 3;
}
}
message ValidatorNodeRegistration {
bytes public_key = 1;
Signature signature = 2;
}
message TemplateRegistration {
bytes author_public_key = 1;
Signature author_signature = 2;
string template_name = 3;
uint32 template_version = 4;
TemplateType template_type = 5;
BuildInfo build_info = 6;
bytes binary_sha = 7;
string binary_url = 8;
}
message ConfidentialOutputData {
bytes claim_public_key = 1;
}
message TemplateType {
oneof template_type {
WasmInfo wasm = 1;
FlowInfo flow = 2;
ManifestInfo manifest = 3;
}
}
message WasmInfo {
uint32 abi_version = 1;
}
message FlowInfo {
}
message ManifestInfo {
}
message BuildInfo {
string repo_url = 1;
bytes commit_hash = 2;
}

View File

@ -0,0 +1,727 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v3.6.1
// source: sidechain_types.proto
package sidechain_types
import (
types "pool/internal/gbt/tari/proto/types"
reflect "reflect"
sync "sync"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SideChainFeature struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to SideChainFeature:
//
// *SideChainFeature_ValidatorNodeRegistration
// *SideChainFeature_TemplateRegistration
// *SideChainFeature_ConfidentialOutput
SideChainFeature isSideChainFeature_SideChainFeature `protobuf_oneof:"side_chain_feature"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SideChainFeature) Reset() {
*x = SideChainFeature{}
mi := &file_sidechain_types_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SideChainFeature) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SideChainFeature) ProtoMessage() {}
func (x *SideChainFeature) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SideChainFeature.ProtoReflect.Descriptor instead.
func (*SideChainFeature) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{0}
}
func (x *SideChainFeature) GetSideChainFeature() isSideChainFeature_SideChainFeature {
if x != nil {
return x.SideChainFeature
}
return nil
}
func (x *SideChainFeature) GetValidatorNodeRegistration() *ValidatorNodeRegistration {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_ValidatorNodeRegistration); ok {
return x.ValidatorNodeRegistration
}
}
return nil
}
func (x *SideChainFeature) GetTemplateRegistration() *TemplateRegistration {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_TemplateRegistration); ok {
return x.TemplateRegistration
}
}
return nil
}
func (x *SideChainFeature) GetConfidentialOutput() *ConfidentialOutputData {
if x != nil {
if x, ok := x.SideChainFeature.(*SideChainFeature_ConfidentialOutput); ok {
return x.ConfidentialOutput
}
}
return nil
}
type isSideChainFeature_SideChainFeature interface {
isSideChainFeature_SideChainFeature()
}
type SideChainFeature_ValidatorNodeRegistration struct {
ValidatorNodeRegistration *ValidatorNodeRegistration `protobuf:"bytes,1,opt,name=validator_node_registration,json=validatorNodeRegistration,proto3,oneof"`
}
type SideChainFeature_TemplateRegistration struct {
TemplateRegistration *TemplateRegistration `protobuf:"bytes,2,opt,name=template_registration,json=templateRegistration,proto3,oneof"`
}
type SideChainFeature_ConfidentialOutput struct {
ConfidentialOutput *ConfidentialOutputData `protobuf:"bytes,3,opt,name=confidential_output,json=confidentialOutput,proto3,oneof"`
}
func (*SideChainFeature_ValidatorNodeRegistration) isSideChainFeature_SideChainFeature() {}
func (*SideChainFeature_TemplateRegistration) isSideChainFeature_SideChainFeature() {}
func (*SideChainFeature_ConfidentialOutput) isSideChainFeature_SideChainFeature() {}
type ValidatorNodeRegistration struct {
state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
Signature *types.Signature `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ValidatorNodeRegistration) Reset() {
*x = ValidatorNodeRegistration{}
mi := &file_sidechain_types_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ValidatorNodeRegistration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidatorNodeRegistration) ProtoMessage() {}
func (x *ValidatorNodeRegistration) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidatorNodeRegistration.ProtoReflect.Descriptor instead.
func (*ValidatorNodeRegistration) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{1}
}
func (x *ValidatorNodeRegistration) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
func (x *ValidatorNodeRegistration) GetSignature() *types.Signature {
if x != nil {
return x.Signature
}
return nil
}
type TemplateRegistration struct {
state protoimpl.MessageState `protogen:"open.v1"`
AuthorPublicKey []byte `protobuf:"bytes,1,opt,name=author_public_key,json=authorPublicKey,proto3" json:"author_public_key,omitempty"`
AuthorSignature *types.Signature `protobuf:"bytes,2,opt,name=author_signature,json=authorSignature,proto3" json:"author_signature,omitempty"`
TemplateName string `protobuf:"bytes,3,opt,name=template_name,json=templateName,proto3" json:"template_name,omitempty"`
TemplateVersion uint32 `protobuf:"varint,4,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"`
TemplateType *TemplateType `protobuf:"bytes,5,opt,name=template_type,json=templateType,proto3" json:"template_type,omitempty"`
BuildInfo *BuildInfo `protobuf:"bytes,6,opt,name=build_info,json=buildInfo,proto3" json:"build_info,omitempty"`
BinarySha []byte `protobuf:"bytes,7,opt,name=binary_sha,json=binarySha,proto3" json:"binary_sha,omitempty"`
BinaryUrl string `protobuf:"bytes,8,opt,name=binary_url,json=binaryUrl,proto3" json:"binary_url,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TemplateRegistration) Reset() {
*x = TemplateRegistration{}
mi := &file_sidechain_types_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TemplateRegistration) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TemplateRegistration) ProtoMessage() {}
func (x *TemplateRegistration) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TemplateRegistration.ProtoReflect.Descriptor instead.
func (*TemplateRegistration) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{2}
}
func (x *TemplateRegistration) GetAuthorPublicKey() []byte {
if x != nil {
return x.AuthorPublicKey
}
return nil
}
func (x *TemplateRegistration) GetAuthorSignature() *types.Signature {
if x != nil {
return x.AuthorSignature
}
return nil
}
func (x *TemplateRegistration) GetTemplateName() string {
if x != nil {
return x.TemplateName
}
return ""
}
func (x *TemplateRegistration) GetTemplateVersion() uint32 {
if x != nil {
return x.TemplateVersion
}
return 0
}
func (x *TemplateRegistration) GetTemplateType() *TemplateType {
if x != nil {
return x.TemplateType
}
return nil
}
func (x *TemplateRegistration) GetBuildInfo() *BuildInfo {
if x != nil {
return x.BuildInfo
}
return nil
}
func (x *TemplateRegistration) GetBinarySha() []byte {
if x != nil {
return x.BinarySha
}
return nil
}
func (x *TemplateRegistration) GetBinaryUrl() string {
if x != nil {
return x.BinaryUrl
}
return ""
}
type ConfidentialOutputData struct {
state protoimpl.MessageState `protogen:"open.v1"`
ClaimPublicKey []byte `protobuf:"bytes,1,opt,name=claim_public_key,json=claimPublicKey,proto3" json:"claim_public_key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConfidentialOutputData) Reset() {
*x = ConfidentialOutputData{}
mi := &file_sidechain_types_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConfidentialOutputData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfidentialOutputData) ProtoMessage() {}
func (x *ConfidentialOutputData) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConfidentialOutputData.ProtoReflect.Descriptor instead.
func (*ConfidentialOutputData) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{3}
}
func (x *ConfidentialOutputData) GetClaimPublicKey() []byte {
if x != nil {
return x.ClaimPublicKey
}
return nil
}
type TemplateType struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to TemplateType:
//
// *TemplateType_Wasm
// *TemplateType_Flow
// *TemplateType_Manifest
TemplateType isTemplateType_TemplateType `protobuf_oneof:"template_type"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TemplateType) Reset() {
*x = TemplateType{}
mi := &file_sidechain_types_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TemplateType) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TemplateType) ProtoMessage() {}
func (x *TemplateType) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TemplateType.ProtoReflect.Descriptor instead.
func (*TemplateType) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{4}
}
func (x *TemplateType) GetTemplateType() isTemplateType_TemplateType {
if x != nil {
return x.TemplateType
}
return nil
}
func (x *TemplateType) GetWasm() *WasmInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Wasm); ok {
return x.Wasm
}
}
return nil
}
func (x *TemplateType) GetFlow() *FlowInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Flow); ok {
return x.Flow
}
}
return nil
}
func (x *TemplateType) GetManifest() *ManifestInfo {
if x != nil {
if x, ok := x.TemplateType.(*TemplateType_Manifest); ok {
return x.Manifest
}
}
return nil
}
type isTemplateType_TemplateType interface {
isTemplateType_TemplateType()
}
type TemplateType_Wasm struct {
Wasm *WasmInfo `protobuf:"bytes,1,opt,name=wasm,proto3,oneof"`
}
type TemplateType_Flow struct {
Flow *FlowInfo `protobuf:"bytes,2,opt,name=flow,proto3,oneof"`
}
type TemplateType_Manifest struct {
Manifest *ManifestInfo `protobuf:"bytes,3,opt,name=manifest,proto3,oneof"`
}
func (*TemplateType_Wasm) isTemplateType_TemplateType() {}
func (*TemplateType_Flow) isTemplateType_TemplateType() {}
func (*TemplateType_Manifest) isTemplateType_TemplateType() {}
type WasmInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
AbiVersion uint32 `protobuf:"varint,1,opt,name=abi_version,json=abiVersion,proto3" json:"abi_version,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WasmInfo) Reset() {
*x = WasmInfo{}
mi := &file_sidechain_types_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WasmInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WasmInfo) ProtoMessage() {}
func (x *WasmInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WasmInfo.ProtoReflect.Descriptor instead.
func (*WasmInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{5}
}
func (x *WasmInfo) GetAbiVersion() uint32 {
if x != nil {
return x.AbiVersion
}
return 0
}
type FlowInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FlowInfo) Reset() {
*x = FlowInfo{}
mi := &file_sidechain_types_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FlowInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FlowInfo) ProtoMessage() {}
func (x *FlowInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FlowInfo.ProtoReflect.Descriptor instead.
func (*FlowInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{6}
}
type ManifestInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ManifestInfo) Reset() {
*x = ManifestInfo{}
mi := &file_sidechain_types_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ManifestInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ManifestInfo) ProtoMessage() {}
func (x *ManifestInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ManifestInfo.ProtoReflect.Descriptor instead.
func (*ManifestInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{7}
}
type BuildInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
RepoUrl string `protobuf:"bytes,1,opt,name=repo_url,json=repoUrl,proto3" json:"repo_url,omitempty"`
CommitHash []byte `protobuf:"bytes,2,opt,name=commit_hash,json=commitHash,proto3" json:"commit_hash,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuildInfo) Reset() {
*x = BuildInfo{}
mi := &file_sidechain_types_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *BuildInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuildInfo) ProtoMessage() {}
func (x *BuildInfo) ProtoReflect() protoreflect.Message {
mi := &file_sidechain_types_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuildInfo.ProtoReflect.Descriptor instead.
func (*BuildInfo) Descriptor() ([]byte, []int) {
return file_sidechain_types_proto_rawDescGZIP(), []int{8}
}
func (x *BuildInfo) GetRepoUrl() string {
if x != nil {
return x.RepoUrl
}
return ""
}
func (x *BuildInfo) GetCommitHash() []byte {
if x != nil {
return x.CommitHash
}
return nil
}
var File_sidechain_types_proto protoreflect.FileDescriptor
const file_sidechain_types_proto_rawDesc = "" +
"\n" +
"\x15sidechain_types.proto\x12\btari.rpc\x1a\vtypes.proto\"\xbb\x02\n" +
"\x10SideChainFeature\x12e\n" +
"\x1bvalidator_node_registration\x18\x01 \x01(\v2#.tari.rpc.ValidatorNodeRegistrationH\x00R\x19validatorNodeRegistration\x12U\n" +
"\x15template_registration\x18\x02 \x01(\v2\x1e.tari.rpc.TemplateRegistrationH\x00R\x14templateRegistration\x12S\n" +
"\x13confidential_output\x18\x03 \x01(\v2 .tari.rpc.ConfidentialOutputDataH\x00R\x12confidentialOutputB\x14\n" +
"\x12side_chain_feature\"m\n" +
"\x19ValidatorNodeRegistration\x12\x1d\n" +
"\n" +
"public_key\x18\x01 \x01(\fR\tpublicKey\x121\n" +
"\tsignature\x18\x02 \x01(\v2\x13.tari.rpc.SignatureR\tsignature\"\x81\x03\n" +
"\x14TemplateRegistration\x12*\n" +
"\x11author_public_key\x18\x01 \x01(\fR\x0fauthorPublicKey\x12>\n" +
"\x10author_signature\x18\x02 \x01(\v2\x13.tari.rpc.SignatureR\x0fauthorSignature\x12#\n" +
"\rtemplate_name\x18\x03 \x01(\tR\ftemplateName\x12)\n" +
"\x10template_version\x18\x04 \x01(\rR\x0ftemplateVersion\x12;\n" +
"\rtemplate_type\x18\x05 \x01(\v2\x16.tari.rpc.TemplateTypeR\ftemplateType\x122\n" +
"\n" +
"build_info\x18\x06 \x01(\v2\x13.tari.rpc.BuildInfoR\tbuildInfo\x12\x1d\n" +
"\n" +
"binary_sha\x18\a \x01(\fR\tbinarySha\x12\x1d\n" +
"\n" +
"binary_url\x18\b \x01(\tR\tbinaryUrl\"B\n" +
"\x16ConfidentialOutputData\x12(\n" +
"\x10claim_public_key\x18\x01 \x01(\fR\x0eclaimPublicKey\"\xa9\x01\n" +
"\fTemplateType\x12(\n" +
"\x04wasm\x18\x01 \x01(\v2\x12.tari.rpc.WasmInfoH\x00R\x04wasm\x12(\n" +
"\x04flow\x18\x02 \x01(\v2\x12.tari.rpc.FlowInfoH\x00R\x04flow\x124\n" +
"\bmanifest\x18\x03 \x01(\v2\x16.tari.rpc.ManifestInfoH\x00R\bmanifestB\x0f\n" +
"\rtemplate_type\"+\n" +
"\bWasmInfo\x12\x1f\n" +
"\vabi_version\x18\x01 \x01(\rR\n" +
"abiVersion\"\n" +
"\n" +
"\bFlowInfo\"\x0e\n" +
"\fManifestInfo\"G\n" +
"\tBuildInfo\x12\x19\n" +
"\brepo_url\x18\x01 \x01(\tR\arepoUrl\x12\x1f\n" +
"\vcommit_hash\x18\x02 \x01(\fR\n" +
"commitHashB8Z6pool/internal/gbt/tari/sidechain_types;sidechain_typesb\x06proto3"
var (
file_sidechain_types_proto_rawDescOnce sync.Once
file_sidechain_types_proto_rawDescData []byte
)
func file_sidechain_types_proto_rawDescGZIP() []byte {
file_sidechain_types_proto_rawDescOnce.Do(func() {
file_sidechain_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_sidechain_types_proto_rawDesc), len(file_sidechain_types_proto_rawDesc)))
})
return file_sidechain_types_proto_rawDescData
}
var file_sidechain_types_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_sidechain_types_proto_goTypes = []any{
(*SideChainFeature)(nil), // 0: tari.rpc.SideChainFeature
(*ValidatorNodeRegistration)(nil), // 1: tari.rpc.ValidatorNodeRegistration
(*TemplateRegistration)(nil), // 2: tari.rpc.TemplateRegistration
(*ConfidentialOutputData)(nil), // 3: tari.rpc.ConfidentialOutputData
(*TemplateType)(nil), // 4: tari.rpc.TemplateType
(*WasmInfo)(nil), // 5: tari.rpc.WasmInfo
(*FlowInfo)(nil), // 6: tari.rpc.FlowInfo
(*ManifestInfo)(nil), // 7: tari.rpc.ManifestInfo
(*BuildInfo)(nil), // 8: tari.rpc.BuildInfo
(*types.Signature)(nil), // 9: tari.rpc.Signature
}
var file_sidechain_types_proto_depIdxs = []int32{
1, // 0: tari.rpc.SideChainFeature.validator_node_registration:type_name -> tari.rpc.ValidatorNodeRegistration
2, // 1: tari.rpc.SideChainFeature.template_registration:type_name -> tari.rpc.TemplateRegistration
3, // 2: tari.rpc.SideChainFeature.confidential_output:type_name -> tari.rpc.ConfidentialOutputData
9, // 3: tari.rpc.ValidatorNodeRegistration.signature:type_name -> tari.rpc.Signature
9, // 4: tari.rpc.TemplateRegistration.author_signature:type_name -> tari.rpc.Signature
4, // 5: tari.rpc.TemplateRegistration.template_type:type_name -> tari.rpc.TemplateType
8, // 6: tari.rpc.TemplateRegistration.build_info:type_name -> tari.rpc.BuildInfo
5, // 7: tari.rpc.TemplateType.wasm:type_name -> tari.rpc.WasmInfo
6, // 8: tari.rpc.TemplateType.flow:type_name -> tari.rpc.FlowInfo
7, // 9: tari.rpc.TemplateType.manifest:type_name -> tari.rpc.ManifestInfo
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_sidechain_types_proto_init() }
func file_sidechain_types_proto_init() {
if File_sidechain_types_proto != nil {
return
}
file_sidechain_types_proto_msgTypes[0].OneofWrappers = []any{
(*SideChainFeature_ValidatorNodeRegistration)(nil),
(*SideChainFeature_TemplateRegistration)(nil),
(*SideChainFeature_ConfidentialOutput)(nil),
}
file_sidechain_types_proto_msgTypes[4].OneofWrappers = []any{
(*TemplateType_Wasm)(nil),
(*TemplateType_Flow)(nil),
(*TemplateType_Manifest)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_sidechain_types_proto_rawDesc), len(file_sidechain_types_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_sidechain_types_proto_goTypes,
DependencyIndexes: file_sidechain_types_proto_depIdxs,
MessageInfos: file_sidechain_types_proto_msgTypes,
}.Build()
File_sidechain_types_proto = out.File
file_sidechain_types_proto_goTypes = nil
file_sidechain_types_proto_depIdxs = nil
}

View File

@ -0,0 +1,188 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
import "types.proto";
import "sidechain_types.proto";
// The transaction kernel tracks the excess for a given transaction. For an explanation of what the excess is, and
// why it is necessary, refer to the
// [Mimblewimble TLU post](https://tlu.tarilabs.com/protocols/mimblewimble-1/sources/PITCHME.link.html?highlight=mimblewimble#mimblewimble).
// The kernel also tracks other transaction metadata, such as the lock height for the transaction (i.e. the earliest
// this transaction can be mined) and the transaction fee, in cleartext.
message TransactionKernel {
// Options for a kernel's structure or use
uint32 features = 1;
/// Fee originally included in the transaction this proof is for (in MicroMinotari)
uint64 fee = 2;
// This kernel is not valid earlier than lock_height blocks
// The max lock_height of all *inputs* to this transaction
uint64 lock_height = 3;
// Remainder of the sum of all transaction commitments. If the transaction
// is well formed, amounts components should sum to zero and the excess
// is hence a valid public key.
bytes excess = 6;
// The signature proving the excess is a valid public key, which signs
// the transaction fee.
Signature excess_sig = 7;
// The hash of the kernel, as it appears in the MMR
bytes hash = 8;
// Version
uint32 version = 9;
// Optional burned commitment
bytes burn_commitment = 10;
}
// A transaction input.
//
// Primarily a reference to an output being spent by the transaction.
message TransactionInput {
// The features of the output being spent. We will check maturity for all outputs.
OutputFeatures features = 1;
// The commitment referencing the output being spent.
bytes commitment = 2;
// Hash of the input, as it appears in the MMR
bytes hash = 3;
// The serialised script
bytes script = 4;
// The script input data, if any
bytes input_data = 5;
// A signature with k_s, signing the script, input data, and mined height
ComAndPubSignature script_signature = 7;
// The offset public key, K_O
bytes sender_offset_public_key = 8;
// The hash of the output this input is spending
bytes output_hash = 9;
// Covenant
bytes covenant = 10;
// Version
uint32 version = 11;
// The encrypted data
bytes encrypted_data = 12;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 13;
// The metadata signature for output this input is spending
ComAndPubSignature metadata_signature = 14;
// The rangeproof hash for output this input is spending
bytes rangeproof_hash = 15;
}
// Output for a transaction, defining the new ownership of coins that are being transferred. The commitment is a
// blinded value for the output while the range proof guarantees the commitment includes a positive value without
// overflow and the ownership of the private key.
message TransactionOutput {
// Options for an output's structure or use
OutputFeatures features = 1;
// The homomorphic commitment representing the output amount
bytes commitment = 2;
// A proof that the commitment is in the right range
RangeProof range_proof = 3;
// The hash of the output, as it appears in the MMR
bytes hash = 4;
// Tari script serialised script
bytes script = 5;
// Tari script offset public key, K_O
bytes sender_offset_public_key = 6;
// Metadata signature with the homomorphic commitment private values (amount and blinding factor) and the sender
// offset private key
ComAndPubSignature metadata_signature = 7;
// Covenant
bytes covenant = 8;
// Version
uint32 version = 9;
// Encrypted Pedersen commitment openings (value and mask) for the output
bytes encrypted_data = 10;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 11;
// Payment reference (PayRef) - 32-byte Blake2b hash of (block_hash || output_hash)
// This provides a unique, deterministic reference for the output that can be used
// for payment verification without revealing wallet ownership
bytes payment_reference = 12;
}
// Options for UTXOs
message OutputFeatures {
// Version
uint32 version = 1;
// The type of output, eg Coinbase, all of which have different consensus rules
uint32 output_type = 2;
// The maturity of the specific UTXO. This is the min lock height at which an UTXO can be spend. Coinbase UTXO
// require a min maturity of the Coinbase_lock_height, this should be checked on receiving new blocks.
uint64 maturity = 3;
// Additional arbitrary info in coinbase transactions supplied by miners
bytes coinbase_extra = 4;
// Features that are specific to a side chain
SideChainFeature sidechain_feature = 5;
// The type of range proof used in the output
uint32 range_proof_type = 6;
}
// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
// cut-through means that blocks and transactions have the same structure. The inputs, outputs and kernels should
// be sorted by their Blake2b-256bit digest hash
message AggregateBody {
// List of inputs spent by the transaction.
repeated TransactionInput inputs = 1;
// List of outputs the transaction produces.
repeated TransactionOutput outputs = 2;
// Kernels contain the excesses and their signatures for transaction
repeated TransactionKernel kernels = 3;
}
// A transaction which consists of a kernel offset and an aggregate body made up of inputs, outputs and kernels.
message Transaction {
bytes offset = 1;
AggregateBody body = 2;
bytes script_offset = 3;
}
message UnblindedOutput {
// Value of the output
uint64 value = 1;
// Spending key of the output
bytes spending_key = 2;
// Options for an output's structure or use
OutputFeatures features = 3;
// Tari script serialised script
bytes script = 4;
// Tari script input data for spending
bytes input_data = 5;
// Tari script private key
bytes script_private_key = 7;
// Tari script offset pubkey, K_O
bytes sender_offset_public_key = 8;
// UTXO signature with the script offset private key, k_O
ComAndPubSignature metadata_signature = 9;
// The minimum height the script allows this output to be spent
uint64 script_lock_height = 10;
// Covenant
bytes covenant = 11;
// Encrypted data
bytes encrypted_data = 12;
// The minimum value of the commitment that is proven by the range proof (in MicroMinotari)
uint64 minimum_value_promise = 13;
// The range proof
RangeProof range_proof = 14;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
// Copyright 2020. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package tari.rpc;
/// An unsigned range interface to more accurately represent Rust native Range's
message Range {
uint64 min = 1;
uint64 max = 2;
}
/// An Empty placeholder for endpoints without request parameters
message Empty {}
/// Define an interface for block height
message BlockHeight {
uint64 block_height = 1;
}
// Define the explicit Signature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type.
message Signature {
bytes public_nonce = 1;
bytes signature = 2;
}
// Define the explicit ComAndPubSignature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type.
message ComAndPubSignature {
bytes ephemeral_commitment = 1;
bytes ephemeral_pubkey = 2;
bytes u_a = 3;
bytes u_x = 4;
bytes u_y = 5;
}
// Define the explicit CommitmentSignature implementation for the Minotari base layer. A different signature scheme can be
// employed by redefining this type
message CommitmentSignature {
bytes public_nonce = 1;
bytes u = 2;
bytes v = 3;
}
/// PoW Algorithm constants
message PowAlgorithmConstants {
uint64 min_difficulty = 2;
uint64 max_difficulty = 3;
uint64 target_time = 4;
}
/// Weight params
message WeightParams {
uint64 kernel_weight = 1;
uint64 input_weight = 2;
uint64 output_weight = 3;
uint64 features_and_scripts_bytes_per_gram = 4;
}
/// Output version
message OutputsVersion {
Range outputs = 1;
Range features = 2;
}
/// Output types
enum OutputType {
STANDARD = 0;
COINBASE = 1;
BURN = 2;
VALIDATOR_NODE_REGISTRATION = 3;
CODE_TEMPLATE_REGISTRATION = 4;
}
/// Range proof types
enum RangeProofType {
BULLETPROOF_PLUS = 0;
REVEALED_VALUE = 1;
}
message PermittedRangeProofs {
OutputType output_type = 1;
repeated RangeProofType range_proof_types = 2;
}
/// Range proof
message RangeProof {
bytes proof_bytes = 1;
}
/// Consensus Constants response
message ConsensusConstants {
uint64 coinbase_min_maturity = 1;
uint32 blockchain_version = 2;
uint64 future_time_limit = 3;
uint64 difficulty_block_window = 5;
uint64 max_block_transaction_weight = 7;
uint64 pow_algo_count = 8;
uint64 median_timestamp_count = 9;
uint64 emission_initial = 10;
repeated uint64 emission_decay = 11;
uint64 emission_tail = 12 [deprecated=true];
uint64 min_sha3x_pow_difficulty = 13;
uint64 block_weight_inputs = 14;
uint64 block_weight_outputs = 15;
uint64 block_weight_kernels = 16;
uint64 pre_mine_value = 17;
uint64 max_script_byte_size = 18;
uint64 validator_node_validity_period = 19;
uint64 effective_from_height = 20;
Range valid_blockchain_version_range = 21;
uint64 max_randomx_seed_height = 22;
map<uint32, PowAlgorithmConstants> proof_of_work = 23;
WeightParams transaction_weight = 24;
Range input_version_range = 26;
OutputsVersion output_version_range = 27;
Range kernel_version_range = 28;
repeated OutputType permitted_output_types = 29;
uint64 epoch_length = 30;
uint64 validator_node_registration_min_deposit_amount = 31;
uint64 validator_node_registration_min_lock_height = 32;
uint64 validator_node_registration_shuffle_interval_epoch = 33;
repeated PermittedRangeProofs permitted_range_proof_types = 34;
uint64 inflation_bips = 35;
uint64 tail_epoch_length = 36;
uint64 max_block_coinbase_count = 37;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
// Copyright 2021. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "types.proto";
import "network.proto";
import "transaction.proto";
package tari.rpc;
service ValidatorNode {
rpc GetIdentity(GetIdentityRequest) returns (GetIdentityResponse);
rpc GetMetadata(GetMetadataRequest) returns (GetMetadataResponse);
rpc GetTokenData(GetTokenDataRequest) returns (GetTokenDataResponse);
// rpc ExecuteInstruction(ExecuteInstructionRequest) returns (ExecuteInstructionResponse);
rpc InvokeReadMethod(InvokeReadMethodRequest) returns (InvokeReadMethodResponse);
rpc InvokeMethod(InvokeMethodRequest) returns (InvokeMethodResponse);
rpc GetConstitutionRequests(GetConstitutionRequestsRequest) returns (stream TransactionOutput);
rpc PublishContractAcceptance(PublishContractAcceptanceRequest) returns (PublishContractAcceptanceResponse);
rpc PublishContractUpdateProposalAcceptance(PublishContractUpdateProposalAcceptanceRequest) returns (PublishContractUpdateProposalAcceptanceResponse);
}
message GetConstitutionRequestsRequest {
// empty
}
message GetMetadataRequest {
// empty
}
message PublishContractAcceptanceRequest {
bytes contract_id = 1;
}
message PublishContractAcceptanceResponse {
string status = 1;
uint64 tx_id = 2;
}
message PublishContractUpdateProposalAcceptanceRequest {
bytes contract_id = 1;
uint64 proposal_id = 2;
}
message PublishContractUpdateProposalAcceptanceResponse {
string status = 1;
uint64 tx_id = 2;
}
message GetMetadataResponse {
repeated SidechainMetadata sidechains = 1;
}
message SidechainMetadata {
bytes asset_public_key =1;
uint64 committed_height = 2;
bytes committed_hash = 3;
}
message GetTokenDataRequest {
bytes asset_pub_key = 1;
bytes unique_id = 2;
}
message GetTokenDataResponse {
}
//message ExecuteInstructionRequest{
// bytes asset_public_key = 1;
// uint32 template_id = 2;
// string method = 3;
// bytes args = 4;
//// bytes token_id = 5;
//// bytes signature = 6;
//}
//
//message ExecuteInstructionResponse {
// string status = 1;
// optional bytes result = 2;
//}
message InvokeReadMethodRequest{
bytes contract_id = 1;
uint32 template_id = 2;
string method = 3;
bytes args = 4;
bytes sender = 5;
}
message InvokeReadMethodResponse {
bytes result = 1;
Authority authority = 2;
}
message Authority {
bytes node_public_key =1;
bytes signature = 2;
bytes proxied_by = 3;
}
message InvokeMethodRequest {
bytes contract_id = 1;
uint32 template_id = 2;
string method = 3;
bytes args = 4;
bytes sender = 5;
}
message InvokeMethodResponse {
string status = 1;
bytes result = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,385 @@
package sha3x
import (
"context"
"crypto/rand"
"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"pool/internal/db"
"pool/internal/gbt/coin"
"pool/internal/gbt/dbif"
"pool/internal/gbt/tari"
"pool/internal/msg"
"pool/internal/utility"
"sync"
"sync/atomic"
"time"
"go.uber.org/zap"
)
const GBT_SHA3X_VERSION string = "sha3x v1.0"
type Sha3xAddrConfig struct {
Addr string `json:"addr"`
}
type Sha3xConfig struct {
Monero Sha3xAddrConfig `json:"sha3x"`
}
type GbtSha3xContext struct {
Config Sha3xConfig
GbtCtx *coin.GbtContext
Ctx context.Context
last_time time.Time
last_gbt tari.TariBlockTemplate
last_blockhash string
last_height uint64
Submits float64
addressIndex int
Target []byte
Header []byte
last_body string
Jobs sync.Map
JobIds []string
JobGenCount int
new_block_chan chan int
new_block_index int
}
var logg *zap.Logger
var GbtSha3xCtx GbtSha3xContext
func configInit(config *Sha3xConfig) {
data, err := ioutil.ReadFile("gbt.conf")
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {
GbtSha3xCtx.GbtCtx = GbtCtx
GbtSha3xCtx.last_height = 0
configInit(&GbtSha3xCtx.Config)
GbtSha3xCtx.JobGenCount = 0
GbtSha3xCtx.Target = make([]byte, 32)
GbtSha3xCtx.Header = make([]byte, 49)
GbtSha3xCtx.last_time = time.Now()
GbtSha3xCtx.Ctx = context.Background()
logg = GbtCtx.Log
GbtSha3xCtx.new_block_chan = make(chan int, 256)
GbtSha3xCtx.new_block_index = 0
logg.Info("[gbt]", zap.String("gbt_sha3x_version", GBT_SHA3X_VERSION))
}
func Start() {
go gbt_running(&GbtSha3xCtx)
go gbt_notify_running(&GbtSha3xCtx)
go submit_block_running(&GbtSha3xCtx)
}
func Stop() {
defer close(GbtSha3xCtx.new_block_chan)
}
func update_block_confirm(gbt *GbtSha3xContext) {
}
func randomxJobId() string {
// 生成4个字节
bytes := make([]byte, 4)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
// 转成 hex 字符串
hexStr := hex.EncodeToString(bytes)
return hexStr
}
func removeJobs(gbt *GbtSha3xContext, clean bool) {
if !clean {
if len(gbt.JobIds) > 10 {
end := len(gbt.JobIds) - 10
for i := 0; i < end; i++ {
gbt.Jobs.Delete(gbt.JobIds[i])
}
gbt.JobIds = gbt.JobIds[end:]
}
} else {
gbt.Jobs.Range(func(key, value interface{}) bool {
gbt.Jobs.Delete(key)
return true
})
gbt.JobIds = nil
gbt.JobGenCount = 0
}
}
func gbt_running(gbt *GbtSha3xContext) {
ticker := time.NewTicker(1000 * time.Millisecond)
defer ticker.Stop()
for gbt.GbtCtx.Started {
select {
case <-ticker.C:
// 获取区块模板
blockTemplate, err := gbt.GbtCtx.TariClient.GetBlockTemplate(gbt.Ctx, 1)
if err != nil || len(blockTemplate.Header) != 638 {
fmt.Println("任务模板中的区块头长度:", len(blockTemplate.Header))
return
}
// 初始化 ZMQ 发布通道
if gbt.GbtCtx.PubCh == nil {
gbt.GbtCtx.PubCh = utility.InitZmqPub(gbt.GbtCtx.Config.Zmq.Pub)
continue
}
height := blockTemplate.Height
if height == gbt.last_height {
removeJobs(gbt, false)
if gbt.JobGenCount >= 10 {
generateJob(gbt, &blockTemplate)
gbt.JobGenCount = 0 // 成功生成 Job 后重置计数器
}
} else {
removeJobs(gbt, true)
generateJob(gbt, &blockTemplate)
gbt.last_height = height
gbt.JobGenCount = 0 // 高度变化也重置计数器
}
// 标记存活
atomic.StoreInt32(&(gbt.GbtCtx.FlagAliving), 1)
// 无论是否需要发布新任务,计数均+1保持至少10秒更新一次任务
gbt.JobGenCount += 1
case blkIdx := <-gbt.new_block_chan:
log.Println("new block chan", blkIdx)
update_block_confirm(gbt)
case <-gbt.GbtCtx.ExitGbtChan:
logg.Error("[gbt]", zap.String("gbt", "exit"))
return
}
}
}
func generateJob(gbt *GbtSha3xContext, blockTemplate *tari.TariBlockTemplate) {
for trycnt := 0; trycnt < 3; trycnt++ {
job := msg.Sha3xJob{
JobId: randomxJobId(),
MiningHash: blockTemplate.MiningHash,
Header: blockTemplate.Header,
Body: blockTemplate.Body,
TargetDifficulty: blockTemplate.TargetDifficulty,
Height: blockTemplate.Height,
}
sendMsg := msg.Sha3xStratumJob{
JobId: job.JobId,
Header: job.MiningHash,
U64target: job.TargetDifficulty,
Height: uint32(job.Height),
}
bt, err := json.Marshal(sendMsg)
if err != nil {
fmt.Println(err)
continue
}
// 保存 Job
gbt.Jobs.LoadOrStore(job.JobId, job)
gbt.JobIds = append(gbt.JobIds, job.JobId)
// 发布 Job
if err := gbt.GbtCtx.PubCh.SendMessage([][]byte{[]byte("jobsha3x"), bt}); err != nil {
logg.Warn("[gbt]", zap.String("job", err.Error()))
continue
}
logg.Warn("[gbt]", zap.String("job", "sent"))
gbt.JobGenCount++
break
}
}
func gbt_notify_running(gbt *GbtSha3xContext) {
for {
if !gbt.GbtCtx.Started {
break
}
if gbt.GbtCtx.MoneroNewBlockSubCh == nil {
gbt.GbtCtx.MoneroNewBlockSubCh = utility.InitZmqSub(gbt.GbtCtx.Config.Rpc.ZmqSub, utility.BITCOIND_ZMQ_HASHBLOCK)
}
if gbt.GbtCtx.MoneroNewBlockSubCh != nil {
cmsg_sub, err := gbt.GbtCtx.MoneroNewBlockSubCh.RecvMessage()
if err != nil {
if !gbt.GbtCtx.Started {
break
}
gbt.GbtCtx.MoneroNewBlockSubCh.SetSubscribe(utility.BITCOIND_ZMQ_HASHBLOCK)
gbt.GbtCtx.MoneroNewBlockSubCh.Connect(gbt.GbtCtx.Config.Rpc.ZmqSub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "hashblock" {
GbtSha3xCtx.new_block_index = GbtSha3xCtx.new_block_index + 1
//log.Println("gbt_notify_running", hex.EncodeToString(cmsg_sub[1]), GbtNexaCtx.new_block_index)
gbt.new_block_chan <- GbtSha3xCtx.new_block_index
}
}
} else {
logg.Error("[gbt]", zap.String("notify", "NodeSubCh fail!"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
type ServerSubmitBlock struct {
JobId string
Header []byte
Body []byte
Nonce string
}
func submit_block_running(block *GbtSha3xContext) {
logg.Info("[block]", zap.String("submit_block_running", "Start."))
for {
if !block.GbtCtx.Started {
break
}
if block.GbtCtx.SubCh == nil {
block.GbtCtx.SubCh = utility.InitZmqSub(block.GbtCtx.Config.Zmq.Sub, "blk"+block.GbtCtx.Coin)
}
if block.GbtCtx.SubCh != nil {
cmsg_sub, err := block.GbtCtx.SubCh.RecvMessage()
if err != nil {
if !block.GbtCtx.Started {
break
}
time.Sleep(time.Duration(1) * time.Second)
block.GbtCtx.SubCh.SetSubscribe("blk" + block.GbtCtx.Coin)
block.GbtCtx.SubCh.Connect(block.GbtCtx.Config.Zmq.Sub)
continue
}
if len(cmsg_sub) >= 2 {
if string(cmsg_sub[0]) == "blksha3x" {
cmsg := cmsg_sub[1]
//block data
msgb := make([]byte, len(cmsg)-16)
copy(msgb, cmsg)
var submitMsg msg.BlockSha3xMsg
if err := json.Unmarshal(msgb, &submitMsg); err != nil {
//block.Consumer.MarkOffset(cmsg, "")
logg.Error("[block]", zap.String("failed to Unmarshal job", err.Error()))
continue
}
var height = submitMsg.Height
logg.Warn("[block]", zap.Uint64("height", height))
if height <= block.last_height {
continue
}
block.last_height = height
indexb, err1 := hex.DecodeString(string(cmsg[len(msgb)+8:]))
if err1 != nil {
logg.Error("[block]", zap.String("failed to decode index", err1.Error()))
continue
}
var index uint32 = utility.ByteToUint32(indexb)
logg.Warn("[block]", zap.Uint32("index", index))
logg.Debug("[block]", zap.String("msg", string(cmsg)), zap.String("blk", string(msgb)))
if v, ok := block.Jobs.Load(submitMsg.Id); ok {
job := v.(*msg.Sha3xJob) // 类型断言
headerStr, bodyStr := job.Header, job.Body
header, err := hex.DecodeString(headerStr)
if err != nil {
fmt.Println(err)
return
}
body, err := hex.DecodeString(bodyStr)
if err != nil {
fmt.Println(err)
return
}
nonceByte := make([]byte, 8)
binary.LittleEndian.PutUint64(nonceByte, submitMsg.Nonce)
copy(header[311:319], nonceByte)
blockHash_byte, _ := block.GbtCtx.TariClient.SubmitBlock(block.Ctx, header, body)
nonceStr := fmt.Sprintf("%x", submitMsg.Nonce)
blockHash := hex.EncodeToString(blockHash_byte)
dbif.NotifyPoolBlkStatsSubmitResult(block.GbtCtx, int64(height), blockHash, "OK", nonceStr, submitMsg.SubIdx)
block.Submits += 1
logg.Warn("[block]", zap.Float64("total submits", block.Submits), zap.Int64("SubIdx", submitMsg.SubIdx))
new_block_into_db(block, submitMsg.User, submitMsg.Miner, submitMsg.Index, int64(height), nonceStr, blockHash, submitMsg.SubIdx)
}
}
}
} else {
logg.Error("[block]", zap.String("block", "SubCh failed! retry"))
time.Sleep(time.Duration(1) * time.Second)
}
}
}
func new_block_into_db(block *GbtSha3xContext, user string, miner string, minerid string, height int64, nonce string, hash string, subidx int64) bool {
db, err := sql.Open("sqlite3", "./blocks.db")
if err != nil {
log.Printf("Error opening database: %v", err)
return false
}
defer db.Close()
createTableSQL := `
CREATE TABLE IF NOT EXISTS blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user TEXT NOT NULL,
miner TEXT NOT NULL,
minerid TEXT NOT NULL,
height INTEGER,
nonce TEXT NOT NULL,
hash TEXT NOT NULL,
subidx INTEGER,
checked INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
_, err = db.Exec(createTableSQL)
if err != nil {
log.Printf("Error creating table: %v", err)
return false
}
insertSQL := `INSERT INTO blocks (user, miner, minerid, height, nonce, checked, hash, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
_, err = db.Exec(insertSQL, user, miner, minerid, height, nonce, 0, hash, subidx)
if err != nil {
log.Printf("Error inserting data from blocks %s: %v", fmt.Sprint(height), err)
return false
}
return true
}

120
internal/gbt/tari/tari.go Normal file
View File

@ -0,0 +1,120 @@
package tari
import (
"context"
"encoding/base64"
"encoding/hex"
"fmt"
base_node "pool/internal/gbt/tari/proto"
block "pool/internal/gbt/tari/proto/block"
"google.golang.org/grpc"
)
// var PowAlgoMap = []string{"randomxM", "sha3x", "randomxT"}
type BaseNodeClient struct {
Conn *grpc.ClientConn
Client base_node.BaseNodeClient
}
// 创建BaseNode客户端
func NewBaseNodeClient(address string) (*BaseNodeClient, error) {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
return nil, fmt.Errorf("failed to connect to base node: %v", err)
}
// 移除 defer conn.Close(),让连接保持打开状态
client := base_node.NewBaseNodeClient(conn)
return &BaseNodeClient{
Conn: conn,
Client: client,
}, nil
}
// Close 关闭GRPC连接
func (c *BaseNodeClient) Close() error {
if c.Conn != nil {
return c.Conn.Close()
}
return nil
}
type TariBlockTemplate struct {
MiningHash string
Header string
Body string
Height uint64
TargetDifficulty uint64
}
func base64ToHex(data string) (string, error) {
result, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", err
}
return hex.EncodeToString(result), nil
}
func (nc *BaseNodeClient) GetBlockTemplate(ctx context.Context, powIndex uint32) (TariBlockTemplate, error) {
var pow_algo block.PowAlgo_PowAlgos
switch powIndex {
case 0:
pow_algo = block.PowAlgo_POW_ALGOS_RANDOMXM
case 1:
pow_algo = block.PowAlgo_POW_ALGOS_SHA3X
case 2:
pow_algo = block.PowAlgo_POW_ALGOS_RANDOMXT
default:
fmt.Println("不支持", powIndex, "算法")
}
templateReq := &base_node.NewBlockTemplateRequest{
Algo: &block.PowAlgo{
PowAlgo: pow_algo,
},
MaxWeight: 0x00,
}
templateResp, err := nc.Client.GetNewBlockTemplate(ctx, templateReq)
if err != nil {
fmt.Println(pow_algo, "获取区块模板失败:", err)
return TariBlockTemplate{}, err
}
// 节点未同步完成
if !templateResp.InitialSyncAchieved {
fmt.Println("节点还未完成同步")
return TariBlockTemplate{}, err
}
blk_template, miner_data := templateResp.NewBlockTemplate, templateResp.MinerData
targetDifficulty := miner_data.TargetDifficulty
height := blk_template.Header.Height
blockBlob, err := nc.Client.GetNewBlockBlob(ctx, blk_template)
if err != nil {
fmt.Println("获得block blob失败", err)
return TariBlockTemplate{}, err
}
mining_hash, header, body := blockBlob.BlockHash, blockBlob.Header, blockBlob.BlockBody
var t_bt = TariBlockTemplate{
MiningHash: hex.EncodeToString(mining_hash),
Header: hex.EncodeToString(header),
Body: hex.EncodeToString(body),
TargetDifficulty: targetDifficulty,
Height: height,
}
return t_bt, nil
}
func (nc *BaseNodeClient) SubmitBlock(ctx context.Context, header, body []byte) ([]byte, error) {
submitReq := &base_node.BlockBlobRequest{
HeaderBlob: header,
BodyBlob: body,
}
submitResp, err := nc.Client.SubmitBlockBlob(ctx, submitReq)
if err != nil {
fmt.Println("提交区块失败:", err)
return nil, err
}
blockHash := submitResp.BlockHash
return blockHash, nil
}

165
internal/msg/msg.go Normal file
View File

@ -0,0 +1,165 @@
// msg.go
package msg
import (
"time"
"github.com/decred/dcrd/chaincfg/chainhash"
)
type StratumJob struct {
Job_id string `json:"job_id, omitemtpy"`
Version int32 `json:"version, omitemtpy"`
Prevblock chainhash.Hash `json:"prevblock, omitemtpy"`
Coinbase1 string `json:"coinbase1, omitemtpy"`
Coinbase2 string `json:"coinbase2, omitemtpy"`
Bits uint32 `json:"bits, omitemtpy"`
Timestamp time.Time `json:"ts, omitemtpy"`
Extranonce1 string `json:"extranonce1, omitemtpy"`
Extranonce2_size uint64 `json:"extranonce2_size, omitemtpy"`
Extranonce2 string `json:"extranonce2, omitemtpy"`
Nonce string `json:"nonce, omitemtpy`
Target string `json:"target, omitemtpy"`
Difficulty float64 `json:"difficulty, omitemtpy"`
PrevblockS string `json:"prevblocks,omitempty"`
PrevblockBig string `json:"prevblockbig,omitempty"`
Transactions *[]string `json:"transactions,omitempty"`
BitsS string `json:"bitss,omitempty"`
Height uint32 `json:"height,omitempty"`
TransData *[]string `json:"data,omitempty"`
Payloadstart string `json:"payloadstart,omitempty"`
TimestampS string `json:"timestamps, omitempty"`
Segwit string `json:"default_witness_commitment, omitempty"`
IsClean bool `json:"isclean, omitempty"`
Mintime uint32 `json:"mintime, omitempty"`
JobDifficulty float64 `json:"diff, omitempty"`
}
type NexaStratumJob struct {
Header string `json:"header, omitempty"`
NBits string `json:"nBits, omitempty"`
Id uint64 `json:"id, omitempty"`
CurTime uint64 `json:"timestamp, omitempty"`
Target string `json:"target, omitempty"`
Height uint32 `json:"height, omitempty"`
Nonce string `json:"nonce, omitempty"`
Extranonce1 string `json:"extranonce1, omitempty"`
Extranonce2_size uint64 `json:"extranonce2_size, omitempty"`
Extranonce2 string `json:"extranonce2, omitempty"`
JobDifficulty float64 `json:"diff, omitempty"`
}
type BlockNexaMsg struct {
Id uint64 `json:"id"`
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
Header string `json:"header"`
Nonce string `json:"nonce"`
Pow string `json:"pow"`
SubIdx int64 `json:"subidx"`
}
type Sha3xStratumJob struct {
Header string `json:"header, omitempty"`
NBits string `json:"nBits, omitempty"`
Id uint64 `json:"id, omitempty"`
JobId string `json:"job_id", omitempty`
CurTime uint64 `json:"timestamp, omitempty"`
Target string `json:"target, omitempty"`
Height uint32 `json:"height, omitempty"`
Nonce string `json:"nonce, omitempty"`
Extranonce1 string `json:"extranonce1, omitempty"`
Extranonce2_size uint64 `json:"extranonce2_size, omitempty"`
Extranonce2 string `json:"extranonce2, omitempty"`
JobDifficulty float64 `json:"diff, omitempty"`
U64target uint64 `json:"u64target, omitempty"`
}
type BlockSha3xMsg struct {
Id uint64 `json:"id"`
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
Header string `json:"header"`
Nonce uint64 `json:"nonce"`
Pow string `json:"pow"`
SubIdx int64 `json:"subidx"`
Height uint64 `json:"height"`
SubmitIdx uint64 `json:"submitidx"`
}
type Sha3xJob struct {
JobId string
MiningHash string
Height uint64
Header string
Body string
TargetDifficulty uint64
}
type GbtSendMsg struct {
Id uint64
JobId string
MiningHash string
Header string
TargetDifficulty uint64
Height uint64
Target string
Nonce string
Extranonce1 string `json:"extranonce1, omitempty"`
Extranonce2_size uint64 `json:"extranonce2_size, omitempty"`
Extranonce2 string `json:"extranonce2, omitempty"`
}
type MonoreBlockTemplate struct {
BlockhashingBlob string `json:"blockhashing_blob"`
BlocktemplateBlob string `json:"blocktemplate_blob"`
Difficulty uint64 `json:"difficulty"`
DiffcultyTop64 uint64 `json:"difficulty_top64"`
ExpectedReward uint64 `json:"expected_reward"`
Height uint64 `json:"height"`
NextSeedHash string `json:"next_seed_hash"`
PrevHash string `json:"prev_hash"`
ReservedOffset uint64 `json:"reserved_offset"`
SeedHash string `json:"seed_hash"`
SeedHeight uint64 `json:"seed_height"`
Status string `json:"status"`
Untrusted bool `json:"untrusted"`
WideDifficulty string `json:"wide_difficulty"`
}
type MoneroStratumJob struct {
Id uint64 `json:"id"`
JobId string `json:"job_id"`
BlockhashingBlob string `json:"blockhashing_blob"`
BlocktemplateBlob string `json:"blocktemplate_blob"`
Difficulty uint64 `json:"difficulty"`
DiffcultyTop64 uint64 `json:"difficulty_top64"`
ExpectedReward uint64 `json:"expected_reward"`
Height uint64 `json:"height"`
NextSeedHash string `json:"next_seed_hash"`
PrevHash string `json:"prev_hash"`
ReservedOffset uint64 `json:"reserved_offset"`
SeedHash string `json:"seed_hash"`
SeedHeight uint64 `json:"seed_height"`
Status string `json:"status"`
Untrusted bool `json:"untrusted"`
WideDifficulty string `json:"wide_difficulty"`
Target string `json:"target"`
Nonce string `json:"nonce"`
CompleteHeader []byte `json:"completeHeader"`
}
type BlockMoneroMsg struct {
Id uint64 `json:"id"`
User string `json:"user"`
Miner string `json:"miner"`
Index string `json:"index"`
Header string `json:"header"`
Nonce string `json:"nonce"`
Pow string `json:"pow"`
SubIdx int64 `json:"subidx"`
Height uint64 `json:"height"`
SubmitIdx uint64 `json:"submitidx"`
}

View File

@ -0,0 +1,681 @@
// coin.go
package coin
import (
"container/list"
"crypto/md5"
"crypto/rand"
"encoding/base64"
"database/sql"
"encoding/hex"
"io"
"log"
"math"
"math/big"
"net"
"fmt"
"pool/internal/db"
"pool/internal/msg"
"pool/internal/server/diff"
"pool/internal/utility"
"sync"
"time"
"github.com/rs/zerolog"
"github.com/redis/go-redis/v9"
"github.com/zeromq/goczmq"
"go.uber.org/zap"
"gopkg.in/natefinch/lumberjack.v2"
_ "github.com/mattn/go-sqlite3"
)
const JOB_EXPIRED_TIME uint32 = 3600 //job expired time (second)
const LOCAL_JOBS_EXPIRED_TIME uint32 = 3600 //300 //local jobs expired time (second)
const LOCAL_JOBS_TOTAL_SIZE uint32 = 100 //300 //total local jobs
const CONN_EXPIRED_TIME uint32 = 600 //connection expired time
// miner status
// const MINER_STATUS_OFFLINE string = "offline"
const MINER_STATUS_CONNECTED string = "connected"
const MINER_STATUS_SUBSCRIBED string = "subscribed"
const MINER_STATUS_AUTHORIZED string = "authorized"
const MINER_STATUS_RUNNING string = "online"
const MINER_STATUS_DISCONNECTED string = "offline"
const MINER_STATUS_DISABLED string = "disabled"
const MINER_DURATION_TIME time.Duration = 1
const MINER_DIFFICULTY_ADJUST_DURATION time.Duration = 5
// vardiff
const UP_DIFF int = 0
const DOWN_DIFF int = 1
const UPDATE_DIFF int = 2
const DIFFICULTY_WAIT_TIMES int = 6
const (
Low = 0
Mid = 1
Hign = 2
)
type BindConfig struct {
Listen string `json:"listen"`
Auth bool `json:"auth"`
}
type DiffConfig struct {
StartDifficulty float64 `json:"start_diff"`
DiffMin float64 `json:"diff_min"`
DiffMax float64 `json:"diff_max"`
DiffAdjustInterval float64 `json:"diff_adjust_interval"`
DiffAdjustPercentage float64 `json:"diff_adjust_percentage"`
DiffAdjustTime float64 `json:"diff_adjust_time"`
Filter string `json:"filter"`
Dbg bool `json:"dbg"`
}
type ServerConfig struct {
Coin string `json:"coin"`
Host BindConfig `json:"host"`
Diff DiffConfig `json:"diff"`
Zmq utility.ZmqConfig `json:"zmq"`
Redis utility.RedisConfig `json:"redis"`
Zaplog zap.Config `json:"zap"`
Logrotae utility.LogRotateConfig `json:"logrotate"`
}
type CoinObj struct {
Coin string
Init func(server *ServerContext)
Start func()
Stop func()
InitMiner func(miner *MinerObj)
HandleMinerSubscribe func(miner *MinerObj, id float64, extranonce1 string, msg string)
HandleMinerAuth func(miner *MinerObj)
HandleMinerSubmit func(miner *MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool)
SetDifficulty func(miner *MinerObj)
Notify func(miner *MinerObj)
HandleJobMsg func(server *ServerContext, Msg []byte)
IsMhsLow func(miner *MinerObj) bool
GetBlockInterval func() int
}
type PoolBlkMsg struct {
Height int64
Hash string
Pow string
Net_target string
Submit string
Success bool
Accepts float64
Rejects float64
Reward float64
Fee float64
Nonce string
SubIdx int64
}
type ServerContext struct {
CoinCtx CoinObj
DbCtx *db.DbContext
Config *ServerConfig
PubCh *goczmq.Sock
SubCh *goczmq.Sock
Listener net.Listener
MinerType string
Extranonce1 uint64
Difficulty float64
RefDifficulty float64
Accepts float64
Rejects float64
AverageHashrate float64
Miners sync.Map
MMhs sync.Map
Started bool
SLock sync.Mutex
ExitFlag bool
//AlivingChan chan bool
//LiveingExpired bool
FlagAliving int32
FlagAlivingExit int32
ExitPingChan chan bool
ExitJobChan chan bool
Logg *zap.Logger
LogR *lumberjack.Logger
SJob msg.StratumJob
//UpdateMap sync.Map
SyncJobChan chan bool
Synced bool
ExitDbMiners chan bool
ExitDbMinersStats chan bool
ExitDbUser chan bool
ExitDbUserStats chan bool
ExitDbPoolStats chan bool
NexaJob msg.NexaStratumJob
Sha3xJob msg.Sha3xStratumJob
MoneroJob msg.MoneroStratumJob
Tari_Sha3xJob msg.GbtSendMsg
ExitDiffVar chan bool
RedisClient *redis.Client
Accepts5M float64
Accepts15M float64
Accepts30M float64
Accepts1h float64
Accepts3h float64
Accepts6h float64
Accepts12h float64
Accepts24h float64
Accepts48h float64
Rejects5M float64
Rejects15M float64
Rejects30M float64
Rejects1h float64
Rejects3h float64
Rejects6h float64
Rejects12h float64
Rejects24h float64
Rejects48h float64
Mhs5M float64
Mhs15M float64
Mhs30M float64
Mhs1h float64
Mhs3h float64
Mhs6h float64
Mhs12h float64
Mhs24h float64
Mhs48h float64
RejectRatio5M float64
RejectRatio15M float64
RejectRatio30M float64
RejectRatio1h float64
RejectRatio3h float64
RejectRatio6h float64
RejectRatio12h float64
RejectRatio24h float64
RejectRatio48h float64
TotalMiners int64
Normal int64
Abnormal int64
Offline int64
MhsZero int64
MhsLow int64
HighRejects int64
Unstable int64
NetTarget string
NetHight uint64
Submits int64
Blocks int64
Orphans int64
Reward float64
Fee float64
/*Users sync.Map
UsersSLock sync.Mutex*/
/*PoolSLock sync.Mutex*/
SubIdx int64
MinerIndex int64
//NotifyBlkDetailIdx int32
CacheUsers sync.Map
CacheUsersCnt int32
CurrentConns int32
IpCounts map[string]int
IpMutex sync.Mutex
}
type JobListEntry struct {
Job_id string
Ts time.Time
}
type MhsItem struct {
Tt time.Time
Diff float64
}
type MhsObj struct {
MinerId string
Name string
Accepts []MhsItem
Rejects []MhsItem
StartSubmitTime time.Time
StartDayTime time.Time
User string
Miner string
Index string
Status string
Algo int
Release bool
LockForMhs sync.Mutex
}
type VarDiffOptions struct {
VariancePercent float64
AdjustTime float64
AdjustInterval float64
MinDiff float64
MaxDiff float64
MinShares float64
MaxShares float64
TargetShares float64
SubmitShares float64
SilenceCount float64
LastCalcTime time.Time
Uptimes int
Downtimes int
Level int
LastSubmitTime time.Time
}
type BlockMsg struct {
Target string
Submit_target string
Height int64
Success bool
Pow string
Net_target string
Submit string
Hash string
Header string
Accepts float64
Total_accepts float64
Rejects float64
Total_rejects float64
Reward float64
Fee float64
Nonce string
SubIdx int64
}
type MinerObj struct {
Server *ServerContext
Conn net.Conn
Authorized bool
MinerId string
JobId uint32
Name string
Jobs sync.Map
LockForJobs sync.Mutex
JobList *list.List
Target *big.Int
Difficulty float64
DifficultyNext float64
ServerDifficulty float64
ServerTarget *big.Int
ServerTargetS string
Accepts float64
Rejects float64
StartSubmitTime time.Time
LastSubmitime time.Time
SubmitIndex uint32
AverageHashrate float64
M5Accepts float64
M5Hashrate float64
M5SubmitTime time.Time
LastJobId string
LastNonce string
CurHeight uint32
CurHeight64 uint64
Reconnect bool
LastHeader string
VarDiffOpt VarDiffOptions
Version int32
Job msg.StratumJob
User string
PassWord string
Miner string
Session string
Duration float64
Status string
ConnSetupTime time.Time
TxLock sync.Mutex
KeepliveCnt float64
RecvedLiveAck bool
PongFailCnt int
PingCnt int
NexaJob msg.NexaStratumJob
Sha3xJob msg.Sha3xStratumJob
MoneroJob msg.MoneroStratumJob
Tari_Sha3xJob msg.GbtSendMsg
FromIP string
OnlineTime time.Time
OfflineTime time.Time
Retry int64
DurationTime float64
MinerIndex int64
Protocol string
ErrStaleds int64
ErrLowDiffs int64
ErrDuplicates int64
ErrFormats int64
ErrOthers int64
IsDisabled bool
Submits int64
Blocks int64
Orphans int64
Accepts5M float64
Accepts15M float64
Accepts30M float64
Accepts1h float64
Accepts3h float64
Accepts6h float64
Accepts12h float64
Accepts24h float64
Accepts48h float64
Rejects5M float64
Rejects15M float64
Rejects30M float64
Rejects1h float64
Rejects3h float64
Rejects6h float64
Rejects12h float64
Rejects24h float64
Rejects48h float64
Mhs5M float64
Mhs15M float64
Mhs30M float64
Mhs1h float64
Mhs3h float64
Mhs6h float64
Mhs12h float64
Mhs24h float64
Mhs48h float64
RejectRatio5M float64
RejectRatio15M float64
RejectRatio30M float64
RejectRatio1h float64
RejectRatio3h float64
RejectRatio6h float64
RejectRatio12h float64
RejectRatio24h float64
RejectRatio48h float64
Reward float64
Fee float64
Zlog zerolog.Logger
LogR *lumberjack.Logger
ZlogInit bool
//EndCh chan bool
DiffHandler diff.KalmanVarDiff
NeedExit int32
PingEnabled bool
}
/*type UserBlockMsg struct {
User string
Miner string
Index string
Height int64
Hash string
Pow string
Net_target string
Submit string
Success bool
Accepts float64
Rejects float64
Reward float64
Fee float64
Nonce string
SubIdx int64
}*/
/*
type UserMinerContainer struct {
Data map[string]string
}*/
/*
type UserObj struct {
Server *ServerContext
User string
Name string
Normal int64
Abnormal int64
Offline int64
MhsZero int64
MhsLow int64
HighRejects int64
Unstable int64
Submits int64
Blocks int64
Orphans int64
Reward float64
Fee float64
Accepts5M float64
Accepts15M float64
Accepts30M float64
Accepts1h float64
Accepts3h float64
Accepts6h float64
Accepts12h float64
Accepts24h float64
Accepts48h float64
Rejects5M float64
Rejects15M float64
Rejects30M float64
Rejects1h float64
Rejects3h float64
Rejects6h float64
Rejects12h float64
Rejects24h float64
Rejects48h float64
Mhs5M float64
Mhs15M float64
Mhs30M float64
Mhs1h float64
Mhs3h float64
Mhs6h float64
Mhs12h float64
Mhs24h float64
Mhs48h float64
RejectRatio5M float64
RejectRatio15M float64
RejectRatio30M float64
RejectRatio1h float64
RejectRatio3h float64
RejectRatio6h float64
RejectRatio12h float64
RejectRatio24h float64
RejectRatio48h float64
}*/
func md5md5(v string) string {
md5Obj := md5.New()
md5Obj.Write([]byte(v))
char := md5Obj.Sum(nil)
return hex.EncodeToString(char)
}
func Guid() string {
c := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, c); err != nil {
return ""
}
return md5md5(base64.URLEncoding.EncodeToString(c))
}
func VarAdjustDifficulty(miner *MinerObj, adjust int) {
if adjust != UP_DIFF && adjust != DOWN_DIFF && adjust != UPDATE_DIFF {
miner.Server.Logg.Error("[server]", zap.Int("Not support adjust ", adjust))
return
}
if adjust == UP_DIFF {
miner.DifficultyNext = miner.Difficulty
if miner.VarDiffOpt.Level == Mid {
miner.DifficultyNext *= math.Pow(2, 1)
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
} else if miner.VarDiffOpt.Level == Hign {
miner.DifficultyNext *= math.Pow(2, 2)
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
}
} else if adjust == DOWN_DIFF {
miner.DifficultyNext = miner.Difficulty
if miner.VarDiffOpt.Level == Mid {
miner.DifficultyNext /= math.Pow(2, 1)
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
} else if miner.VarDiffOpt.Level == Hign {
miner.DifficultyNext /= math.Pow(2, 2)
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
}
} else if adjust == UPDATE_DIFF {
if miner.VarDiffOpt.SubmitShares > 0 {
// re-target if outside bounds
if miner.VarDiffOpt.SubmitShares < miner.VarDiffOpt.MinShares || miner.VarDiffOpt.SubmitShares > miner.VarDiffOpt.MaxShares {
var change float64 = miner.VarDiffOpt.SubmitShares / miner.VarDiffOpt.TargetShares
miner.DifficultyNext = miner.Difficulty
miner.DifficultyNext *= change
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
}
miner.VarDiffOpt.SilenceCount = 0
} else {
// radical measures if there were no shares submitted
miner.VarDiffOpt.SilenceCount++
miner.DifficultyNext = miner.Difficulty / math.Pow(2, miner.VarDiffOpt.SilenceCount)
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
}
}
if miner.DifficultyNext < miner.VarDiffOpt.MinDiff {
miner.DifficultyNext = miner.VarDiffOpt.MinDiff
} else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff {
miner.DifficultyNext = miner.VarDiffOpt.MaxDiff
}
miner.VarDiffOpt.TargetShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext
miner.VarDiffOpt.MinShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext * (1 - miner.VarDiffOpt.VariancePercent)
miner.VarDiffOpt.MaxShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext * (1 + miner.VarDiffOpt.VariancePercent)
miner.VarDiffOpt.SubmitShares = 0
miner.VarDiffOpt.Uptimes = 0
miner.VarDiffOpt.Downtimes = 0
miner.Server.Logg.Info("[server]", zap.Float64("DifficultyNext", miner.DifficultyNext))
miner.Server.Logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares))
now := time.Now()
share_interval := now.Sub(miner.LastSubmitime).Seconds()
New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, miner.DifficultyNext, miner.VarDiffOpt.SubmitShares, share_interval, miner.VarDiffOpt.MinShares, miner.VarDiffOpt.MaxShares)
}
var gdiff_db *sql.DB
func Init_diff_db() {
db, err := sql.Open("sqlite3", "./diffs.db")
if err != nil {
log.Printf("Error opening database: %v", err)
return
}
//defer db.Close()
gdiff_db = db
createTableSQL := `
CREATE TABLE IF NOT EXISTS diffs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts TEXT NOT NULL,
user TEXT NOT NULL,
miner TEXT NOT NULL,
minerid TEXT NOT NULL,
diff REAL NOT NULL,
next REAL NOT NULL,
kp REAL NOT NULL,
interval REAL NOT NULL,
mhs REAL NOT NULL,
mhs_est REAL NOT NULL
);`
_, err = gdiff_db.Exec(createTableSQL)
if err != nil {
log.Printf("Error creating table: %v", err)
return
}
}
func New_diff_into_db(user string, miner string, minerid string, diff float64, diff_next float64, kp float64, interval float64, mhs float64, mhs_est float64) {
if gdiff_db != nil {
insertSQL := `INSERT INTO diffs (ts, user, miner, minerid, diff, next, kp, interval, mhs, mhs_est) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
_, err := gdiff_db.Exec(insertSQL, time.Now().Format("2006-01-02 15:04:05"), user, miner, minerid, diff, diff_next, kp, interval, mhs, mhs_est)
if err != nil {
log.Printf("Error inserting data from diffs %s: %v", user+"."+miner+"_"+minerid, err)
return
}
}
}
func DiffStop() {
if gdiff_db != nil {
defer gdiff_db.Close()
}
}

1224
internal/server/dbif/dbif.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
// diff.go
package diff
import (
"fmt"
"math"
"strconv"
"strings"
)
type KalmanVarDiff struct {
Kf *KalmanFilter
StartDiff float64
MinDiff float64
MaxDiff float64
TargetInterval float64
MhsEst float64
DiffEst float64
}
type KalmanFilter struct {
X float64 // 估计的状态
P float64 // 状态协方差
F float64 // 状态转移矩阵
H float64 // 观测矩阵
Q float64 // 过程噪声协方差
R float64 // 观测噪声协方差
K float64 // 卡尔曼增益
}
func NewKalmanFilter(init_mhs float64, init_state_p float64) *KalmanFilter {
x := init_mhs
p := init_state_p
f := 1.0
h := 1.0
q := 0.01
r := init_mhs * 3
//r := 1.0
return &KalmanFilter{
X: x,
P: p,
F: f,
H: h,
Q: q,
R: r,
}
/*
return &KalmanFilter{
X: 1.0,
P: 1.0,
F: 1.0,
H: 1.0,
Q: 0.1,
R: 1.0,
}*/
}
func (kf *KalmanFilter) Update(measurement float64) (float64, float64) {
kf.R = measurement * 2
// 预测
p := kf.X*kf.Q + kf.P
// 计算卡尔曼增益
kf.K = p / (p + kf.R + 1)
// 更新状态估计
if measurement >= kf.X {
kf.X = kf.X + kf.K*(measurement-kf.X)
} else {
kf.X = kf.X - kf.K*(kf.X-measurement)
}
// 更新协方差矩阵
kf.P = (1 - kf.K) * p
// 自适应调整过程噪声和观测噪声
//kf.adapt()
return kf.X, kf.P
}
func (kf *KalmanFilter) adapt() {
// 自适应调整参数
if kf.P > 10.0 {
kf.Q *= 1.1 // 增加过程噪声
} else {
kf.Q *= 0.9 // 减少过程噪声
}
if kf.K > 0.5 {
kf.R *= 1.1 // 增加观测噪声
} else {
kf.R *= 0.9 // 减少观测噪声
}
}
func (kd *KalmanVarDiff) Init(startDiff float64, minDiff float64, maxDiff float64, targetTime float64) {
kd.StartDiff = startDiff
kd.MinDiff = minDiff
kd.MaxDiff = maxDiff
kd.TargetInterval = targetTime
kd.DiffEst = startDiff
kd.MhsEst = startDiff / targetTime
kd.Kf = NewKalmanFilter(startDiff/targetTime, 1.0)
}
func (kd *KalmanVarDiff) DeInit() {
}
// 提取科学计数法有效数字(整数部分和一位小数)及指数,并合并为新的浮点数
func extractAndCombine(num float64) float64 {
// 将浮点数格式化为科学计数法
scientificStr := fmt.Sprintf("%.10e", num)
// 分离小数部分和指数部分
parts := strings.Split(scientificStr, "e")
if len(parts) != 2 {
fmt.Println("Error: unexpected scientific notation format")
return 0
}
// 处理小数部分
decimalPart := parts[0]
exponentPart := parts[1]
// 去除小数部分前的 "0."
decimalPart = strings.TrimPrefix(decimalPart, "0.")
// 提取整数部分和一位小数
decimalParts := strings.Split(decimalPart, ".")
if len(decimalParts) < 2 {
decimalPart = decimalParts[0] + ".0" // 没有小数部分时,添加 ".0"
} else {
decimalPart = decimalParts[0] + "." + decimalParts[1][:1] // 只取一位小数
//decimalPart = decimalParts[0]
}
// 将指数部分转换为整数
exponent, err := strconv.Atoi(exponentPart)
if err != nil {
fmt.Println("Error parsing exponent:", err)
return 0
}
// 计算新的浮点数
newNumber := (func() float64 {
digit, err := strconv.ParseFloat(decimalPart, 64)
if err != nil {
fmt.Println("Error parsing decimal part:", err)
return 0
}
return digit * math.Pow(10, float64(exponent))
})()
return newNumber
}
func (kd *KalmanVarDiff) Handler(diff float64, interval float64) (float64, float64) {
//newx, newp := kd.Kf.Update(kd.DiffEst / interval)
newx, newp := kd.Kf.Update(diff / interval)
kd.MhsEst = newx
newdiff := newx * kd.TargetInterval
kd.DiffEst = newdiff
newdiff2 := extractAndCombine(newdiff)
return newdiff2, newp
}

View File

@ -0,0 +1,14 @@
#ifndef NEXAAPI_H
#define NEXAAPI_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool nexa_hash( unsigned char *out, unsigned char *in);
bool nexa_hash12( unsigned char *out, unsigned char *in);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,288 @@
/*
Copyright (c) 2018-2019, tevador <tevador@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RANDOMX_H
#define RANDOMX_H
#include <stddef.h>
#include <stdint.h>
#define RANDOMX_HASH_SIZE 32
#define RANDOMX_DATASET_ITEM_SIZE 64
#ifndef RANDOMX_EXPORT
#define RANDOMX_EXPORT
#endif
typedef enum {
RANDOMX_FLAG_DEFAULT = 0,
RANDOMX_FLAG_LARGE_PAGES = 1,
RANDOMX_FLAG_HARD_AES = 2,
RANDOMX_FLAG_FULL_MEM = 4,
RANDOMX_FLAG_JIT = 8,
RANDOMX_FLAG_SECURE = 16,
RANDOMX_FLAG_ARGON2_SSSE3 = 32,
RANDOMX_FLAG_ARGON2_AVX2 = 64,
RANDOMX_FLAG_ARGON2 = 96
} randomx_flags;
typedef struct randomx_dataset randomx_dataset;
typedef struct randomx_cache randomx_cache;
typedef struct randomx_vm randomx_vm;
#if defined(__cplusplus)
#ifdef __cpp_constexpr
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif
inline CONSTEXPR randomx_flags operator |(randomx_flags a, randomx_flags b) {
return static_cast<randomx_flags>(static_cast<int>(a) | static_cast<int>(b));
}
inline CONSTEXPR randomx_flags operator &(randomx_flags a, randomx_flags b) {
return static_cast<randomx_flags>(static_cast<int>(a) & static_cast<int>(b));
}
inline randomx_flags& operator |=(randomx_flags& a, randomx_flags b) {
return a = a | b;
}
extern "C" {
#endif
/**
* @return The recommended flags to be used on the current machine.
* Does not include:
* RANDOMX_FLAG_LARGE_PAGES
* RANDOMX_FLAG_FULL_MEM
* RANDOMX_FLAG_SECURE
* These flags must be added manually if desired.
* On OpenBSD RANDOMX_FLAG_SECURE is enabled by default in JIT mode as W^X is enforced by the OS.
*/
RANDOMX_EXPORT randomx_flags randomx_get_flags(void);
/**
* Creates a randomx_cache structure and allocates memory for RandomX Cache.
*
* @param flags is any combination of these 2 flags (each flag can be set or not set):
* RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages
* RANDOMX_FLAG_JIT - create cache structure with JIT compilation support; this makes
* subsequent Dataset initialization faster
* Optionally, one of these two flags may be selected:
* RANDOMX_FLAG_ARGON2_SSSE3 - optimized Argon2 for CPUs with the SSSE3 instruction set
* makes subsequent cache initialization faster
* RANDOMX_FLAG_ARGON2_AVX2 - optimized Argon2 for CPUs with the AVX2 instruction set
* makes subsequent cache initialization faster
*
* @return Pointer to an allocated randomx_cache structure.
* Returns NULL if:
* (1) memory allocation fails
* (2) the RANDOMX_FLAG_JIT is set and JIT compilation is not supported on the current platform
* (3) an invalid or unsupported RANDOMX_FLAG_ARGON2 value is set
*/
RANDOMX_EXPORT randomx_cache *randomx_alloc_cache(randomx_flags flags);
/**
* Initializes the cache memory and SuperscalarHash using the provided key value.
* Does nothing if called again with the same key value.
*
* @param cache is a pointer to a previously allocated randomx_cache structure. Must not be NULL.
* @param key is a pointer to memory which contains the key value. Must not be NULL.
* @param keySize is the number of bytes of the key.
*/
RANDOMX_EXPORT void randomx_init_cache(randomx_cache *cache, const void *key, size_t keySize);
/**
* Returns a pointer to the internal memory buffer of the cache structure. The size
* of the internal memory buffer is RANDOMX_ARGON_MEMORY KiB.
*
* @param cache is a pointer to a previously allocated randomx_cache structure. Must not be NULL.
*
* @return Pointer to the internal memory buffer of the cache structure.
*/
RANDOMX_EXPORT void *randomx_get_cache_memory(randomx_cache *cache);
/**
* Releases all memory occupied by the randomx_cache structure.
*
* @param cache is a pointer to a previously allocated randomx_cache structure.
*/
RANDOMX_EXPORT void randomx_release_cache(randomx_cache* cache);
/**
* Creates a randomx_dataset structure and allocates memory for RandomX Dataset.
*
* @param flags is the initialization flags. Only one flag is supported (can be set or not set):
* RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages
*
* @return Pointer to an allocated randomx_dataset structure.
* NULL is returned if memory allocation fails.
*/
RANDOMX_EXPORT randomx_dataset *randomx_alloc_dataset(randomx_flags flags);
/**
* Gets the number of items contained in the dataset.
*
* @return the number of items contained in the dataset.
*/
RANDOMX_EXPORT unsigned long randomx_dataset_item_count(void);
/**
* Initializes dataset items.
*
* Note: In order to use the Dataset, all items from 0 to (randomx_dataset_item_count() - 1) must be initialized.
* This may be done by several calls to this function using non-overlapping item sequences.
*
* @param dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL.
* @param cache is a pointer to a previously allocated and initialized randomx_cache structure. Must not be NULL.
* @param startItem is the item number where initialization should start.
* @param itemCount is the number of items that should be initialized.
*/
RANDOMX_EXPORT void randomx_init_dataset(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount);
/**
* Returns a pointer to the internal memory buffer of the dataset structure. The size
* of the internal memory buffer is randomx_dataset_item_count() * RANDOMX_DATASET_ITEM_SIZE.
*
* @param dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL.
*
* @return Pointer to the internal memory buffer of the dataset structure.
*/
RANDOMX_EXPORT void *randomx_get_dataset_memory(randomx_dataset *dataset);
/**
* Releases all memory occupied by the randomx_dataset structure.
*
* @param dataset is a pointer to a previously allocated randomx_dataset structure.
*/
RANDOMX_EXPORT void randomx_release_dataset(randomx_dataset *dataset);
/**
* Creates and initializes a RandomX virtual machine.
*
* @param flags is any combination of these 5 flags (each flag can be set or not set):
* RANDOMX_FLAG_LARGE_PAGES - allocate scratchpad memory in large pages
* RANDOMX_FLAG_HARD_AES - virtual machine will use hardware accelerated AES
* RANDOMX_FLAG_FULL_MEM - virtual machine will use the full dataset
* RANDOMX_FLAG_JIT - virtual machine will use a JIT compiler
* RANDOMX_FLAG_SECURE - when combined with RANDOMX_FLAG_JIT, the JIT pages are never
* writable and executable at the same time (W^X policy)
* The numeric values of the first 4 flags are ordered so that a higher value will provide
* faster hash calculation and a lower numeric value will provide higher portability.
* Using RANDOMX_FLAG_DEFAULT (all flags not set) works on all platforms, but is the slowest.
* @param cache is a pointer to an initialized randomx_cache structure. Can be
* NULL if RANDOMX_FLAG_FULL_MEM is set.
* @param dataset is a pointer to a randomx_dataset structure. Can be NULL
* if RANDOMX_FLAG_FULL_MEM is not set.
*
* @return Pointer to an initialized randomx_vm structure.
* Returns NULL if:
* (1) Scratchpad memory allocation fails.
* (2) The requested initialization flags are not supported on the current platform.
* (3) cache parameter is NULL and RANDOMX_FLAG_FULL_MEM is not set
* (4) dataset parameter is NULL and RANDOMX_FLAG_FULL_MEM is set
*/
RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset);
/**
* Reinitializes a virtual machine with a new Cache. This function should be called anytime
* the Cache is reinitialized with a new key. Does nothing if called with a Cache containing
* the same key value as already set.
*
* @param machine is a pointer to a randomx_vm structure that was initialized
* without RANDOMX_FLAG_FULL_MEM. Must not be NULL.
* @param cache is a pointer to an initialized randomx_cache structure. Must not be NULL.
*/
RANDOMX_EXPORT void randomx_vm_set_cache(randomx_vm *machine, randomx_cache* cache);
/**
* Reinitializes a virtual machine with a new Dataset.
*
* @param machine is a pointer to a randomx_vm structure that was initialized
* with RANDOMX_FLAG_FULL_MEM. Must not be NULL.
* @param dataset is a pointer to an initialized randomx_dataset structure. Must not be NULL.
*/
RANDOMX_EXPORT void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset *dataset);
/**
* Releases all memory occupied by the randomx_vm structure.
*
* @param machine is a pointer to a previously created randomx_vm structure.
*/
RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine);
/**
* Calculates a RandomX hash value.
*
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
* @param input is a pointer to memory to be hashed. Must not be NULL.
* @param inputSize is the number of bytes to be hashed.
* @param output is a pointer to memory where the hash will be stored. Must not
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
*/
RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output);
/**
* Set of functions used to calculate multiple RandomX hashes more efficiently.
* randomx_calculate_hash_first will begin a hash calculation.
* randomx_calculate_hash_next will output the hash value of the previous input
* and begin the calculation of the next hash.
* randomx_calculate_hash_last will output the hash value of the previous input.
*
* WARNING: These functions may alter the floating point rounding mode of the calling thread.
*
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
* @param input is a pointer to memory to be hashed. Must not be NULL.
* @param inputSize is the number of bytes to be hashed.
* @param nextInput is a pointer to memory to be hashed for the next hash. Must not be NULL.
* @param nextInputSize is the number of bytes to be hashed for the next hash.
* @param output is a pointer to memory where the hash will be stored. Must not
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
*/
RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize);
RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output);
RANDOMX_EXPORT void randomx_calculate_hash_last(randomx_vm* machine, void* output);
/**
* Calculate a RandomX commitment from a RandomX hash and its input.
*
* @param input is a pointer to memory that was hashed. Must not be NULL.
* @param inputSize is the number of bytes in the input.
* @param hash_in is the output from randomx_calculate_hash* (RANDOMX_HASH_SIZE bytes).
* @param com_out is a pointer to memory where the commitment will be stored. Must not
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
*/
RANDOMX_EXPORT void randomx_calculate_commitment(const void* input, size_t inputSize, const void* hash_in, void* com_out);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -0,0 +1,4 @@
#ifndef SHA3X_API_H
#define SHA3X_API_H
void sha3x_hash(unsigned char * out, unsigned char * in);
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,117 @@
package monero
/*
#cgo CFLAGS: -I/home/lizixuan/桌面/tari-server/internal/server/include
#cgo LDFLAGS: -L/home/lizixuan/桌面/tari-server/internal/server/lib/randomx -lrandomx
#include <randomx.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
*/
import "C"
import (
"fmt"
"unsafe"
"golang.org/x/sys/cpu"
)
type RandomXValidator struct {
cache *C.randomx_cache
vm *C.randomx_vm
flags C.randomx_flags
seed []byte
}
// NewRandomXValidator 初始化 cache + vm
func NewRandomXValidator(seed []byte) (*RandomXValidator, error) {
if len(seed) != 32 {
return nil, fmt.Errorf("seed must be 32 bytes")
}
var flags C.randomx_flags = 0
// 检测 AES-NI 支持
if cpu.X86.HasAES {
flags |= C.RANDOMX_FLAG_HARD_AES
} else {
fmt.Println("[RandomX] CPU 不支持 AES-NI将使用纯软件模式")
}
// ⚠️ 默认启用 JIT如果系统禁止会报错
flags |= C.RANDOMX_FLAG_JIT
// 分配 cache
cache := C.randomx_alloc_cache(flags)
if cache == nil {
return nil, fmt.Errorf("failed to alloc cache")
}
C.randomx_init_cache(cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
// 创建 vm
vm := C.randomx_create_vm(flags, cache, nil)
if vm == nil {
C.randomx_release_cache(cache)
return nil, fmt.Errorf("failed to create randomx vm")
}
return &RandomXValidator{
cache: cache,
vm: vm,
flags: flags,
seed: append([]byte{}, seed...),
}, nil
}
// SetSeed 更新 seed替换 cache并重置 vm
func (v *RandomXValidator) SetSeed(seed []byte) error {
if len(seed) != 32 {
return fmt.Errorf("seed must be 32 bytes")
}
// 如果相同 seed不用更新
if string(seed) == string(v.seed) {
return nil
}
C.randomx_init_cache(v.cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
C.randomx_vm_set_cache(v.vm, v.cache)
v.seed = append(v.seed[:0], seed...)
return nil
}
// Destroy 释放 vm + cache
func (v *RandomXValidator) Destroy() {
if v.vm != nil {
C.randomx_destroy_vm(v.vm)
v.vm = nil
}
if v.cache != nil {
C.randomx_release_cache(v.cache)
v.cache = nil
}
}
// BuildPowHash 计算区块哈希
func (v *RandomXValidator) BuildPowHash(blockBlob, nonce []byte) ([]byte, []byte, error) {
if v.vm == nil {
return nil, nil, fmt.Errorf("vm is nil")
}
if len(nonce) != 4 {
return nil, nil, fmt.Errorf("nonce must be 4 bytes")
}
blockHeader := make([]byte, len(blockBlob))
copy(blockHeader, blockBlob)
copy(blockHeader[39:43], nonce)
var hash [32]byte
C.randomx_calculate_hash(v.vm,
unsafe.Pointer(&blockHeader[0]),
C.size_t(len(blockHeader)),
unsafe.Pointer(&hash[0]),
)
return hash[:], blockHeader, nil
}

View File

@ -0,0 +1,756 @@
package monero
import (
"crypto/rand"
"strings"
//"database/sql"
"encoding/hex"
"encoding/json"
//"log"
//"math"
"math/big"
//"strings"
"fmt"
"pool/internal/msg"
"pool/internal/server/coin"
"pool/internal/server/dbif"
"pool/internal/stratum"
"pool/internal/utility"
"time"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
const SERVER_MONERO_VERSION string = "monero v0.1a"
type ServerMoneroContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
Sha3xJob msg.Sha3xStratumJob
RandomxVM *RandomXValidator
}
var logg *zap.Logger
var ServerMoneroCtx ServerMoneroContext
type MoneroNotify_params_msg struct {
Id string `json:"id"`
JobId string `json:"job_id"`
SeedHash string `json:"seed_hash"`
Blob string `json:"blob"`
Height uint32 `json:"height"`
Target string `json:"target"`
NextSeedHash string `json:"next_seed_hash"`
Algo string `json:"algo"`
}
type Monero_msg struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params MoneroNotify_params_msg `json:"params"`
}
// 辅助函数:反转每个字节的小端 hex
func reverseHexBytes(s string) string {
if len(s)%2 != 0 {
s = "0" + s
}
res := ""
for i := len(s); i > 0; i -= 2 {
res += s[i-2 : i]
}
return res
}
func calc_target(diff uint64) string {
difficulty := new(big.Int)
difficulty.SetString(fmt.Sprintf("%d", diff), 10)
// 2^256 - 1
max := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
// target = (2^256 - 1) / difficulty
target := new(big.Int).Div(max, difficulty)
// 转为32字节 hex大端
targetHexBE := fmt.Sprintf("%064x", target)
return targetHexBE
}
func calc_diff(hash string) uint64 {
be := reverseHexBytes(hash)
target_be := new(big.Int)
target_be.SetString(be, 16)
max := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
difficulty := new(big.Rat).SetFrac(max, target_be)
// Convert *big.Rat to *big.Float, then to uint64
diffFloat := new(big.Float).SetRat(difficulty)
result, _ := diffFloat.Uint64()
return result
}
func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
var submit_item coin.BlockMsg
/*var user_blk_item coin.UserBlockMsg*/
var pool_blk_item coin.PoolBlkMsg
var blk_detail_height int64
var blk_detail_hash string
var blk_detail_success bool
var blk_detail_miner_diff float64
var blk_detail_pool_diff float64
if miner.Authorized != true {
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNAUTH_WORKER)
stratum.Send_reconnect_msg(miner)
return false, false, false
}
var new_found bool = false
var ack stratum.Submit_ack
ack.ID = id
ack.Result = true
// fmt.Println("提交job_id:", job_id)
var keys []string
miner.Jobs.Range(func(k, v interface{}) bool {
if key, ok := k.(string); ok {
keys = append(keys, key)
}
return true // 继续遍历
})
// fmt.Println("目前任务所有key:", keys)
v, ok := miner.Jobs.Load(job_id)
if ok {
job := v.(msg.MoneroStratumJob)
if uint32(job.Height) < miner.CurHeight-1 {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_STALED_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
if (miner.LastNonce != nonce) || (miner.MoneroJob.BlocktemplateBlob != job.BlocktemplateBlob) {
miner.MoneroJob.BlocktemplateBlob = job.BlocktemplateBlob
miner.LastNonce = nonce
job.Nonce = nonce
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
}
var calc_hash []byte
var completeHeader []byte
nonceByte, err := hex.DecodeString(nonce)
if err != nil {
fmt.Println(err)
return false, false, false
}
headerByte, err := hex.DecodeString(job.BlockhashingBlob)
if err != nil {
fmt.Println(err)
return false, false, false
}
calc_hash, completeHeader, err = ServerMoneroCtx.RandomxVM.BuildPowHash(headerByte, nonceByte)
if err != nil {
fmt.Println("calc_hash error:", err)
return false, false, false
}
job.CompleteHeader = completeHeader
if miner.ZlogInit {
miner.Zlog.Info().Msg("hash in " + submit_item.Header + " calc_hash " + hex.EncodeToString(calc_hash) + " " + miner.User + "." + miner.Miner)
}
submit_target := new(big.Int)
submit_target.SetBytes(calc_hash)
calc_diff := utility.MoneroTarget2Diff(calc_hash)
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " target diff " + fmt.Sprintf("%f", (miner.Difficulty)) + " submit diff " + fmt.Sprintf("%f", (calc_diff)))
}
if calc_diff < float64(job.Difficulty) {
ack.Result = false
miner.ErrLowDiffs = miner.ErrLowDiffs + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE)
return false, false, false
}
stb, _ := hex.DecodeString(job.Target)
server_diff := utility.MoneroTarget2Diff(utility.Reverse(stb))
network_target := new(big.Int)
network_target.SetBytes(stb)
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " calc_diff " + fmt.Sprintf("%f", (calc_diff)) + " miner.Difficulty " + fmt.Sprintf("%f", (miner.Difficulty)) + " server_diff " + fmt.Sprintf("%f", (server_diff)))
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " submit_target " + hex.EncodeToString(submit_target.Bytes()) + " network_target " + hex.EncodeToString(network_target.Bytes()) + " target " + hex.EncodeToString(miner.ServerTarget.Bytes()) + " cmp " + fmt.Sprintf("%d", (network_target.Cmp(submit_target))))
}
submit_item.Hash = hex.EncodeToString(calc_hash)
submit_item.Target = hex.EncodeToString(miner.Target.Bytes())
submit_item.Submit_target = hex.EncodeToString(calc_hash)
submit_item.Height = int64(job.Height)
submit_item.Pow = hex.EncodeToString(calc_hash)
submit_item.Net_target = hex.EncodeToString(network_target.Bytes())
pool_blk_item.Height = int64(job.Height)
pool_blk_item.Hash = hex.EncodeToString(calc_hash)
pool_blk_item.Pow = hex.EncodeToString(calc_hash)
pool_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())
blk_detail_height = int64(job.Height)
blk_detail_hash = hex.EncodeToString(calc_hash)
blk_detail_success = false
blk_detail_miner_diff = float64(job.Difficulty)
blk_detail_pool_diff = miner.Server.RefDifficulty
if ack.Result == true {
if (calc_diff >= server_diff) || (network_target.Cmp(submit_target) >= 0) {
miner.Server.SubIdx++
Produce_block_submit(miner /*header,*/, &job, submit_item.Hash, miner.Server.SubIdx)
miner.SubmitIndex++
miner.Submits = miner.Submits + 1
new_found = true
}
if new_found && float64(miner.Server.MoneroJob.Difficulty) <= calc_diff {
pool_blk_item.Submit = "y"
pool_blk_item.Success = false
pool_blk_item.Accepts = miner.Accepts
pool_blk_item.Rejects = miner.Rejects
pool_blk_item.Reward = 0
pool_blk_item.Fee = 0
pool_blk_item.Nonce = nonce
pool_blk_item.SubIdx = miner.Server.SubIdx
dbif.NotifyPoolBlkStatsDb2(miner.Server, &pool_blk_item)
}
}
} else {
miner.LastHeader = job.BlocktemplateBlob
miner.LastNonce = nonce
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_DUP_SHARE)
miner.ErrDuplicates = miner.ErrDuplicates + 1
return false, false, false
}
} else {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_FOUND_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
miner.LastJobId = job_id
ack.Error = nil
body, err := json.Marshal(ack)
if err != nil {
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit Marshal " + err.Error())
}
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNKNOWN)
return false, false, false
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//miner.Server.Miners.Delete(miner.MinerId)
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
miner.TxLock.Lock()
miner.Status = coin.MINER_STATUS_RUNNING
miner.TxLock.Unlock()
if ack.Result {
miner.Accepts += miner.Difficulty
miner.M5Accepts += miner.Difficulty
miner.VarDiffOpt.SubmitShares += miner.Difficulty
} else {
miner.Rejects += miner.Difficulty
}
now := time.Now()
if miner.Server.Config.Diff.Filter == "kalman" {
if ack.Result {
share_interval := now.Sub(miner.LastSubmitime).Seconds()
mhs := miner.Difficulty * share_interval
diff_next, kalman_p := miner.DiffHandler.Handler(miner.Difficulty, share_interval)
mhs_est := diff_next * miner.Server.Config.Diff.DiffAdjustInterval
ratio := diff_next / miner.Difficulty
if ratio > 0 {
if now.Sub(miner.StartSubmitTime).Seconds() > 180 {
if ratio >= 2 {
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else if ratio <= 0.5 {
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else {
}
} else {
miner.DifficultyNext = diff_next * 10000000 / 10000000
}
}
if miner.DifficultyNext > 0.0 {
if miner.DifficultyNext < miner.VarDiffOpt.MinDiff {
miner.DifficultyNext = miner.VarDiffOpt.MinDiff
} else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff {
miner.DifficultyNext = miner.VarDiffOpt.MaxDiff
}
}
if miner.Server.Config.Diff.Dbg {
coin.New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, diff_next, kalman_p, share_interval, mhs, mhs_est)
}
}
} else {
if now.Sub(miner.LastSubmitime).Seconds() < miner.Server.Config.Diff.DiffAdjustInterval {
if ack.Result {
if miner.VarDiffOpt.Uptimes++; miner.VarDiffOpt.Uptimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.UP_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Uptimes = 0
}
if now.Sub(miner.LastSubmitime).Seconds() > miner.Server.Config.Diff.DiffAdjustInterval*2 {
if ack.Result {
if miner.VarDiffOpt.Downtimes++; miner.VarDiffOpt.Downtimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.DOWN_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Downtimes = 0
}
}
if ack.Result {
miner.LastSubmitime = now
miner.VarDiffOpt.LastSubmitTime = now
}
var duration float64 = float64(now.Sub(miner.StartSubmitTime)) / 1000000000
if duration < 1 {
duration = 1
}
diffOneShareHashesAvg := uint64(0xFFFFFFFFFFFFFFFF)
miner.AverageHashrate = miner.Accepts * float64(diffOneShareHashesAvg) / duration / 1000000
var m5_duration float64 = float64(now.Sub(miner.M5SubmitTime)) / 1000000000
if m5_duration >= float64(time.Minute*5)/1000000000 {
miner.M5SubmitTime = now
miner.M5Hashrate = miner.M5Accepts * float64(diffOneShareHashesAvg) / m5_duration / 1000000
miner.M5Accepts = 0
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit M5Accepts " + fmt.Sprintf("%f", (miner.M5Accepts)) + " M5Hashrate(MH/S) " + fmt.Sprintf("%f", (miner.M5Hashrate)))
}
if miner.Server.Config.Diff.Filter == "kalman" {
} else {
if float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000 >= miner.VarDiffOpt.AdjustTime {
coin.VarAdjustDifficulty(miner, coin.UPDATE_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
if ack.Result {
submit_item.Success = false
if new_found {
submit_item.Submit = "y"
submit_item.SubIdx = miner.Server.SubIdx
} else {
submit_item.Submit = "n"
submit_item.SubIdx = -1
}
submit_item.Accepts = miner.Accepts
submit_item.Total_accepts = miner.Accepts
submit_item.Rejects = miner.Rejects
submit_item.Total_rejects = miner.Rejects
submit_item.Reward = 0
submit_item.Fee = 0
submit_item.Nonce = nonce
dbif.NotifyBlkDetailDb(miner, blk_detail_height, blk_detail_hash, blk_detail_success, blk_detail_miner_diff, blk_detail_pool_diff, nonce, submit_item.SubIdx)
return true, new_found, true
}
return false, false, true
}
func contractBlockTemplateBlob(miner *coin.MinerObj, nonceHex string) (string, error) {
blockTemplateStr := miner.MoneroJob.BlocktemplateBlob
block, err := hex.DecodeString(blockTemplateStr)
if err != nil {
return "", err
}
if len(block) < 43 {
return "", fmt.Errorf("blocktemplate blob too short: %d", len(block))
}
// nonce 是 4 字节 hex直接解码成 bytes
nonceBytes, err := hex.DecodeString(nonceHex)
if err != nil {
return "", fmt.Errorf("invalid nonce hex: %v", err)
}
if len(nonceBytes) != 4 {
return "", fmt.Errorf("nonce must be 4 bytes, got %d", len(nonceBytes))
}
// 覆盖 nonce 区域 (39~42)
copy(block[39:43], nonceBytes)
return hex.EncodeToString(block), nil
}
func Produce_block_submit(miner *coin.MinerObj /*header Sha3xBlockHeader,*/, job *msg.MoneroStratumJob, PowHash string, SubIdx int64) {
var nm msg.BlockMoneroMsg
blockBlob, err := contractBlockTemplateBlob(miner, job.Nonce)
if err != nil {
fmt.Println(err)
return
}
nm.Id = job.Id
nm.Header = blockBlob
nm.Nonce = job.Nonce
nm.Pow = PowHash
nm.SubIdx = SubIdx
nm.User = miner.User
nm.Miner = miner.Miner
nm.Height = job.Height
nm.Index = fmt.Sprint(miner.MinerIndex)
body, err := json.Marshal(nm)
if err != nil {
logg.Error("[server]", zap.String("failed to Marshal job", err.Error()))
return
}
// JSON主体
blk := string(body)
// 高度uint32 → 4字节 → hex编码8字符
heightHex := fmt.Sprintf("%08x", job.Height)
// Indexuint32 → 4字节 → hex编码8字符
indexHex := fmt.Sprintf("%08x", miner.MinerIndex)
// 拼接最终消息
msg := blk + heightHex + indexHex
// fmt.Println(msg)
logg.Info("[server]", zap.String("final_msg", msg))
if miner.Server.PubCh == nil {
miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub)
}
if miner.Server.PubCh != nil {
// fmt.Println(msg)
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blkmonero"), []byte(msg)})
if err != nil {
miner.Server.PubCh.Destroy()
miner.Server.PubCh = nil
logg.Info("[server]", zap.String("blk", err.Error()))
} else {
logg.Info("[server]", zap.String("blk", "sent"))
}
}
}
// var start_job_id uint64 = 0
// server-->miner
func parse_miner_notify(miner *coin.MinerObj, msg msg.MoneroStratumJob) int {
if miner.MoneroJob.Height != msg.Height {
miner.Job.IsClean = true
}
miner.MoneroJob = msg
miner.MoneroJob.JobId = msg.JobId
return 1
}
func Init(server *coin.ServerContext) {
ServerMoneroCtx.ServerCtx = server
ServerMoneroCtx.RandomxVM = &RandomXValidator{}
logg = server.Logg
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_MONERO_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {
miner.MoneroJob = miner.Server.MoneroJob
// miner.MoneroJob.Extranonce1 = miner.Job.Extranonce1
server_target := new(big.Int)
t_bytes, err := hex.DecodeString(miner.MoneroJob.Target)
if err != nil {
logg.Error("[server]", zap.String("DecodeString", err.Error()))
return
}
//server_target.SetBytes(common.Reverse(t_bytes))
miner.MoneroJob = ServerMoneroCtx.ServerCtx.MoneroJob
server_target.SetBytes(t_bytes)
miner.ServerTarget = server_target
miner.ServerTargetS = miner.Server.SJob.Target
miner.CurHeight = uint32(miner.MoneroJob.Height)
}
func Handle_subscribe_sha3x(miner *coin.MinerObj, id float64, extranonce1 string) {
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
}
func HandleMinerAuth(miner *coin.MinerObj) {
}
func HandleMinerSubmit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
//nonce_str, _ := stratum.ReverseHexStringByByte(nonce)
accept_ok, submit_ok, handle_ok := handle_submit(miner, id, miner_user, job_id, nonce2, ntime, nonce)
return accept_ok, submit_ok, handle_ok
}
func SetDifficulty(miner *coin.MinerObj) {
stratum.Set_difficulty(miner)
}
func MoneroNotify(miner *coin.MinerObj) {
miner.TxLock.Lock()
if !((miner.Status == coin.MINER_STATUS_AUTHORIZED) || (miner.Status == coin.MINER_STATUS_RUNNING)) {
miner.TxLock.Unlock()
return
}
miner.TxLock.Unlock()
if miner.DifficultyNext > -1 {
ratio := miner.DifficultyNext / miner.Difficulty
if ratio > 1.1 || ratio < 0.9 {
miner.Difficulty = miner.DifficultyNext
miner.DifficultyNext = -1
stratum.Set_difficulty(miner)
//logg.Info("[gbt]", zap.Float64("update Diff", miner.Difficulty))
} else {
miner.DifficultyNext = -1
}
}
miner.TxLock.Lock()
//log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId)
var msg Monero_msg
msg.Params.Id = miner.Session
msg.Params.SeedHash = miner.MoneroJob.SeedHash
msg.Params.JobId = miner.MoneroJob.JobId
msg.Params.Blob = miner.MoneroJob.BlockhashingBlob
msg.Params.Height = uint32(miner.MoneroJob.Height)
miner.MoneroJob.Difficulty = uint64(miner.Difficulty)
msg.Params.NextSeedHash = ""
msg.Params.Algo = "rx/0"
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
//msg.Params.Target = target_s[48:]
target_new, _ := utility.MoneroDiffToTarget(miner.Difficulty)
target_str := fmt.Sprintf("%064x", target_new.Bytes())
target_strr, strerr := stratum.ReverseHexStringByByte(target_str)
if strerr != nil {
println("ReverseHexStringByByte", strerr.Error())
}
//println("target=", target_str, "r=", target_strr)
msg.Params.Target = target_strr[48:]
miner.CurHeight = uint32(miner.MoneroJob.Height)
// miner.MoneroJob.JobDifficulty = miner.Difficulty
miner.Jobs.LoadOrStore(miner.MoneroJob.JobId, miner.MoneroJob)
stratum.AddAndUpdateJob(miner)
stratum.UpdateJobs(miner)
miner.JobId++
var body []byte
var err error
msg.Jsonrpc = "2.0"
msg.Method = "job"
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//delete(miner.Server.Miners, miner.MinerId)
//miner.Server.Miners.Delete(miner.MinerId)
}
miner.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func Notify(miner *coin.MinerObj) {
MoneroNotify(miner)
}
func formatUint64ToHexWithPadding(val uint64) string {
hexStr := fmt.Sprintf("%016x", val)
if len(hexStr) < 64 {
paddingLen := 64 - len(hexStr)
hexStr += string(make([]byte, paddingLen))
for i := len(hexStr) - paddingLen; i < 64; i++ {
hexStr = hexStr[:i] + "0" + hexStr[i+1:]
}
}
return hexStr
}
func formatWideTargetTo32BytesTarget(wide_target string) string {
if len(wide_target) > 64 {
panic("任务中的wide_target错误")
}
// 去掉前缀 0x 或 0X
wide_target = strings.TrimPrefix(wide_target, "0x")
wide_target = strings.TrimPrefix(wide_target, "0X")
wide_target = fmt.Sprintf("%0*s%s", 64-len(wide_target), "", wide_target)
return wide_target
}
var last_seed string = ""
func randomxJobId() string {
// 生成4个字节
bytes := make([]byte, 4)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
// 转成 hex 字符串
hexStr := hex.EncodeToString(bytes)
return hexStr
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {
var result msg.MoneroStratumJob
server.Logg.Warn("[server]", zap.String("receive", "job"))
if err := json.Unmarshal(Msg, &result); err != nil {
server.Logg.Error("[server]", zap.String("Unmarshal", err.Error()))
return
}
result.Target = calc_target(result.Difficulty)
// 上个模板 seed_hash 和本次 seed_hash 不一致时,重置 randomx 虚拟机
if result.SeedHash != last_seed {
fmt.Println("开始创建新的 randomx vm, 本次 seed_hash", result.SeedHash)
seedBytes, err := hex.DecodeString(result.SeedHash)
if err != nil {
panic(err)
}
// 如果已有旧 VM先释放
if ServerMoneroCtx.RandomxVM != nil {
ServerMoneroCtx.RandomxVM.Destroy()
}
// 创建新 VM
vm, err := NewRandomXValidator(seedBytes)
if err != nil {
panic(err)
}
ServerMoneroCtx.RandomxVM = vm
last_seed = result.SeedHash
}
server.MoneroJob = msg.MoneroStratumJob(result)
logg.Debug("[gbt]", zap.String("Target", server.MoneroJob.Target))
logg.Debug("[gbt]", zap.Uint64("Id", server.MoneroJob.Id), zap.Float64("network diff", float64(server.MoneroJob.Difficulty)))
server.NetHight = uint64(server.MoneroJob.Height) // 当前server中的全网高度
server.NetTarget = result.Target // 当前server中的全网target
server.Miners.Range(func(k, v interface{}) bool {
if v != nil {
m, ok := v.(*(coin.MinerObj))
if ok {
if m != nil {
server.Logg.Info("[server]", zap.String("lock", "start"))
m.TxLock.Lock()
status := m.Status
cmd := parse_miner_notify(m, server.MoneroJob)
m.TxLock.Unlock()
server.Logg.Info("[server]", zap.String("lock", "end"))
var need_notify bool = true
if time.Now().Sub(m.ConnSetupTime) >= time.Duration(coin.CONN_EXPIRED_TIME)*time.Second {
if (status != coin.MINER_STATUS_RUNNING) && (status != coin.MINER_STATUS_AUTHORIZED) {
//m.Conn.Close()
need_notify = false
}
}
if need_notify {
switch cmd {
case 0: //extranonce 1 and extranonce2 size
//TODO
case 1: //notify
MoneroNotify(m)
}
}
}
}
}
return true
})
}
func IsMhsLow(miner *coin.MinerObj) bool {
if miner.Mhs5M < 1 {
return true
}
return false
}
func GetBlockInterval() int {
return 3600
}

View File

@ -0,0 +1,61 @@
// hash_nexa.go
package nexa
/*
#cgo CFLAGS : -I../include
#cgo LDFLAGS: -L../lib -lnexa
#include <stdio.h>
#include <stdlib.h>
#include "nexaapi.h"
*/
import "C"
import (
//"encoding/hex"
//"log"
"unsafe"
)
func BuildPowHash(h NexaBlockHeader) []byte {
outputs := make([]byte, 32)
inb := NexaBlockHeaderToBytes(h)
//log.Println("[nexa]in", hex.EncodeToString(inb))
in := (*C.uchar)(C.CBytes(inb))
output := (*C.uchar)(C.malloc(32))
C.nexa_hash(output, in)
p := uintptr(unsafe.Pointer(output))
for i := 0; i < 32; i++ {
j := *(*byte)(unsafe.Pointer(p))
outputs[i] = j
p += unsafe.Sizeof(j)
}
C.free(unsafe.Pointer(output))
C.free(unsafe.Pointer(in))
outputs32 := make([]byte, 32)
for i := 0; i < 32; i++ {
outputs32[i] = outputs[i]
}
return outputs32
}
func BuildPowHash12(h NexaBlockHeader12) []byte {
outputs := make([]byte, 32)
inb := NexaBlockHeaderToBytes12(h)
//log.Println("[nexa]in", hex.EncodeToString(inb))
in := (*C.uchar)(C.CBytes(inb))
output := (*C.uchar)(C.malloc(32))
C.nexa_hash12(output, in)
p := uintptr(unsafe.Pointer(output))
for i := 0; i < 32; i++ {
j := *(*byte)(unsafe.Pointer(p))
outputs[i] = j
p += unsafe.Sizeof(j)
}
C.free(unsafe.Pointer(output))
C.free(unsafe.Pointer(in))
outputs32 := make([]byte, 32)
for i := 0; i < 32; i++ {
outputs32[i] = outputs[i]
}
return outputs32
}

View File

@ -0,0 +1,943 @@
// nexa.go
package nexa
import (
//"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
//"log"
//"math"
"math/big"
"strings"
"fmt"
"pool/internal/msg"
"pool/internal/server/coin"
"pool/internal/server/dbif"
"pool/internal/stratum"
"pool/internal/utility"
"time"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
const SERVER_NEXA_VERSION string = "nexa v2.0x"
type NexaBlockHeader struct {
Header [32]byte
Nonce [16]byte
}
func NexaBlockHeaderToBytes(h NexaBlockHeader) []byte {
out := make([]byte, 49)
for i := 0; i < 32; i++ {
out[i] = h.Header[i]
}
out[32] = 0x10
for i := 0; i < 16; i++ {
out[33+i] = h.Nonce[i]
}
return out
}
type NexaBlockHeader12 struct {
Header [32]byte
Nonce [12]byte
}
func NexaBlockHeaderToBytes12(h NexaBlockHeader12) []byte {
out := make([]byte, 45)
for i := 0; i < 32; i++ {
out[i] = h.Header[i]
}
out[32] = 0x0c
for i := 0; i < 12; i++ {
out[33+i] = h.Nonce[i]
}
return out
}
type ServerNexaContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
NexaJob msg.NexaStratumJob
}
var logg *zap.Logger
var ServerNexaCtx ServerNexaContext
type Notify_msg_nexa struct {
ID interface{} `json:"id"`
Method string `json:"method"`
Params [5]interface{} `json:"params"`
}
type Notify_msg_nexa_gpu struct {
Jsonrpc string `json:"jsonrpc"`
ID interface{} `json:"id"`
Method string `json:"method"`
Params [4]interface{} `json:"params"`
}
func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
var submit_item coin.BlockMsg
/*var user_blk_item coin.UserBlockMsg*/
var pool_blk_item coin.PoolBlkMsg
var blk_detail_height int64
var blk_detail_hash string
var blk_detail_success bool
var blk_detail_miner_diff float64
var blk_detail_pool_diff float64
if miner.Authorized != true {
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNAUTH_WORKER)
stratum.Send_reconnect_msg(miner)
return false, false, false
}
var new_found bool = false
var ack stratum.Submit_ack
ack.ID = id
ack.Result = true
//logg.Warn("[server]", zap.String("user", miner.User), zap.String("miner", miner.Miner))
//logg.Debug("[server]", zap.Float64("id", id), zap.String("job_id", job_id))
//logg.Debug("[server]", zap.String("nonce2", nonce2), zap.String("ntime", ntime), zap.String("nonce", nonce))
//stratum.UpdateJobs(miner)
v, ok := miner.Jobs.Load(job_id)
if ok {
job := v.(msg.NexaStratumJob)
if job.Height < miner.CurHeight-1 {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_STALED_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
//logg.Debug("[server]", zap.Uint64("ntime", nt), zap.Uint64("mintime", uint64(job.Mintime)), zap.Uint64("jobtime", jt_reverse))
/*if nt < uint64(job.Mintime) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_OLD)
} else if nt > jt_reverse+uint64(600) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_NEW)
} else */{
if (miner.LastNonce != nonce) || (miner.LastHeader != job.Header) {
miner.LastHeader = job.Header
miner.LastNonce = nonce
job.Nonce = nonce
job.Extranonce2 = nonce2
//logg.Debug("[server]", zap.Uint32("height", job.Height), zap.String("target", job.Target))
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
}
phb, _ := hex.DecodeString(job.Header)
nb, _ := hex.DecodeString(nonce)
var calc_hash []byte
if miner.Protocol == "yxminer" {
var header NexaBlockHeader
for i := 0; i < 32; i++ {
header.Header[i] = phb[i]
}
for i := 0; i < 16; i++ {
header.Nonce[i] = nb[i]
}
submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
var header NexaBlockHeader12
for i := 0; i < 32; i++ {
header.Header[i] = phb[i]
}
for i := 0; i < 12; i++ {
header.Nonce[i] = nb[i]
}
submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes12(header))
calc_hash = BuildPowHash12(header)
} else {
var header NexaBlockHeader
for i := 0; i < 32; i++ {
header.Header[i] = phb[i]
}
for i := 0; i < 16; i++ {
header.Nonce[i] = nb[i]
}
submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
}
//logg.Debug("[server]", zap.String("hash in", submit_item.Header))
//calc_hash, header := util.BuildBlockHash(&(job), true, Build_PowHash)
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
if miner.ZlogInit {
miner.Zlog.Info().Msg("hash in " + submit_item.Header + " calc_hash " + hex.EncodeToString(calc_hash) + " " + miner.User + "." + miner.Miner)
}
submit_target := new(big.Int)
//submit_target.SetBytes(common.Reverse(calc_hash))
//hashs, _ := utility.ReverseS(hex.EncodeToString(calc_hash))
//hashb, _ := hex.DecodeString(hashs)
//submit_target.SetBytes(hashb)
submit_target.SetBytes(calc_hash)
/*logg.Debug("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
if submit_target.Cmp(miner.Target) > 0 {*/
//calc_diff := Target2Diff(common.Reverse(calc_hash))
calc_diff := utility.Target2Diff(calc_hash)
//log.Printf("diff,calc_diff:%f difficulty:%f ", calc_diff, miner.Difficulty)
//logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " target diff " + fmt.Sprintf("%f", (miner.Difficulty)) + " submit diff " + fmt.Sprintf("%f", (calc_diff)))
}
//logg.Debug("[server]", zap.String("target", miner.Target.String()), zap.Any("bytes", miner.Target.Bytes()))
//logg.Info("[server]", zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
//if calc_diff < miner.Difficulty {
if calc_diff < job.JobDifficulty {
//gpu protocol handler
/*for i := 0; i < 8; i++ {
temp_nonce := header.Nonce[8+i]
header.Nonce[8+i] = header.Nonce[i]
header.Nonce[i] = temp_nonce
}
submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(NexaBlockHeaderToBytes(header))))*/
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
//submit_target = new(big.Int)
/*submit_target.SetBytes(calc_hash)
calc_diff = utility.Target2Diff(calc_hash)
logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if calc_diff < miner.Difficulty {
*/
ack.Result = false
miner.ErrLowDiffs = miner.ErrLowDiffs + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE)
return false, false, false
//}
}
//logg.Warn("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())))
//submit_target.Text(16)
/*if submit_target.Cmp(miner.ServerTarget) <= 0 {*/
//log.Println("[server]server_target", miner.ServerTargetS)
//stb, _ := hex.DecodeString(miner.ServerTargetS)
stb, _ := hex.DecodeString(job.Target)
//logg.Info("[server]", zap.String("target", job.Target))
//server_diff := Target2Diff(common.Reverse(stb))
server_diff := utility.Target2Diff(utility.Reverse(stb))
//log.Printf("[server]server_diff %f", server_diff)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("ServerTargetS", miner.ServerTargetS))
network_target := new(big.Int)
network_target.SetBytes(stb)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("submit_target", hex.EncodeToString(submit_target.Bytes())), zap.String("network_target", hex.EncodeToString(network_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())), zap.Int("cmp", network_target.Cmp(submit_target)))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " calc_diff " + fmt.Sprintf("%f", (calc_diff)) + " miner.Difficulty " + fmt.Sprintf("%f", (miner.Difficulty)) + " server_diff " + fmt.Sprintf("%f", (server_diff)))
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " submit_target " + hex.EncodeToString(submit_target.Bytes()) + " network_target " + hex.EncodeToString(network_target.Bytes()) + " target " + hex.EncodeToString(miner.ServerTarget.Bytes()) + " cmp " + fmt.Sprintf("%d", (network_target.Cmp(submit_target))))
}
submit_item.Hash = hex.EncodeToString(calc_hash)
submit_item.Target = hex.EncodeToString(miner.Target.Bytes())
submit_item.Submit_target = hex.EncodeToString(calc_hash)
submit_item.Height = int64(job.Height)
submit_item.Pow = hex.EncodeToString(calc_hash)
submit_item.Net_target = hex.EncodeToString(network_target.Bytes())
/*user_blk_item.Height = int64(job.Height)
user_blk_item.Hash = hex.EncodeToString(calc_hash)
user_blk_item.Pow = hex.EncodeToString(calc_hash)
user_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())*/
pool_blk_item.Height = int64(job.Height)
pool_blk_item.Hash = hex.EncodeToString(calc_hash)
pool_blk_item.Pow = hex.EncodeToString(calc_hash)
pool_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())
blk_detail_height = int64(job.Height)
blk_detail_hash = hex.EncodeToString(calc_hash)
blk_detail_success = false
//blk_detail_miner_diff = miner.Difficulty
blk_detail_miner_diff = job.JobDifficulty
blk_detail_pool_diff = miner.Server.RefDifficulty
if ack.Result == true {
/*if miner.CurHeight != 0 && miner.CurHeight == job.Height {
return
}*/
//if true {
if (calc_diff >= server_diff) || (network_target.Cmp(submit_target) >= 0) {
miner.Server.SubIdx++
Produce_block_submit(miner /*header,*/, &job, submit_item.Hash, miner.Server.SubIdx)
miner.SubmitIndex++
miner.Submits = miner.Submits + 1
//miner.CurHeight = job.Height
new_found = true
}
}
} else {
miner.LastHeader = job.Header
miner.LastNonce = nonce
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_DUP_SHARE)
miner.ErrDuplicates = miner.ErrDuplicates + 1
return false, false, false
}
}
} else {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_FOUND_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
miner.LastJobId = job_id
ack.Error = nil
body, err := json.Marshal(ack)
if err != nil {
//logg.Error("[server]", zap.String("Marshal", err.Error()))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit Marshal " + err.Error())
}
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNKNOWN)
return false, false, false
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//miner.Server.Miners.Delete(miner.MinerId)
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
//logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Lock()
miner.Status = coin.MINER_STATUS_RUNNING
miner.TxLock.Unlock()
if ack.Result {
miner.Accepts += miner.Difficulty
miner.M5Accepts += miner.Difficulty
miner.VarDiffOpt.SubmitShares += miner.Difficulty
} else {
miner.Rejects += miner.Difficulty
}
now := time.Now()
if miner.Server.Config.Diff.Filter == "kalman" {
if ack.Result {
share_interval := now.Sub(miner.LastSubmitime).Seconds()
mhs := miner.Difficulty * share_interval
diff_next, kalman_p := miner.DiffHandler.Handler(miner.Difficulty, share_interval)
mhs_est := diff_next * miner.Server.Config.Diff.DiffAdjustInterval
ratio := diff_next / miner.Difficulty
if ratio > 0 {
if now.Sub(miner.StartSubmitTime).Seconds() > 180 {
if ratio >= 2 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else if ratio <= 0.5 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else {
}
} else {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
/*if ratio >= 1.1 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else if ratio <= 0.8 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else {
}*/
}
}
if miner.DifficultyNext > 0.0 {
if miner.DifficultyNext < miner.VarDiffOpt.MinDiff {
miner.DifficultyNext = miner.VarDiffOpt.MinDiff
} else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff {
miner.DifficultyNext = miner.VarDiffOpt.MaxDiff
}
}
//miner.VarDiffOpt.LastCalcTime = now
if miner.Server.Config.Diff.Dbg {
coin.New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, diff_next, kalman_p, share_interval, mhs, mhs_est)
}
//log.Println("diff adjust", ratio, diff_next, miner.Difficulty, miner.DifficultyNext)
}
} else {
// submit time < DiffAdjustInterval,then up adjust diff
if now.Sub(miner.LastSubmitime).Seconds() < miner.Server.Config.Diff.DiffAdjustInterval {
if ack.Result {
if miner.VarDiffOpt.Uptimes++; miner.VarDiffOpt.Uptimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.UP_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Uptimes = 0
}
// submit time > 2 * DiffAdjustInterval,then down adjust diff
if now.Sub(miner.LastSubmitime).Seconds() > miner.Server.Config.Diff.DiffAdjustInterval*2 {
if ack.Result {
if miner.VarDiffOpt.Downtimes++; miner.VarDiffOpt.Downtimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.DOWN_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Downtimes = 0
}
}
if ack.Result {
miner.LastSubmitime = now
miner.VarDiffOpt.LastSubmitTime = now
}
var duration float64 = float64(now.Sub(miner.StartSubmitTime)) / 1000000000
if duration < 1 {
duration = 1
}
diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF)
miner.AverageHashrate = miner.Accepts * float64(diffOneShareHashesAvg) / duration / 1000000
var m5_duration float64 = float64(now.Sub(miner.M5SubmitTime)) / 1000000000
if m5_duration >= float64(time.Minute*5)/1000000000 {
miner.M5SubmitTime = now
miner.M5Hashrate = miner.M5Accepts * float64(diffOneShareHashesAvg) / m5_duration / 1000000
//logg.Info("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
miner.M5Accepts = 0
}
//logg.Warn("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("Rejects", miner.Rejects))
//logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares), zap.Float64("SubmitShares", miner.VarDiffOpt.SubmitShares))
//logg.Warn("[server]", zap.Float64("reject rate", miner.Rejects/(miner.Accepts+miner.Rejects)), zap.Float64("Hashrate(MH/S)", miner.AverageHashrate))
//logg.Warn("[server]", zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit M5Accepts " + fmt.Sprintf("%f", (miner.M5Accepts)) + " M5Hashrate(MH/S) " + fmt.Sprintf("%f", (miner.M5Hashrate)))
}
//logg.Info("[server]", zap.Float64("LastCalcTime", float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000))
//calc acutal submit shares period of time, then compare with target shares and adjust diff
if miner.Server.Config.Diff.Filter == "kalman" {
} else {
if float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000 >= miner.VarDiffOpt.AdjustTime {
coin.VarAdjustDifficulty(miner, coin.UPDATE_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
if new_found {
//util.StaleAllJobs(miner)
/*user_blk_item.User = miner.User
user_blk_item.Miner = miner.Miner
user_blk_item.Index = fmt.Sprint(miner.MinerIndex)
user_blk_item.Submit = "y"
user_blk_item.Success = false
user_blk_item.Accepts = miner.Accepts
user_blk_item.Rejects = miner.Rejects
user_blk_item.Reward = 0
user_blk_item.Fee = 0
user_blk_item.Nonce = nonce
user_blk_item.SubIdx = miner.Server.SubIdx
dbif.NotifyUsersBlkStatsDb2(miner, &user_blk_item)*/
pool_blk_item.Submit = "y"
pool_blk_item.Success = false
pool_blk_item.Accepts = miner.Accepts
pool_blk_item.Rejects = miner.Rejects
pool_blk_item.Reward = 0
pool_blk_item.Fee = 0
pool_blk_item.Nonce = nonce
pool_blk_item.SubIdx = miner.Server.SubIdx
dbif.NotifyPoolBlkStatsDb2(miner.Server, &pool_blk_item)
}
if ack.Result {
submit_item.Success = false
if new_found {
submit_item.Submit = "y"
submit_item.SubIdx = miner.Server.SubIdx
} else {
submit_item.Submit = "n"
submit_item.SubIdx = -1
}
submit_item.Accepts = miner.Accepts
submit_item.Total_accepts = miner.Accepts
submit_item.Rejects = miner.Rejects
submit_item.Total_rejects = miner.Rejects
submit_item.Reward = 0
submit_item.Fee = 0
submit_item.Nonce = nonce
//dbif.NotifyMinerDb2(miner, &submit_item)
dbif.NotifyBlkDetailDb(miner, blk_detail_height, blk_detail_hash, blk_detail_success, blk_detail_miner_diff, blk_detail_pool_diff, nonce, submit_item.SubIdx)
return true, new_found, true
}
return false, false, true
}
func Produce_block_submit(miner *coin.MinerObj /*header NexaBlockHeader,*/, job *msg.NexaStratumJob, PowHash string, SubIdx int64) {
var nm msg.BlockNexaMsg
nm.Id = job.Id
nm.Header = job.Header
nm.Nonce = job.Nonce
nm.Pow = PowHash
nm.SubIdx = SubIdx
nm.User = miner.User
nm.Miner = miner.Miner
nm.Index = fmt.Sprint(miner.MinerIndex)
body, err := json.Marshal(nm)
if err != nil {
logg.Error("[server]", zap.String("failed to Marshal job", err.Error()))
return
}
blk := string(body)
//Add Height
heightb := utility.Uint32ToByte(job.Height)
heights := hex.EncodeToString(heightb)
blk += heights
var Height uint32 = utility.ByteToUint32(heightb)
logg.Warn("[server]", zap.Uint32("Height", Height))
//Add SubmitIndex
indexb := utility.Uint32ToByte(miner.SubmitIndex)
indexs := hex.EncodeToString(indexb)
blk += indexs
var SubmitIndex uint32 = utility.ByteToUint32(indexb)
logg.Info("[server]", zap.Uint32("SubmitIndex", SubmitIndex))
logg.Info("[server]", zap.String("blk", blk))
if miner.Server.PubCh == nil {
miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub)
}
if miner.Server.PubCh != nil {
//miner.Server.PubCh.SendChan <- [][]byte{[]byte("blknexa"), []byte(blk)}
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blknexa"), []byte(blk)})
if err != nil {
miner.Server.PubCh.Destroy()
miner.Server.PubCh = nil
logg.Info("[server]", zap.String("blk", err.Error()))
} else {
logg.Info("[server]", zap.String("blk", "sent"))
}
}
}
// server-->miner
func nexa_parse_miner_notify(miner *coin.MinerObj, msg msg.NexaStratumJob) int {
if miner.NexaJob.Height != msg.Height {
miner.Job.IsClean = true
}
miner.NexaJob = msg
miner.NexaJob.Extranonce1 = miner.Job.Extranonce1
miner.Job.Extranonce2_size = msg.Extranonce2_size
//miner.Server.Logg.Info("[server]", zap.Int32("miner.Version", miner.Version), zap.Int32("msg.Version", msg.Version))
return 1
}
func Init(server *coin.ServerContext) {
ServerNexaCtx.ServerCtx = server
logg = server.Logg
logg.Info("[server]", zap.String("server_nexa_version", SERVER_NEXA_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {
miner.NexaJob = miner.Server.NexaJob
miner.NexaJob.Extranonce1 = miner.Job.Extranonce1
server_target := new(big.Int)
t_bytes, err := hex.DecodeString(miner.NexaJob.Target)
if err != nil {
logg.Error("[server]", zap.String("DecodeString", err.Error()))
return
}
//server_target.SetBytes(common.Reverse(t_bytes))
server_target.SetBytes(t_bytes)
miner.ServerTarget = server_target
miner.ServerTargetS = miner.Server.SJob.Target
}
func Handle_subscribe_nexa(miner *coin.MinerObj, id float64, extranonce1 string) {
miner.TxLock.Lock()
var result [3]interface{}
//result[0] = results
result[0] = nil
if miner.Protocol == "yxminer" {
result[1] = extranonce1
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
var result2 [2]interface{}
var result3 [2]interface{}
var result4 [2]interface{}
result3[0] = "mining.set_difficulty"
if miner.Protocol == "WildRig" {
result3[1] = extranonce1[:8]
} else {
result3[1] = miner.Difficulty
}
result4[0] = "mining.notify"
//result4[1] = extranonce1
result4[1] = extranonce1[:8]
result2[0] = result3
result2[1] = result4
result[0] = result2
result[1] = extranonce1[:8]
//result[0] = fmt.Sprintf("[[%s,%.2f],[%s,%s]]", "mining.set_difficulty", miner.Difficulty, "mining.notify", extranonce1)
} else {
result[1] = extranonce1
}
//result[1] = miner.Job.Extranonce1
//miner.Server.Logg.Debug("[server]", zap.Uint64("extra2", miner.Job.Extranonce2_size))
if miner.Job.Extranonce2_size == 0 {
result[2] = 4
} else {
if miner.Protocol == "yxminer" {
result[2] = miner.Job.Extranonce2_size
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
result[2] = 4
} else {
result[2] = miner.Job.Extranonce2_size
}
}
if extranonce1 == "" {
miner.TxLock.Unlock()
stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_SUBSCRIBED)
return
}
var body []byte
var err error
if miner.Protocol == "yxminer" {
var ack stratum.Subscribe_reply
ack.ID = id
ack.Result = result
ack.Error = nil
body, err = json.Marshal(ack)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
var ack stratum.SubscribeGpu_reply
ack.Jsonrpc = "2.0"
ack.ID = id
ack.Result = result
ack.Error = nil
body, err = json.Marshal(ack)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
} else {
var ack stratum.Subscribe_reply
ack.ID = id
ack.Result = result
ack.Error = nil
body, err = json.Marshal(ack)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
}
var body_string = string(body) + "\n"
//miner.Server.Logg.Debug("[server]", zap.String("tx", body_string))
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//delete(miner.Server.Miners, miner.MinerId)
//miner.Server.Miners.Delete(miner.MinerId)
}
miner.Status = coin.MINER_STATUS_SUBSCRIBED
miner.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
if strings.Contains(msg, "YxMiner") {
miner.Protocol = "yxminer"
} else if strings.Contains(msg, "BzMiner") {
miner.Protocol = "bzminer"
} else if strings.Contains(msg, "lolMiner") {
miner.Protocol = "lolminer"
} else if strings.Contains(msg, "Rigel") {
miner.Protocol = "Rigel"
} else if strings.Contains(msg, "WildRig") {
miner.Protocol = "WildRig"
} else {
miner.Protocol = "standard"
}
Handle_subscribe_nexa(miner, id, extranonce1)
}
func HandleMinerAuth(miner *coin.MinerObj) {
}
func HandleMinerSubmit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
if miner.Protocol == "yxminer" {
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
nonce = nonce2 + nonce
} else {
}
accept_ok, submit_ok, handle_ok := handle_submit(miner, id, miner_user, job_id, nonce2, ntime, nonce)
return accept_ok, submit_ok, handle_ok
}
func SetDifficulty(miner *coin.MinerObj) {
if miner.Protocol == "yxminer" {
stratum.Set_difficulty(miner)
} else {
stratum.Set_difficulty_nexa(miner)
}
}
func NexaNotify(miner *coin.MinerObj) {
miner.TxLock.Lock()
if !((miner.Status == coin.MINER_STATUS_AUTHORIZED) || (miner.Status == coin.MINER_STATUS_RUNNING)) {
miner.TxLock.Unlock()
return
}
miner.TxLock.Unlock()
if miner.DifficultyNext > -1 {
ratio := miner.DifficultyNext / miner.Difficulty
if ratio > 1.1 || ratio < 0.9 {
miner.Difficulty = miner.DifficultyNext
miner.DifficultyNext = -1
if miner.Protocol == "yxminer" {
stratum.Set_difficulty(miner)
} else {
stratum.Set_difficulty_nexa(miner)
}
//logg.Info("[gbt]", zap.Float64("update Diff", miner.Difficulty))
} else {
miner.DifficultyNext = -1
}
}
miner.TxLock.Lock()
//log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId)
var params [5]interface{}
idb := make([]byte, 4)
binary.BigEndian.PutUint32(idb, miner.JobId)
miner.Job.Job_id = hex.EncodeToString(idb)
params[0] = miner.Job.Job_id
params[1] = miner.NexaJob.Header
//params[3] = miner.NexaJob.Height
if miner.Protocol == "yxminer" {
params[2] = miner.NexaJob.NBits
params[3] = miner.NexaJob.CurTime
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
params[2] = miner.NexaJob.Height
params[3] = miner.NexaJob.NBits
} else {
params[2] = miner.NexaJob.NBits
params[3] = miner.NexaJob.CurTime
}
miner.CurHeight = miner.NexaJob.Height
if miner.Reconnect {
params[4] = true
miner.Reconnect = false
} else {
params[4] = miner.Job.IsClean
}
params[4] = true
miner.NexaJob.JobDifficulty = miner.Difficulty
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.NexaJob)
/*var entry coin.JobListEntry
entry.Job_id = miner.Job.Job_id
entry.Ts = time.Now()
miner.LockForJobs.Lock()
miner.JobList.PushFront(entry)
var removes string = ""
if miner.JobList.Len() > int(coin.LOCAL_JOBS_TOTAL_SIZE) {
e := miner.JobList.Back()
entry := e.Value.(coin.JobListEntry)
removes = entry.Job_id
miner.JobList.Remove(e)
}
miner.LockForJobs.Unlock()
if len(removes) > 0 {
miner.Jobs.Delete(removes)
}*/
stratum.AddAndUpdateJob(miner)
stratum.UpdateJobs(miner)
//miner.LastJobId = miner.Job.Job_id
miner.JobId++
var body []byte
var err error
if miner.Protocol == "yxminer" {
var msg Notify_msg_nexa
msg.ID = nil
msg.Method = "mining.notify"
msg.Params = params
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
} else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" {
var msg Notify_msg_nexa_gpu
msg.ID = nil
msg.Method = "mining.notify"
var params4 [4]interface{}
params4[0] = params[0]
params4[1] = params[1]
params4[2] = params[2]
params4[3] = params[3]
msg.Params = params4
msg.Jsonrpc = "2.0"
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
} else {
var msg Notify_msg_nexa
msg.ID = nil
msg.Method = "mining.notify"
msg.Params = params
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//delete(miner.Server.Miners, miner.MinerId)
//miner.Server.Miners.Delete(miner.MinerId)
}
//miner.Server.Logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func Notify(miner *coin.MinerObj) {
NexaNotify(miner)
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {
var result msg.NexaStratumJob
server.Logg.Warn("[server]", zap.String("receive", "job"))
if err := json.Unmarshal(Msg, &result); err != nil {
server.Logg.Error("[server]", zap.String("Unmarshal", err.Error()))
return
}
server.NexaJob = msg.NexaStratumJob(result)
logg.Debug("[gbt]", zap.String("Target", server.NexaJob.Target))
server.NexaJob.Extranonce2_size = 8
server.SJob.Extranonce2_size = 8
logg.Debug("[gbt]", zap.Uint32("Height", server.NexaJob.Height), zap.String("Target", server.NexaJob.Target), zap.String("Header", server.NexaJob.Header) /*, zap.Uint64("Timastamp", server.NexaJob.CurTime)*/)
targetb, _ := hex.DecodeString(server.NexaJob.Target)
logg.Debug("[gbt]", zap.Uint64("Id", server.NexaJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb))))
server.NetHight = uint64(server.NexaJob.Height)
server.NetTarget = server.NexaJob.Target
server.Miners.Range(func(k, v interface{}) bool {
if v != nil {
m, ok := v.(*(coin.MinerObj))
if ok {
if m != nil {
server.Logg.Info("[server]", zap.String("lock", "start"))
m.TxLock.Lock()
status := m.Status
cmd := nexa_parse_miner_notify(m, server.NexaJob)
m.TxLock.Unlock()
server.Logg.Info("[server]", zap.String("lock", "end"))
var need_notify bool = true
if time.Now().Sub(m.ConnSetupTime) >= time.Duration(coin.CONN_EXPIRED_TIME)*time.Second {
if (status != coin.MINER_STATUS_RUNNING) && (status != coin.MINER_STATUS_AUTHORIZED) {
//m.Conn.Close()
need_notify = false
}
}
if need_notify {
switch cmd {
case 0: //extranonce 1 and extranonce2 size
//TODO
case 1: //notify
NexaNotify(m)
}
}
}
}
}
return true
})
}
func IsMhsLow(miner *coin.MinerObj) bool {
if miner.Mhs5M < 1 {
return true
}
return false
}
func GetBlockInterval() int {
return 180
}

View File

@ -0,0 +1,117 @@
package randomxT
/*
#cgo CFLAGS: -I/home/lizixuan/桌面/tari-server/internal/server/include
#cgo LDFLAGS: -L/home/lizixuan/桌面/tari-server/internal/server/lib/randomx -lrandomx
#include <randomx.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
*/
import "C"
import (
"fmt"
"unsafe"
"golang.org/x/sys/cpu"
)
type RandomXValidator struct {
cache *C.randomx_cache
vm *C.randomx_vm
flags C.randomx_flags
seed []byte
}
// NewRandomXValidator 初始化 cache + vm
func NewRandomXValidator(seed []byte) (*RandomXValidator, error) {
if len(seed) != 32 {
return nil, fmt.Errorf("seed must be 32 bytes")
}
var flags C.randomx_flags = 0
// 检测 AES-NI 支持
if cpu.X86.HasAES {
flags |= C.RANDOMX_FLAG_HARD_AES
} else {
fmt.Println("[RandomX] CPU 不支持 AES-NI将使用纯软件模式")
}
// ⚠️ 默认启用 JIT如果系统禁止会报错
flags |= C.RANDOMX_FLAG_JIT
// 分配 cache
cache := C.randomx_alloc_cache(flags)
if cache == nil {
return nil, fmt.Errorf("failed to alloc cache")
}
C.randomx_init_cache(cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
// 创建 vm
vm := C.randomx_create_vm(flags, cache, nil)
if vm == nil {
C.randomx_release_cache(cache)
return nil, fmt.Errorf("failed to create randomx vm")
}
return &RandomXValidator{
cache: cache,
vm: vm,
flags: flags,
seed: append([]byte{}, seed...),
}, nil
}
// SetSeed 更新 seed替换 cache并重置 vm
func (v *RandomXValidator) SetSeed(seed []byte) error {
if len(seed) != 32 {
return fmt.Errorf("seed must be 32 bytes")
}
// 如果相同 seed不用更新
if string(seed) == string(v.seed) {
return nil
}
C.randomx_init_cache(v.cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
C.randomx_vm_set_cache(v.vm, v.cache)
v.seed = append(v.seed[:0], seed...)
return nil
}
// Destroy 释放 vm + cache
func (v *RandomXValidator) Destroy() {
if v.vm != nil {
C.randomx_destroy_vm(v.vm)
v.vm = nil
}
if v.cache != nil {
C.randomx_release_cache(v.cache)
v.cache = nil
}
}
// BuildPowHash 计算区块哈希
func (v *RandomXValidator) BuildPowHash(blockBlob, nonce []byte) ([]byte, []byte, error) {
if v.vm == nil {
return nil, nil, fmt.Errorf("vm is nil")
}
if len(nonce) != 4 {
return nil, nil, fmt.Errorf("nonce must be 4 bytes")
}
blockHeader := make([]byte, len(blockBlob))
copy(blockHeader, blockBlob)
copy(blockHeader[39:43], nonce)
var hash [32]byte
C.randomx_calculate_hash(v.vm,
unsafe.Pointer(&blockHeader[0]),
C.size_t(len(blockHeader)),
unsafe.Pointer(&hash[0]),
)
return hash[:], blockHeader, nil
}

View File

@ -0,0 +1,761 @@
// sha3x.go
package randomxT
import (
"strconv"
//"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
//"log"
//"math"
"math/big"
//"strings"
"fmt"
"pool/internal/msg"
"pool/internal/server/coin"
"pool/internal/server/dbif"
"pool/internal/stratum"
"pool/internal/utility"
"time"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
const SERVER_SHA3X_VERSION string = "sha3x v0.1a"
type Sha3xBlockHeader struct {
Nonce [8]byte
Header [32]byte
Algo byte
}
func Sha3xBlockHeaderToBytes(h Sha3xBlockHeader) []byte {
out := make([]byte, 8+32+1)
for i := 0; i < 8; i++ {
out[i] = h.Nonce[i]
}
for i := 0; i < 32; i++ {
out[8+i] = h.Header[i]
}
out[8+32] = h.Algo
return out
}
type ServerSha3xContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
Sha3xJob msg.Sha3xStratumJob
}
var logg *zap.Logger
var ServerSha3xCtx ServerSha3xContext
type Sha3xNotify_params_msg struct {
Algo string `json:"algo"`
Blob string `json:"blob"`
Height uint32 `json:"height"`
Job_id string `json:"job_id"`
Target string `json:"target"`
}
type Sha3xNotify_msg struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params Sha3xNotify_params_msg `json:"params"`
}
func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
var submit_item coin.BlockMsg
/*var user_blk_item coin.UserBlockMsg*/
var pool_blk_item coin.PoolBlkMsg
var blk_detail_height int64
var blk_detail_hash string
var blk_detail_success bool
var blk_detail_miner_diff float64
var blk_detail_pool_diff float64
if miner.Authorized != true {
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNAUTH_WORKER)
stratum.Send_reconnect_msg(miner)
return false, false, false
}
var new_found bool = false
var ack stratum.Submit_ack
ack.ID = id
ack.Result = true
//logg.Warn("[server]", zap.String("user", miner.User), zap.String("miner", miner.Miner))
//logg.Debug("[server]", zap.Float64("id", id), zap.String("job_id", job_id))
//logg.Debug("[server]", zap.String("nonce2", nonce2), zap.String("ntime", ntime), zap.String("nonce", nonce))
//stratum.UpdateJobs(miner)
v, ok := miner.Jobs.Load(job_id)
if ok {
job := v.(msg.Sha3xStratumJob)
if job.Height < miner.CurHeight-1 {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_STALED_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
//logg.Debug("[server]", zap.Uint64("ntime", nt), zap.Uint64("mintime", uint64(job.Mintime)), zap.Uint64("jobtime", jt_reverse))
/*if nt < uint64(job.Mintime) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_OLD)
} else if nt > jt_reverse+uint64(600) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_NEW)
} else */{
if (miner.LastNonce != nonce) || (miner.LastHeader != job.Header) {
miner.LastHeader = job.Header
miner.LastNonce = nonce
job.Nonce = nonce
job.Extranonce2 = nonce2
//logg.Debug("[server]", zap.Uint32("height", job.Height), zap.String("target", job.Target))
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
}
phb, _ := hex.DecodeString(job.Header)
nb, _ := hex.DecodeString(nonce)
var calc_hash []byte
var header Sha3xBlockHeader
for i := 0; i < 8; i++ {
header.Nonce[i] = nb[i]
}
for i := 0; i < 32; i++ {
header.Header[i] = phb[i]
}
header.Algo = 1
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
//logg.Debug("[server]", zap.String("hash in", submit_item.Header))
//calc_hash, header := util.BuildBlockHash(&(job), true, Build_PowHash)
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
if miner.ZlogInit {
miner.Zlog.Info().Msg("hash in " + submit_item.Header + " calc_hash " + hex.EncodeToString(calc_hash) + " " + miner.User + "." + miner.Miner)
}
submit_target := new(big.Int)
//submit_target.SetBytes(common.Reverse(calc_hash))
//hashs, _ := utility.ReverseS(hex.EncodeToString(calc_hash))
//hashb, _ := hex.DecodeString(hashs)
//submit_target.SetBytes(hashb)
submit_target.SetBytes(calc_hash)
/*logg.Debug("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
if submit_target.Cmp(miner.Target) > 0 {*/
calc_diff := utility.Target2Diff(utility.Reverse(calc_hash))
//calc_diff := utility.Target2Diff(calc_hash)
//log.Printf("diff,calc_diff:%f difficulty:%f ", calc_diff, miner.Difficulty)
//logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " target diff " + fmt.Sprintf("%f", (miner.Difficulty)) + " submit diff " + fmt.Sprintf("%f", (calc_diff)))
}
//logg.Debug("[server]", zap.String("target", miner.Target.String()), zap.Any("bytes", miner.Target.Bytes()))
//logg.Info("[server]", zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
//if calc_diff < miner.Difficulty {
if calc_diff < job.JobDifficulty {
//gpu protocol handler
/*for i := 0; i < 8; i++ {
temp_nonce := header.Nonce[8+i]
header.Nonce[8+i] = header.Nonce[i]
header.Nonce[i] = temp_nonce
}
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(Sha3xBlockHeaderToBytes(header))))*/
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
//submit_target = new(big.Int)
/*submit_target.SetBytes(calc_hash)
calc_diff = utility.Target2Diff(calc_hash)
logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if calc_diff < miner.Difficulty {
*/
ack.Result = false
miner.ErrLowDiffs = miner.ErrLowDiffs + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE)
return false, false, false
//}
}
//logg.Warn("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())))
//submit_target.Text(16)
/*if submit_target.Cmp(miner.ServerTarget) <= 0 {*/
//log.Println("[server]server_target", miner.ServerTargetS)
//stb, _ := hex.DecodeString(miner.ServerTargetS)
stb, _ := hex.DecodeString(job.Target)
//logg.Info("[server]", zap.String("target", job.Target))
//server_diff := Target2Diff(common.Reverse(stb))
server_diff := utility.Target2Diff(utility.Reverse(stb))
//log.Printf("[server]server_diff %f", server_diff)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("ServerTargetS", miner.ServerTargetS))
network_target := new(big.Int)
network_target.SetBytes(stb)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("submit_target", hex.EncodeToString(submit_target.Bytes())), zap.String("network_target", hex.EncodeToString(network_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())), zap.Int("cmp", network_target.Cmp(submit_target)))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " calc_diff " + fmt.Sprintf("%f", (calc_diff)) + " miner.Difficulty " + fmt.Sprintf("%f", (miner.Difficulty)) + " server_diff " + fmt.Sprintf("%f", (server_diff)))
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " submit_target " + hex.EncodeToString(submit_target.Bytes()) + " network_target " + hex.EncodeToString(network_target.Bytes()) + " target " + hex.EncodeToString(miner.ServerTarget.Bytes()) + " cmp " + fmt.Sprintf("%d", (network_target.Cmp(submit_target))))
}
submit_item.Hash = hex.EncodeToString(calc_hash)
submit_item.Target = hex.EncodeToString(miner.Target.Bytes())
submit_item.Submit_target = hex.EncodeToString(calc_hash)
submit_item.Height = int64(job.Height)
submit_item.Pow = hex.EncodeToString(calc_hash)
submit_item.Net_target = hex.EncodeToString(network_target.Bytes())
/*user_blk_item.Height = int64(job.Height)
user_blk_item.Hash = hex.EncodeToString(calc_hash)
user_blk_item.Pow = hex.EncodeToString(calc_hash)
user_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())*/
pool_blk_item.Height = int64(job.Height)
pool_blk_item.Hash = hex.EncodeToString(calc_hash)
pool_blk_item.Pow = hex.EncodeToString(calc_hash)
pool_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())
blk_detail_height = int64(job.Height)
blk_detail_hash = hex.EncodeToString(calc_hash)
blk_detail_success = false
//blk_detail_miner_diff = miner.Difficulty
blk_detail_miner_diff = job.JobDifficulty
blk_detail_pool_diff = miner.Server.RefDifficulty
if ack.Result == true {
/*if miner.CurHeight != 0 && miner.CurHeight == job.Height {
return
}*/
//if true {
if (calc_diff >= server_diff) || (network_target.Cmp(submit_target) >= 0) {
//if true {
miner.Server.SubIdx++
Produce_block_submit(miner /*header,*/, &job, submit_item.Hash, miner.Server.SubIdx)
miner.SubmitIndex++
miner.Submits = miner.Submits + 1
//miner.CurHeight = job.Height
new_found = true
}
if new_found && float64(miner.Server.Sha3xJob.U64target) <= calc_diff {
pool_blk_item.Submit = "y"
pool_blk_item.Success = false
pool_blk_item.Accepts = miner.Accepts
pool_blk_item.Rejects = miner.Rejects
pool_blk_item.Reward = 0
pool_blk_item.Fee = 0
pool_blk_item.Nonce = nonce
pool_blk_item.SubIdx = miner.Server.SubIdx
dbif.NotifyPoolBlkStatsDb2(miner.Server, &pool_blk_item)
}
}
} else {
miner.LastHeader = job.Header
miner.LastNonce = nonce
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_DUP_SHARE)
miner.ErrDuplicates = miner.ErrDuplicates + 1
return false, false, false
}
}
} else {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_FOUND_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
miner.LastJobId = job_id
ack.Error = nil
body, err := json.Marshal(ack)
if err != nil {
//logg.Error("[server]", zap.String("Marshal", err.Error()))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit Marshal " + err.Error())
}
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNKNOWN)
return false, false, false
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//miner.Server.Miners.Delete(miner.MinerId)
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
//logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Lock()
miner.Status = coin.MINER_STATUS_RUNNING
miner.TxLock.Unlock()
if ack.Result {
miner.Accepts += miner.Difficulty
miner.M5Accepts += miner.Difficulty
miner.VarDiffOpt.SubmitShares += miner.Difficulty
} else {
miner.Rejects += miner.Difficulty
}
now := time.Now()
if miner.Server.Config.Diff.Filter == "kalman" {
if ack.Result {
share_interval := now.Sub(miner.LastSubmitime).Seconds()
mhs := miner.Difficulty * share_interval
diff_next, kalman_p := miner.DiffHandler.Handler(miner.Difficulty, share_interval)
mhs_est := diff_next * miner.Server.Config.Diff.DiffAdjustInterval
ratio := diff_next / miner.Difficulty
if ratio > 0 {
if now.Sub(miner.StartSubmitTime).Seconds() > 180 {
if ratio >= 2 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else if ratio <= 0.5 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else {
}
} else {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
/*if ratio >= 1.1 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else if ratio <= 0.8 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else {
}*/
}
}
if miner.DifficultyNext > 0.0 {
if miner.DifficultyNext < miner.VarDiffOpt.MinDiff {
miner.DifficultyNext = miner.VarDiffOpt.MinDiff
} else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff {
miner.DifficultyNext = miner.VarDiffOpt.MaxDiff
}
}
//miner.VarDiffOpt.LastCalcTime = now
if miner.Server.Config.Diff.Dbg {
coin.New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, diff_next, kalman_p, share_interval, mhs, mhs_est)
}
//log.Println("diff adjust", ratio, diff_next, miner.Difficulty, miner.DifficultyNext)
}
} else {
// submit time < DiffAdjustInterval,then up adjust diff
if now.Sub(miner.LastSubmitime).Seconds() < miner.Server.Config.Diff.DiffAdjustInterval {
if ack.Result {
if miner.VarDiffOpt.Uptimes++; miner.VarDiffOpt.Uptimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.UP_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Uptimes = 0
}
// submit time > 2 * DiffAdjustInterval,then down adjust diff
if now.Sub(miner.LastSubmitime).Seconds() > miner.Server.Config.Diff.DiffAdjustInterval*2 {
if ack.Result {
if miner.VarDiffOpt.Downtimes++; miner.VarDiffOpt.Downtimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.DOWN_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Downtimes = 0
}
}
if ack.Result {
miner.LastSubmitime = now
miner.VarDiffOpt.LastSubmitTime = now
}
var duration float64 = float64(now.Sub(miner.StartSubmitTime)) / 1000000000
if duration < 1 {
duration = 1
}
//diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF)
diffOneShareHashesAvg := uint64(0xFFFFFFFFFFFFFFFF)
miner.AverageHashrate = miner.Accepts * float64(diffOneShareHashesAvg) / duration / 1000000
var m5_duration float64 = float64(now.Sub(miner.M5SubmitTime)) / 1000000000
if m5_duration >= float64(time.Minute*5)/1000000000 {
miner.M5SubmitTime = now
miner.M5Hashrate = miner.M5Accepts * float64(diffOneShareHashesAvg) / m5_duration / 1000000
//logg.Info("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
miner.M5Accepts = 0
}
//logg.Warn("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("Rejects", miner.Rejects))
//logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares), zap.Float64("SubmitShares", miner.VarDiffOpt.SubmitShares))
//logg.Warn("[server]", zap.Float64("reject rate", miner.Rejects/(miner.Accepts+miner.Rejects)), zap.Float64("Hashrate(MH/S)", miner.AverageHashrate))
//logg.Warn("[server]", zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit M5Accepts " + fmt.Sprintf("%f", (miner.M5Accepts)) + " M5Hashrate(MH/S) " + fmt.Sprintf("%f", (miner.M5Hashrate)))
}
//logg.Info("[server]", zap.Float64("LastCalcTime", float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000))
//calc acutal submit shares period of time, then compare with target shares and adjust diff
if miner.Server.Config.Diff.Filter == "kalman" {
} else {
if float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000 >= miner.VarDiffOpt.AdjustTime {
coin.VarAdjustDifficulty(miner, coin.UPDATE_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
if ack.Result {
submit_item.Success = false
if new_found {
submit_item.Submit = "y"
submit_item.SubIdx = miner.Server.SubIdx
} else {
submit_item.Submit = "n"
submit_item.SubIdx = -1
}
submit_item.Accepts = miner.Accepts
submit_item.Total_accepts = miner.Accepts
submit_item.Rejects = miner.Rejects
submit_item.Total_rejects = miner.Rejects
submit_item.Reward = 0
submit_item.Fee = 0
submit_item.Nonce = nonce
//dbif.NotifyMinerDb2(miner, &submit_item)
dbif.NotifyBlkDetailDb(miner, blk_detail_height, blk_detail_hash, blk_detail_success, blk_detail_miner_diff, blk_detail_pool_diff, nonce, submit_item.SubIdx)
return true, new_found, true
}
return false, false, true
}
func Produce_block_submit(miner *coin.MinerObj /*header Sha3xBlockHeader,*/, job *msg.Sha3xStratumJob, PowHash string, SubIdx int64) {
var nm msg.BlockSha3xMsg
nm.Id = job.Id
nm.Header = job.Header
//nm.Nonce = job.Nonce
noncer, _ := stratum.ReverseHexStringByByte(job.Nonce)
nonce, err := strconv.ParseUint(noncer, 16, 64)
nm.Nonce = nonce
nm.Pow = PowHash
nm.SubIdx = SubIdx
nm.User = miner.User
nm.Miner = miner.Miner
nm.Index = fmt.Sprint(miner.MinerIndex)
body, err := json.Marshal(nm)
if err != nil {
logg.Error("[server]", zap.String("failed to Marshal job", err.Error()))
return
}
blk := string(body)
//Add Height
/*heightb := utility.Uint32ToByte(job.Height)
heights := hex.EncodeToString(heightb)
blk += heights
var Height uint32 = utility.ByteToUint32(heightb)*/
nm.Height = (uint64)(job.Height)
logg.Warn("[server]", zap.Uint32("Height", job.Height))
//Add SubmitIndex
/*indexb := utility.Uint32ToByte(miner.SubmitIndex)
indexs := hex.EncodeToString(indexb)
blk += indexs
var SubmitIndex uint32 = utility.ByteToUint32(indexb)*/
nm.SubmitIdx = (uint64)(miner.SubmitIndex)
logg.Info("[server]", zap.Uint32("SubmitIndex", miner.SubmitIndex))
logg.Info("[server]", zap.String("blk", blk))
if miner.Server.PubCh == nil {
miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub)
}
if miner.Server.PubCh != nil {
//miner.Server.PubCh.SendChan <- [][]byte{[]byte("blksha3x"), []byte(blk)}
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blksha3x"), []byte(blk)})
if err != nil {
miner.Server.PubCh.Destroy()
miner.Server.PubCh = nil
logg.Info("[server]", zap.String("blk", err.Error()))
} else {
logg.Info("[server]", zap.String("blk", "sent"))
}
}
}
// server-->miner
func sha3x_parse_miner_notify(miner *coin.MinerObj, msg msg.Sha3xStratumJob) int {
if miner.Sha3xJob.Height != msg.Height {
miner.Job.IsClean = true
}
miner.Sha3xJob = msg
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
miner.Job.Extranonce2_size = msg.Extranonce2_size
//miner.Server.Logg.Info("[server]", zap.Int32("miner.Version", miner.Version), zap.Int32("msg.Version", msg.Version))
return 1
}
func Init(server *coin.ServerContext) {
ServerSha3xCtx.ServerCtx = server
logg = server.Logg
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_SHA3X_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {
miner.Sha3xJob = miner.Server.Sha3xJob
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
server_target := new(big.Int)
t_bytes, err := hex.DecodeString(miner.NexaJob.Target)
if err != nil {
logg.Error("[server]", zap.String("DecodeString", err.Error()))
return
}
//server_target.SetBytes(common.Reverse(t_bytes))
server_target.SetBytes(t_bytes)
miner.ServerTarget = server_target
miner.ServerTargetS = miner.Server.SJob.Target
}
func Handle_subscribe_sha3x(miner *coin.MinerObj, id float64, extranonce1 string) {
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
}
func HandleMinerAuth(miner *coin.MinerObj) {
}
func HandleMinerSubmit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
//nonce_str, _ := stratum.ReverseHexStringByByte(nonce)
accept_ok, submit_ok, handle_ok := handle_submit(miner, id, miner_user, job_id, nonce2, ntime, nonce)
return accept_ok, submit_ok, handle_ok
}
func SetDifficulty(miner *coin.MinerObj) {
stratum.Set_difficulty(miner)
}
func Sha3xNotify(miner *coin.MinerObj) {
miner.TxLock.Lock()
if !((miner.Status == coin.MINER_STATUS_AUTHORIZED) || (miner.Status == coin.MINER_STATUS_RUNNING)) {
miner.TxLock.Unlock()
return
}
miner.TxLock.Unlock()
if miner.DifficultyNext > -1 {
ratio := miner.DifficultyNext / miner.Difficulty
if ratio > 1.1 || ratio < 0.9 {
miner.Difficulty = miner.DifficultyNext
miner.DifficultyNext = -1
stratum.Set_difficulty(miner)
//logg.Info("[gbt]", zap.Float64("update Diff", miner.Difficulty))
} else {
miner.DifficultyNext = -1
}
}
miner.TxLock.Lock()
//log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId)
var msg Sha3xNotify_msg
idb := make([]byte, 4)
binary.BigEndian.PutUint32(idb, miner.JobId)
miner.Job.Job_id = hex.EncodeToString(idb)
msg.Params.Algo = "sha3x"
msg.Params.Job_id = miner.Job.Job_id
msg.Params.Blob = miner.Sha3xJob.Header
msg.Params.Height = miner.Sha3xJob.Height
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
//msg.Params.Target = target_s[48:]
target_new, _ := utility.DiffToTarget(miner.Difficulty)
target_str := fmt.Sprintf("%064x", target_new.Bytes())
target_strr, strerr := stratum.ReverseHexStringByByte(target_str)
if strerr != nil {
println("ReverseHexStringByByte", strerr.Error())
}
//println("target=", target_str, "r=", target_strr)
msg.Params.Target = target_strr[48:]
miner.CurHeight = miner.Sha3xJob.Height
miner.Sha3xJob.JobDifficulty = miner.Difficulty
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.Sha3xJob)
/*var entry coin.JobListEntry
entry.Job_id = miner.Job.Job_id
entry.Ts = time.Now()
miner.LockForJobs.Lock()
miner.JobList.PushFront(entry)
var removes string = ""
if miner.JobList.Len() > int(coin.LOCAL_JOBS_TOTAL_SIZE) {
e := miner.JobList.Back()
entry := e.Value.(coin.JobListEntry)
removes = entry.Job_id
miner.JobList.Remove(e)
}
miner.LockForJobs.Unlock()
if len(removes) > 0 {
miner.Jobs.Delete(removes)
}*/
stratum.AddAndUpdateJob(miner)
stratum.UpdateJobs(miner)
//miner.LastJobId = miner.Job.Job_id
miner.JobId++
var body []byte
var err error
msg.Jsonrpc = "2.0"
msg.Method = "job"
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//delete(miner.Server.Miners, miner.MinerId)
//miner.Server.Miners.Delete(miner.MinerId)
}
//miner.Server.Logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func Notify(miner *coin.MinerObj) {
Sha3xNotify(miner)
}
func formatUint64ToHexWithPadding(val uint64) string {
hexStr := fmt.Sprintf("%016x", val)
if len(hexStr) < 64 {
paddingLen := 64 - len(hexStr)
hexStr += string(make([]byte, paddingLen))
for i := len(hexStr) - paddingLen; i < 64; i++ {
hexStr = hexStr[:i] + "0" + hexStr[i+1:]
}
}
return hexStr
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {
var result msg.Sha3xStratumJob
server.Logg.Warn("[server]", zap.String("receive", "job"))
if err := json.Unmarshal(Msg, &result); err != nil {
server.Logg.Error("[server]", zap.String("Unmarshal", err.Error()))
return
}
result.Target = formatUint64ToHexWithPadding(result.U64target)
//target_new, _ := utility.DiffToTarget((float64)(result.U64target))
//target_str := fmt.Sprintf("%064x", target_new.Bytes())
//result.Target = target_str
server.Sha3xJob = msg.Sha3xStratumJob(result)
logg.Debug("[gbt]", zap.String("Target", server.Sha3xJob.Target))
server.Sha3xJob.Extranonce2_size = 8
server.SJob.Extranonce2_size = 8
logg.Debug("[gbt]", zap.Uint32("Height", server.Sha3xJob.Height), zap.String("Target", server.Sha3xJob.Target), zap.String("Header", server.Sha3xJob.Header) /*, zap.Uint64("Timastamp", server.Sha3xJob.CurTime)*/)
targetb, _ := hex.DecodeString(server.Sha3xJob.Target)
logg.Debug("[gbt]", zap.Uint64("Id", server.Sha3xJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb))))
server.NetHight = uint64(server.Sha3xJob.Height)
server.NetTarget = server.Sha3xJob.Target
server.Miners.Range(func(k, v interface{}) bool {
if v != nil {
m, ok := v.(*(coin.MinerObj))
if ok {
if m != nil {
server.Logg.Info("[server]", zap.String("lock", "start"))
m.TxLock.Lock()
status := m.Status
cmd := sha3x_parse_miner_notify(m, server.Sha3xJob)
m.TxLock.Unlock()
server.Logg.Info("[server]", zap.String("lock", "end"))
var need_notify bool = true
if time.Now().Sub(m.ConnSetupTime) >= time.Duration(coin.CONN_EXPIRED_TIME)*time.Second {
if (status != coin.MINER_STATUS_RUNNING) && (status != coin.MINER_STATUS_AUTHORIZED) {
//m.Conn.Close()
need_notify = false
}
}
if need_notify {
switch cmd {
case 0: //extranonce 1 and extranonce2 size
//TODO
case 1: //notify
Sha3xNotify(m)
}
}
}
}
}
return true
})
}
func IsMhsLow(miner *coin.MinerObj) bool {
if miner.Mhs5M < 1 {
return true
}
return false
}
func GetBlockInterval() int {
return 3600
}

1865
internal/server/server.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
// hash_sha3x.go
package sha3x
/*
#cgo CFLAGS : -I../include
#cgo LDFLAGS: -L../lib -lsha3x
#include <stdio.h>
#include <stdlib.h>
#include "sha3xapi.h"
*/
import "C"
import (
//"encoding/hex"
//"log"
"unsafe"
)
func BuildPowHash(h Sha3xBlockHeader) []byte {
outputs := make([]byte, 32)
inb := Sha3xBlockHeaderToBytes(h)
//log.Println("[sha3x]in", hex.EncodeToString(inb))
in := (*C.uchar)(C.CBytes(inb))
output := (*C.uchar)(C.malloc(32))
C.sha3x_hash(output, in)
p := uintptr(unsafe.Pointer(output))
for i := 0; i < 32; i++ {
j := *(*byte)(unsafe.Pointer(p))
outputs[i] = j
p += unsafe.Sizeof(j)
}
C.free(unsafe.Pointer(output))
C.free(unsafe.Pointer(in))
outputs32 := make([]byte, 32)
for i := 0; i < 32; i++ {
outputs32[i] = outputs[i]
}
return outputs32
}

View File

@ -0,0 +1,761 @@
// sha3x.go
package sha3x
import (
"strconv"
//"database/sql"
"encoding/binary"
"encoding/hex"
"encoding/json"
//"log"
//"math"
"math/big"
//"strings"
"fmt"
"pool/internal/msg"
"pool/internal/server/coin"
"pool/internal/server/dbif"
"pool/internal/stratum"
"pool/internal/utility"
"time"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
const SERVER_SHA3X_VERSION string = "sha3x v0.1a"
type Sha3xBlockHeader struct {
Nonce [8]byte
Header [32]byte
Algo byte
}
func Sha3xBlockHeaderToBytes(h Sha3xBlockHeader) []byte {
out := make([]byte, 8+32+1)
for i := 0; i < 8; i++ {
out[i] = h.Nonce[i]
}
for i := 0; i < 32; i++ {
out[8+i] = h.Header[i]
}
out[8+32] = h.Algo
return out
}
type ServerSha3xContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
Sha3xJob msg.Sha3xStratumJob
}
var logg *zap.Logger
var ServerSha3xCtx ServerSha3xContext
type Sha3xNotify_params_msg struct {
Algo string `json:"algo"`
Blob string `json:"blob"`
Height uint32 `json:"height"`
Job_id string `json:"job_id"`
Target string `json:"target"`
}
type Sha3xNotify_msg struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params Sha3xNotify_params_msg `json:"params"`
}
func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
var submit_item coin.BlockMsg
/*var user_blk_item coin.UserBlockMsg*/
var pool_blk_item coin.PoolBlkMsg
var blk_detail_height int64
var blk_detail_hash string
var blk_detail_success bool
var blk_detail_miner_diff float64
var blk_detail_pool_diff float64
if miner.Authorized != true {
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNAUTH_WORKER)
stratum.Send_reconnect_msg(miner)
return false, false, false
}
var new_found bool = false
var ack stratum.Submit_ack
ack.ID = id
ack.Result = true
//logg.Warn("[server]", zap.String("user", miner.User), zap.String("miner", miner.Miner))
//logg.Debug("[server]", zap.Float64("id", id), zap.String("job_id", job_id))
//logg.Debug("[server]", zap.String("nonce2", nonce2), zap.String("ntime", ntime), zap.String("nonce", nonce))
//stratum.UpdateJobs(miner)
v, ok := miner.Jobs.Load(job_id)
if ok {
job := v.(msg.Sha3xStratumJob)
if job.Height < miner.CurHeight-1 {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_STALED_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
//logg.Debug("[server]", zap.Uint64("ntime", nt), zap.Uint64("mintime", uint64(job.Mintime)), zap.Uint64("jobtime", jt_reverse))
/*if nt < uint64(job.Mintime) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_OLD)
} else if nt > jt_reverse+uint64(600) {
ack.Result = false
util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_NEW)
} else */{
if (miner.LastNonce != nonce) || (miner.LastHeader != job.Header) {
miner.LastHeader = job.Header
miner.LastNonce = nonce
job.Nonce = nonce
job.Extranonce2 = nonce2
//logg.Debug("[server]", zap.Uint32("height", job.Height), zap.String("target", job.Target))
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
}
phb, _ := hex.DecodeString(job.Header)
nb, _ := hex.DecodeString(nonce)
var calc_hash []byte
var header Sha3xBlockHeader
for i := 0; i < 8; i++ {
header.Nonce[i] = nb[i]
}
for i := 0; i < 32; i++ {
header.Header[i] = phb[i]
}
header.Algo = 1
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
//logg.Debug("[server]", zap.String("hash in", submit_item.Header))
//calc_hash, header := util.BuildBlockHash(&(job), true, Build_PowHash)
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
if miner.ZlogInit {
miner.Zlog.Info().Msg("hash in " + submit_item.Header + " calc_hash " + hex.EncodeToString(calc_hash) + " " + miner.User + "." + miner.Miner)
}
submit_target := new(big.Int)
//submit_target.SetBytes(common.Reverse(calc_hash))
//hashs, _ := utility.ReverseS(hex.EncodeToString(calc_hash))
//hashb, _ := hex.DecodeString(hashs)
//submit_target.SetBytes(hashb)
submit_target.SetBytes(calc_hash)
/*logg.Debug("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
if submit_target.Cmp(miner.Target) > 0 {*/
calc_diff := utility.Target2Diff(utility.Reverse(calc_hash))
//calc_diff := utility.Target2Diff(calc_hash)
//log.Printf("diff,calc_diff:%f difficulty:%f ", calc_diff, miner.Difficulty)
//logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " target diff " + fmt.Sprintf("%f", (miner.Difficulty)) + " submit diff " + fmt.Sprintf("%f", (calc_diff)))
}
//logg.Debug("[server]", zap.String("target", miner.Target.String()), zap.Any("bytes", miner.Target.Bytes()))
//logg.Info("[server]", zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff), zap.String("target", hex.EncodeToString(miner.Target.Bytes())))
//if calc_diff < miner.Difficulty {
if calc_diff < job.JobDifficulty {
//gpu protocol handler
/*for i := 0; i < 8; i++ {
temp_nonce := header.Nonce[8+i]
header.Nonce[8+i] = header.Nonce[i]
header.Nonce[i] = temp_nonce
}
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(header))
calc_hash = BuildPowHash(header)
logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(Sha3xBlockHeaderToBytes(header))))*/
//logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/)
//submit_target = new(big.Int)
/*submit_target.SetBytes(calc_hash)
calc_diff = utility.Target2Diff(calc_hash)
logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff))
if calc_diff < miner.Difficulty {
*/
ack.Result = false
miner.ErrLowDiffs = miner.ErrLowDiffs + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE)
return false, false, false
//}
}
//logg.Warn("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())))
//submit_target.Text(16)
/*if submit_target.Cmp(miner.ServerTarget) <= 0 {*/
//log.Println("[server]server_target", miner.ServerTargetS)
//stb, _ := hex.DecodeString(miner.ServerTargetS)
stb, _ := hex.DecodeString(job.Target)
//logg.Info("[server]", zap.String("target", job.Target))
//server_diff := Target2Diff(common.Reverse(stb))
server_diff := utility.Target2Diff(utility.Reverse(stb))
//log.Printf("[server]server_diff %f", server_diff)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("ServerTargetS", miner.ServerTargetS))
network_target := new(big.Int)
network_target.SetBytes(stb)
//logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff))
//logg.Debug("[server]", zap.String("submit_target", hex.EncodeToString(submit_target.Bytes())), zap.String("network_target", hex.EncodeToString(network_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())), zap.Int("cmp", network_target.Cmp(submit_target)))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " calc_diff " + fmt.Sprintf("%f", (calc_diff)) + " miner.Difficulty " + fmt.Sprintf("%f", (miner.Difficulty)) + " server_diff " + fmt.Sprintf("%f", (server_diff)))
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " submit_target " + hex.EncodeToString(submit_target.Bytes()) + " network_target " + hex.EncodeToString(network_target.Bytes()) + " target " + hex.EncodeToString(miner.ServerTarget.Bytes()) + " cmp " + fmt.Sprintf("%d", (network_target.Cmp(submit_target))))
}
submit_item.Hash = hex.EncodeToString(calc_hash)
submit_item.Target = hex.EncodeToString(miner.Target.Bytes())
submit_item.Submit_target = hex.EncodeToString(calc_hash)
submit_item.Height = int64(job.Height)
submit_item.Pow = hex.EncodeToString(calc_hash)
submit_item.Net_target = hex.EncodeToString(network_target.Bytes())
/*user_blk_item.Height = int64(job.Height)
user_blk_item.Hash = hex.EncodeToString(calc_hash)
user_blk_item.Pow = hex.EncodeToString(calc_hash)
user_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())*/
pool_blk_item.Height = int64(job.Height)
pool_blk_item.Hash = hex.EncodeToString(calc_hash)
pool_blk_item.Pow = hex.EncodeToString(calc_hash)
pool_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())
blk_detail_height = int64(job.Height)
blk_detail_hash = hex.EncodeToString(calc_hash)
blk_detail_success = false
//blk_detail_miner_diff = miner.Difficulty
blk_detail_miner_diff = job.JobDifficulty
blk_detail_pool_diff = miner.Server.RefDifficulty
if ack.Result == true {
/*if miner.CurHeight != 0 && miner.CurHeight == job.Height {
return
}*/
//if true {
if (calc_diff >= server_diff) || (network_target.Cmp(submit_target) >= 0) {
//if true {
miner.Server.SubIdx++
Produce_block_submit(miner /*header,*/, &job, submit_item.Hash, miner.Server.SubIdx)
miner.SubmitIndex++
miner.Submits = miner.Submits + 1
//miner.CurHeight = job.Height
new_found = true
}
if new_found && float64(miner.Server.Sha3xJob.U64target) <= calc_diff {
pool_blk_item.Submit = "y"
pool_blk_item.Success = false
pool_blk_item.Accepts = miner.Accepts
pool_blk_item.Rejects = miner.Rejects
pool_blk_item.Reward = 0
pool_blk_item.Fee = 0
pool_blk_item.Nonce = nonce
pool_blk_item.SubIdx = miner.Server.SubIdx
dbif.NotifyPoolBlkStatsDb2(miner.Server, &pool_blk_item)
}
}
} else {
miner.LastHeader = job.Header
miner.LastNonce = nonce
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_DUP_SHARE)
miner.ErrDuplicates = miner.ErrDuplicates + 1
return false, false, false
}
}
} else {
ack.Result = false
stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_FOUND_JOB)
miner.ErrStaleds = miner.ErrStaleds + 1
return false, false, false
}
miner.LastJobId = job_id
ack.Error = nil
body, err := json.Marshal(ack)
if err != nil {
//logg.Error("[server]", zap.String("Marshal", err.Error()))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit Marshal " + err.Error())
}
miner.ErrOthers = miner.ErrOthers + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNKNOWN)
return false, false, false
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//miner.Server.Miners.Delete(miner.MinerId)
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
//logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Lock()
miner.Status = coin.MINER_STATUS_RUNNING
miner.TxLock.Unlock()
if ack.Result {
miner.Accepts += miner.Difficulty
miner.M5Accepts += miner.Difficulty
miner.VarDiffOpt.SubmitShares += miner.Difficulty
} else {
miner.Rejects += miner.Difficulty
}
now := time.Now()
if miner.Server.Config.Diff.Filter == "kalman" {
if ack.Result {
share_interval := now.Sub(miner.LastSubmitime).Seconds()
mhs := miner.Difficulty * share_interval
diff_next, kalman_p := miner.DiffHandler.Handler(miner.Difficulty, share_interval)
mhs_est := diff_next * miner.Server.Config.Diff.DiffAdjustInterval
ratio := diff_next / miner.Difficulty
if ratio > 0 {
if now.Sub(miner.StartSubmitTime).Seconds() > 180 {
if ratio >= 2 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else if ratio <= 0.5 {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else {
}
} else {
//miner.DifficultyNext = math.Ceil(diff_next*100) / 100
miner.DifficultyNext = diff_next * 10000000 / 10000000
/*if ratio >= 1.1 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else if ratio <= 0.8 {
miner.DifficultyNext = math.Ceil(diff_next*100) / 100
} else {
}*/
}
}
if miner.DifficultyNext > 0.0 {
if miner.DifficultyNext < miner.VarDiffOpt.MinDiff {
miner.DifficultyNext = miner.VarDiffOpt.MinDiff
} else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff {
miner.DifficultyNext = miner.VarDiffOpt.MaxDiff
}
}
//miner.VarDiffOpt.LastCalcTime = now
if miner.Server.Config.Diff.Dbg {
coin.New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, diff_next, kalman_p, share_interval, mhs, mhs_est)
}
//log.Println("diff adjust", ratio, diff_next, miner.Difficulty, miner.DifficultyNext)
}
} else {
// submit time < DiffAdjustInterval,then up adjust diff
if now.Sub(miner.LastSubmitime).Seconds() < miner.Server.Config.Diff.DiffAdjustInterval {
if ack.Result {
if miner.VarDiffOpt.Uptimes++; miner.VarDiffOpt.Uptimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.UP_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Uptimes = 0
}
// submit time > 2 * DiffAdjustInterval,then down adjust diff
if now.Sub(miner.LastSubmitime).Seconds() > miner.Server.Config.Diff.DiffAdjustInterval*2 {
if ack.Result {
if miner.VarDiffOpt.Downtimes++; miner.VarDiffOpt.Downtimes >= coin.DIFFICULTY_WAIT_TIMES {
coin.VarAdjustDifficulty(miner, coin.DOWN_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
} else {
miner.VarDiffOpt.Downtimes = 0
}
}
if ack.Result {
miner.LastSubmitime = now
miner.VarDiffOpt.LastSubmitTime = now
}
var duration float64 = float64(now.Sub(miner.StartSubmitTime)) / 1000000000
if duration < 1 {
duration = 1
}
//diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF)
diffOneShareHashesAvg := uint64(0xFFFFFFFFFFFFFFFF)
miner.AverageHashrate = miner.Accepts * float64(diffOneShareHashesAvg) / duration / 1000000
var m5_duration float64 = float64(now.Sub(miner.M5SubmitTime)) / 1000000000
if m5_duration >= float64(time.Minute*5)/1000000000 {
miner.M5SubmitTime = now
miner.M5Hashrate = miner.M5Accepts * float64(diffOneShareHashesAvg) / m5_duration / 1000000
//logg.Info("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
miner.M5Accepts = 0
}
//logg.Warn("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("Rejects", miner.Rejects))
//logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares), zap.Float64("SubmitShares", miner.VarDiffOpt.SubmitShares))
//logg.Warn("[server]", zap.Float64("reject rate", miner.Rejects/(miner.Accepts+miner.Rejects)), zap.Float64("Hashrate(MH/S)", miner.AverageHashrate))
//logg.Warn("[server]", zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate))
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit M5Accepts " + fmt.Sprintf("%f", (miner.M5Accepts)) + " M5Hashrate(MH/S) " + fmt.Sprintf("%f", (miner.M5Hashrate)))
}
//logg.Info("[server]", zap.Float64("LastCalcTime", float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000))
//calc acutal submit shares period of time, then compare with target shares and adjust diff
if miner.Server.Config.Diff.Filter == "kalman" {
} else {
if float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000 >= miner.VarDiffOpt.AdjustTime {
coin.VarAdjustDifficulty(miner, coin.UPDATE_DIFF)
miner.VarDiffOpt.LastCalcTime = now
}
}
if ack.Result {
submit_item.Success = false
if new_found {
submit_item.Submit = "y"
submit_item.SubIdx = miner.Server.SubIdx
} else {
submit_item.Submit = "n"
submit_item.SubIdx = -1
}
submit_item.Accepts = miner.Accepts
submit_item.Total_accepts = miner.Accepts
submit_item.Rejects = miner.Rejects
submit_item.Total_rejects = miner.Rejects
submit_item.Reward = 0
submit_item.Fee = 0
submit_item.Nonce = nonce
//dbif.NotifyMinerDb2(miner, &submit_item)
dbif.NotifyBlkDetailDb(miner, blk_detail_height, blk_detail_hash, blk_detail_success, blk_detail_miner_diff, blk_detail_pool_diff, nonce, submit_item.SubIdx)
return true, new_found, true
}
return false, false, true
}
func Produce_block_submit(miner *coin.MinerObj /*header Sha3xBlockHeader,*/, job *msg.Sha3xStratumJob, PowHash string, SubIdx int64) {
var nm msg.BlockSha3xMsg
nm.Id = job.Id
nm.Header = job.Header
//nm.Nonce = job.Nonce
noncer, _ := stratum.ReverseHexStringByByte(job.Nonce)
nonce, err := strconv.ParseUint(noncer, 16, 64)
nm.Nonce = nonce
nm.Pow = PowHash
nm.SubIdx = SubIdx
nm.User = miner.User
nm.Miner = miner.Miner
nm.Index = fmt.Sprint(miner.MinerIndex)
body, err := json.Marshal(nm)
if err != nil {
logg.Error("[server]", zap.String("failed to Marshal job", err.Error()))
return
}
blk := string(body)
//Add Height
/*heightb := utility.Uint32ToByte(job.Height)
heights := hex.EncodeToString(heightb)
blk += heights
var Height uint32 = utility.ByteToUint32(heightb)*/
nm.Height = (uint64)(job.Height)
logg.Warn("[server]", zap.Uint32("Height", job.Height))
//Add SubmitIndex
/*indexb := utility.Uint32ToByte(miner.SubmitIndex)
indexs := hex.EncodeToString(indexb)
blk += indexs
var SubmitIndex uint32 = utility.ByteToUint32(indexb)*/
nm.SubmitIdx = (uint64)(miner.SubmitIndex)
logg.Info("[server]", zap.Uint32("SubmitIndex", miner.SubmitIndex))
logg.Info("[server]", zap.String("blk", blk))
if miner.Server.PubCh == nil {
miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub)
}
if miner.Server.PubCh != nil {
//miner.Server.PubCh.SendChan <- [][]byte{[]byte("blksha3x"), []byte(blk)}
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blksha3x"), []byte(blk)})
if err != nil {
miner.Server.PubCh.Destroy()
miner.Server.PubCh = nil
logg.Info("[server]", zap.String("blk", err.Error()))
} else {
logg.Info("[server]", zap.String("blk", "sent"))
}
}
}
// server-->miner
func sha3x_parse_miner_notify(miner *coin.MinerObj, msg msg.Sha3xStratumJob) int {
if miner.Sha3xJob.Height != msg.Height {
miner.Job.IsClean = true
}
miner.Sha3xJob = msg
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
miner.Job.Extranonce2_size = msg.Extranonce2_size
//miner.Server.Logg.Info("[server]", zap.Int32("miner.Version", miner.Version), zap.Int32("msg.Version", msg.Version))
return 1
}
func Init(server *coin.ServerContext) {
ServerSha3xCtx.ServerCtx = server
logg = server.Logg
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_SHA3X_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {
miner.Sha3xJob = miner.Server.Sha3xJob
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
server_target := new(big.Int)
t_bytes, err := hex.DecodeString(miner.NexaJob.Target)
if err != nil {
logg.Error("[server]", zap.String("DecodeString", err.Error()))
return
}
//server_target.SetBytes(common.Reverse(t_bytes))
server_target.SetBytes(t_bytes)
miner.ServerTarget = server_target
miner.ServerTargetS = miner.Server.SJob.Target
}
func Handle_subscribe_sha3x(miner *coin.MinerObj, id float64, extranonce1 string) {
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
}
func HandleMinerAuth(miner *coin.MinerObj) {
}
func HandleMinerSubmit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) {
//nonce_str, _ := stratum.ReverseHexStringByByte(nonce)
accept_ok, submit_ok, handle_ok := handle_submit(miner, id, miner_user, job_id, nonce2, ntime, nonce)
return accept_ok, submit_ok, handle_ok
}
func SetDifficulty(miner *coin.MinerObj) {
stratum.Set_difficulty(miner)
}
func Sha3xNotify(miner *coin.MinerObj) {
miner.TxLock.Lock()
if !((miner.Status == coin.MINER_STATUS_AUTHORIZED) || (miner.Status == coin.MINER_STATUS_RUNNING)) {
miner.TxLock.Unlock()
return
}
miner.TxLock.Unlock()
if miner.DifficultyNext > -1 {
ratio := miner.DifficultyNext / miner.Difficulty
if ratio > 1.1 || ratio < 0.9 {
miner.Difficulty = miner.DifficultyNext
miner.DifficultyNext = -1
stratum.Set_difficulty(miner)
//logg.Info("[gbt]", zap.Float64("update Diff", miner.Difficulty))
} else {
miner.DifficultyNext = -1
}
}
miner.TxLock.Lock()
//log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId)
var msg Sha3xNotify_msg
idb := make([]byte, 4)
binary.BigEndian.PutUint32(idb, miner.JobId)
miner.Job.Job_id = hex.EncodeToString(idb)
msg.Params.Algo = "sha3x"
msg.Params.Job_id = miner.Job.Job_id
msg.Params.Blob = miner.Sha3xJob.Header
msg.Params.Height = miner.Sha3xJob.Height
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
//msg.Params.Target = target_s[48:]
target_new, _ := utility.DiffToTarget(miner.Difficulty)
target_str := fmt.Sprintf("%064x", target_new.Bytes())
target_strr, strerr := stratum.ReverseHexStringByByte(target_str)
if strerr != nil {
println("ReverseHexStringByByte", strerr.Error())
}
//println("target=", target_str, "r=", target_strr)
msg.Params.Target = target_strr[48:]
miner.CurHeight = miner.Sha3xJob.Height
miner.Sha3xJob.JobDifficulty = miner.Difficulty
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.Sha3xJob)
/*var entry coin.JobListEntry
entry.Job_id = miner.Job.Job_id
entry.Ts = time.Now()
miner.LockForJobs.Lock()
miner.JobList.PushFront(entry)
var removes string = ""
if miner.JobList.Len() > int(coin.LOCAL_JOBS_TOTAL_SIZE) {
e := miner.JobList.Back()
entry := e.Value.(coin.JobListEntry)
removes = entry.Job_id
miner.JobList.Remove(e)
}
miner.LockForJobs.Unlock()
if len(removes) > 0 {
miner.Jobs.Delete(removes)
}*/
stratum.AddAndUpdateJob(miner)
stratum.UpdateJobs(miner)
//miner.LastJobId = miner.Job.Job_id
miner.JobId++
var body []byte
var err error
msg.Jsonrpc = "2.0"
msg.Method = "job"
body, err = json.Marshal(msg)
if err != nil {
miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error()))
miner.TxLock.Unlock()
return
}
var body_string = string(body) + "\n"
err = stratum.Conn_tx(miner.Conn, []byte(body_string))
if err != nil {
//delete(miner.Server.Miners, miner.MinerId)
//miner.Server.Miners.Delete(miner.MinerId)
}
//miner.Server.Logg.Debug("[server]", zap.String("tx", body_string))
miner.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func Notify(miner *coin.MinerObj) {
Sha3xNotify(miner)
}
func formatUint64ToHexWithPadding(val uint64) string {
hexStr := fmt.Sprintf("%016x", val)
if len(hexStr) < 64 {
paddingLen := 64 - len(hexStr)
hexStr += string(make([]byte, paddingLen))
for i := len(hexStr) - paddingLen; i < 64; i++ {
hexStr = hexStr[:i] + "0" + hexStr[i+1:]
}
}
return hexStr
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {
var result msg.Sha3xStratumJob
server.Logg.Warn("[server]", zap.String("receive", "job"))
if err := json.Unmarshal(Msg, &result); err != nil {
server.Logg.Error("[server]", zap.String("Unmarshal", err.Error()))
return
}
result.Target = formatUint64ToHexWithPadding(result.U64target)
//target_new, _ := utility.DiffToTarget((float64)(result.U64target))
//target_str := fmt.Sprintf("%064x", target_new.Bytes())
//result.Target = target_str
server.Sha3xJob = msg.Sha3xStratumJob(result)
logg.Debug("[gbt]", zap.String("Target", server.Sha3xJob.Target))
server.Sha3xJob.Extranonce2_size = 8
server.SJob.Extranonce2_size = 8
logg.Debug("[gbt]", zap.Uint32("Height", server.Sha3xJob.Height), zap.String("Target", server.Sha3xJob.Target), zap.String("Header", server.Sha3xJob.Header) /*, zap.Uint64("Timastamp", server.Sha3xJob.CurTime)*/)
targetb, _ := hex.DecodeString(server.Sha3xJob.Target)
logg.Debug("[gbt]", zap.Uint64("Id", server.Sha3xJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb))))
server.NetHight = uint64(server.Sha3xJob.Height)
server.NetTarget = server.Sha3xJob.Target
server.Miners.Range(func(k, v interface{}) bool {
if v != nil {
m, ok := v.(*(coin.MinerObj))
if ok {
if m != nil {
server.Logg.Info("[server]", zap.String("lock", "start"))
m.TxLock.Lock()
status := m.Status
cmd := sha3x_parse_miner_notify(m, server.Sha3xJob)
m.TxLock.Unlock()
server.Logg.Info("[server]", zap.String("lock", "end"))
var need_notify bool = true
if time.Now().Sub(m.ConnSetupTime) >= time.Duration(coin.CONN_EXPIRED_TIME)*time.Second {
if (status != coin.MINER_STATUS_RUNNING) && (status != coin.MINER_STATUS_AUTHORIZED) {
//m.Conn.Close()
need_notify = false
}
}
if need_notify {
switch cmd {
case 0: //extranonce 1 and extranonce2 size
//TODO
case 1: //notify
Sha3xNotify(m)
}
}
}
}
}
return true
})
}
func IsMhsLow(miner *coin.MinerObj) bool {
if miner.Mhs5M < 1 {
return true
}
return false
}
func GetBlockInterval() int {
return 3600
}

1296
internal/stratum/stratum.go Normal file

File diff suppressed because it is too large Load Diff

367
internal/utility/utility.go Normal file
View File

@ -0,0 +1,367 @@
// utility.go
package utility
import (
"encoding/binary"
"encoding/json"
"fmt"
"io/ioutil"
"bytes"
"log"
"math"
"math/big"
"os"
"os/exec"
"strings"
"time"
"github.com/zeromq/goczmq"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
const BITCOIND_ZMQ_HASHBLOCK string = "hashblock"
type CoinConfig struct {
Coin string `json:"coin"`
Pprof string `json:"pprof,omitempty"`
}
type ZmqConfig struct {
Pub string `json:"pub"`
Sub string `json:"sub"`
}
type RedisConfig struct {
Addr string `json:"addr"`
Password string `json:"password"`
DB int `json:"db"`
}
type LogRotateConfig struct {
MaxSize int `json:"maxsize"`
MaxBackups int `json:"maxbackups"`
MaxAge int `json:"maxage"`
Compress bool `json:"compress"`
}
func InitLogg(zaplog *zap.Config, rotate *LogRotateConfig, coinname string, modulename string) (*zap.Logger, *lumberjack.Logger, error) {
os.MkdirAll("logs/"+coinname, os.ModePerm)
logfile := "./logs/" + coinname + "/" + modulename + ".log"
logRotate := &lumberjack.Logger{
Filename: logfile,
MaxSize: rotate.MaxSize,
MaxBackups: rotate.MaxBackups,
MaxAge: rotate.MaxAge,
Compress: rotate.Compress,
}
zaplog.EncoderConfig = zap.NewProductionEncoderConfig()
zaplog.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
opath := []string{"", ""}
opath[0] = zaplog.OutputPaths[0]
opath[1] = logfile
zaplog.OutputPaths = opath
l, err := zaplog.Build(
zap.WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewCore(
zapcore.NewJSONEncoder(zaplog.EncoderConfig),
zapcore.AddSync(logRotate),
zaplog.Level,
)
}),
)
if err != nil {
log.Fatal("[gbt]", err.Error())
return nil, nil, err
}
return l, logRotate, nil
}
func GetCoin(config_file string) (string, string) {
var config CoinConfig
data, err := ioutil.ReadFile(config_file)
if err != nil {
panic(err.Error())
}
if err = json.Unmarshal(data, &config); err != nil {
panic(err.Error())
}
return config.Coin, config.Pprof
}
func confirmXPubSubscriptions(pub *goczmq.Channeler, count int) {
for i := 0; i < count; i++ {
select {
case <-pub.RecvChan:
case <-time.After(time.Second * 2):
log.Println("confirmXPubSubscriptions, timeout")
}
}
}
func InitZmqPub(pub_host string) *goczmq.Sock {
pub_ch, err := goczmq.NewXPub(pub_host)
if err != nil {
log.Fatal("[server]", zap.String("NewXPub", "zmq pub create failed!"))
}
return pub_ch
}
func InitZmqSub(sub_to string, topic string) *goczmq.Sock {
sub_ch, err := goczmq.NewSub(sub_to, topic)
if err != nil {
log.Fatal("[server]", zap.String("NewSub", "zmq sub connect failed!"))
}
return sub_ch
}
func InitZmqPush(sub_to string) *goczmq.Sock {
push_ch, err := goczmq.NewPush(sub_to)
if err != nil {
log.Fatal("[server]", zap.String("NewPushChanneler", "zmq push connect failed!"))
}
//push_ch.Bind(sub_to)
return push_ch
}
func InitZmqPull(sub_to string) *goczmq.Sock {
pull_ch, err := goczmq.NewPull(sub_to)
if err != nil {
log.Fatal("[server]", zap.String("InitZmqPull", "zmq pull connect failed! "+err.Error()))
}
return pull_ch
}
func Int32ToString(n uint32) string {
buf := [11]byte{}
pos := len(buf)
i := int64(n)
signed := i < 0
if signed {
i = -i
}
for {
pos--
buf[pos], i = '0'+byte(i%10), i/10
if i == 0 {
if signed {
pos--
buf[pos] = '-'
}
return string(buf[pos:])
}
}
}
func ByteToUint32(bytes []byte) uint32 {
return binary.LittleEndian.Uint32(bytes)
}
func Reverse_string(instr string) string {
var outstr string = ""
for i := 0; i < len(instr)/2; i++ {
outstr = outstr + instr[len(instr)-i*2-2:len(instr)-i*2]
}
return outstr
}
// CompactToBig converts a compact representation of a whole number N to an
// unsigned 32-bit number. The representation is similar to IEEE754 floating
// point numbers.
//
// Like IEEE754 floating point, there are three basic components: the sign,
// the exponent, and the mantissa. They are broken out as follows:
//
// - the most significant 8 bits represent the unsigned base 256 exponent
// - bit 23 (the 24th bit) represents the sign bit
// - the least significant 23 bits represent the mantissa
//
// -------------------------------------------------
// | Exponent | Sign | Mantissa |
// -------------------------------------------------
// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
// -------------------------------------------------
//
// The formula to calculate N is:
//
// N = (-1^sign) * mantissa * 256^(exponent-3)
//
// This compact form is only used in bitcoin to encode unsigned 256-bit numbers
// which represent difficulty targets, thus there really is not a need for a
// sign bit, but it is implemented here to stay consistent with bitcoind.
func CompactToBig(compact uint32) *big.Int {
// Extract the mantissa, sign bit, and exponent.
mantissa := compact & 0x007fffff
isNegative := compact&0x00800000 != 0
exponent := uint(compact >> 24)
// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes to represent the full 256-bit number. So,
// treat the exponent as the number of bytes and shift the mantissa
// right or left accordingly. This is equivalent to:
// N = mantissa * 256^(exponent-3)
var bn *big.Int
if exponent <= 3 {
mantissa >>= 8 * (3 - exponent)
bn = big.NewInt(int64(mantissa))
} else {
bn = big.NewInt(int64(mantissa))
bn.Lsh(bn, 8*(exponent-3))
}
// Make it negative if the sign bit is set.
if isNegative {
bn = bn.Neg(bn)
}
return bn
}
const truediffone float64 = 26959535291011309493156476344723991336010898738574164086137773096960.0
const bits192 float64 = 6277101735386680763835789423207666416102355444464034512896.0
const bits128 float64 = 340282366920938463463374607431768211456.0
const bits64 float64 = 18446744073709551616.0
func target2float(target []byte) float64 {
var b64 float64 = float64(binary.LittleEndian.Uint64(target[24:32])) * bits192
b64 += (float64(binary.LittleEndian.Uint64(target[16:24])) * bits128)
b64 += (float64(binary.LittleEndian.Uint64(target[8:16])) * bits64)
b64 += (float64(binary.LittleEndian.Uint64(target[0:8])))
return b64
}
func Target2Diff(target []byte) float64 {
//var f64 float64 = truediffone
//max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
maxf, _ := new(big.Float).SetString(max.String())
f64, _ := maxf.Float64()
var fcut64 float64 = target2float(target)
//log.Println("diff", f64, fcut64, f64/fcut64)
return f64 / fcut64
}
func MoneroTarget2Diff(target []byte) float64 {
//var f64 float64 = truediffone
// max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
maxf, _ := new(big.Float).SetString(max.String())
f64, _ := maxf.Float64()
var fcut64 float64 = target2float(target)
//log.Println("diff", f64, fcut64, f64/fcut64)
return f64 / fcut64
}
func DiffToTarget(diff float64 /*, powLimit *big.Int*/) (*big.Int, error) {
if diff <= 0 {
return nil, fmt.Errorf("invalid pool difficulty %v (0 or less than "+
"zero passed)", diff)
}
// Round down in the case of a non-integer diff since we only support
// ints (unless diff < 1 since we don't allow 0)..
if diff <= 1 {
diff = 1
} else {
diff = math.Floor(diff)
}
divisor := new(big.Int).SetInt64(int64(diff))
//max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
target := new(big.Int)
//log.Println("target calc", hex.EncodeToString(max.Bytes()), hex.EncodeToString(divisor.Bytes()))
target.Div(max, divisor)
return target, nil
}
func MoneroDiffToTarget(diff float64 /*, powLimit *big.Int*/) (*big.Int, error) {
if diff <= 0 {
return nil, fmt.Errorf("invalid pool difficulty %v (0 or less than "+
"zero passed)", diff)
}
// Round down in the case of a non-integer diff since we only support
// ints (unless diff < 1 since we don't allow 0)..
if diff <= 1 {
diff = 1
} else {
diff = math.Floor(diff)
}
divisor := new(big.Int).SetInt64(int64(diff))
// max, _ := new(big.Int).SetString("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
max, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
target := new(big.Int)
//log.Println("target calc", hex.EncodeToString(max.Bytes()), hex.EncodeToString(divisor.Bytes()))
target.Div(max, divisor)
return target, nil
}
func Convert_big_endian(src []byte) []byte {
var dst []byte = make([]byte, 32)
for i := 0; i < 8; i++ {
dst[0+4*i] = src[3+4*i]
dst[1+4*i] = src[2+4*i]
dst[2+4*i] = src[1+4*i]
dst[3+4*i] = src[0+4*i]
}
return dst
}
func ReverseS(s string) (string, error) {
a := strings.Split(s, "")
sRev := ""
if len(a)%2 != 0 {
return "", fmt.Errorf("Incorrect input length")
}
for i := 0; i < len(a); i += 2 {
tmp := []string{a[i], a[i+1], sRev}
sRev = strings.Join(tmp, "")
}
return sRev, nil
}
func Reverse(src []byte) []byte {
dst := make([]byte, len(src))
for i := len(src); i > 0; i-- {
dst[len(src)-i] = src[i-1]
}
return dst
}
func Uint32ToByte(targetu uint32) []byte {
bytes := make([]byte, 4)
binary.LittleEndian.PutUint32(bytes, targetu)
return bytes
}
func Uint32ToByteBig(targetu uint32) []byte {
bytes := make([]byte, 4)
binary.BigEndian.PutUint32(bytes, targetu)
return bytes
}
func ExecShellCmd(s string) (string, error) {
cmd := exec.Command("/bin/bash", "-c", s)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
fmt.Println(err)
}
//fmt.Println(out.String(), s)
return out.String(), err
}