add aleo mining code(untested)

This commit is contained in:
lzx 2025-04-23 15:47:41 +08:00
parent c065a36142
commit 6a9ba51a73
7 changed files with 547 additions and 630 deletions

524
internal/gbt/aleo/aleo.go Normal file
View File

@ -0,0 +1,524 @@
package aleo
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
"log"
"net"
"os"
"os/signal"
"runtime"
"sync"
"sync/atomic"
"syscall"
"time"
)
const (
// 网络常量
TcpEndpoint = "127.0.0.1:3030"
RpcEndpoint = "http://127.0.0.1:4133"
// 消息类型
MsgHandshake uint16 = 1
MsgHandshakeResponse uint16 = 2
MsgPuzzleRequest uint16 = 9
MsgPuzzleResponse uint16 = 10
MsgUnconfirmedSolution uint16 = 11
// 协议版本
ProtocolVersion uint32 = 17
// 挖矿参数
MaxPuzzleInstances = 6 // 最大puzzle实例数
)
// Prover 挖矿节点结构
type Prover struct {
conn net.Conn
minerAddress []byte
// 最新状态
latestEpochHash []byte
latestBlockHeader *BlockHeader
epochHashMutex sync.RWMutex
headerMutex sync.RWMutex
// puzzle实例计数
puzzleInstances atomic.Int32
maxPuzzleInstances uint32
// 停止信号
shutdown chan struct{}
}
// BlockHeader 区块头结构
type BlockHeader struct {
Height uint32
PreviousHash [32]byte
Timestamp uint64
CoinbaseTarget uint64
ProofTarget uint64
TransactionsRoot [32]byte
StateRoot [32]byte
}
// Solution 挖矿解结构
type Solution struct {
ID [32]byte
EpochHash []byte
Nonce uint64
Address []byte
Proof []byte
}
func NewProver(minerAddress []byte) (*Prover, error) {
// 计算最大puzzle实例数
maxInstances := uint32(runtime.NumCPU() - 2)
if maxInstances < 1 {
maxInstances = 1
}
if maxInstances > MaxPuzzleInstances {
maxInstances = MaxPuzzleInstances
}
prover := &Prover{
minerAddress: minerAddress,
maxPuzzleInstances: maxInstances,
shutdown: make(chan struct{}),
}
// 连接节点
if err := prover.connect(); err != nil {
return nil, err
}
return prover, nil
}
func (p *Prover) connect() error {
conn, err := net.Dial("tcp", TcpEndpoint)
if err != nil {
return fmt.Errorf("连接失败: %v", err)
}
p.conn = conn
// 执行握手
if err := p.performHandshake(); err != nil {
conn.Close()
return fmt.Errorf("握手失败: %v", err)
}
return nil
}
// mining/message.go
func (p *Prover) sendMessage(msgType uint16, payload []byte) error {
header := make([]byte, 6)
binary.BigEndian.PutUint16(header[0:2], msgType)
binary.BigEndian.PutUint32(header[2:6], ProtocolVersion)
if _, err := p.conn.Write(header); err != nil {
return err
}
if payload != nil {
if _, err := p.conn.Write(payload); err != nil {
return err
}
}
return nil
}
func (p *Prover) receiveMessage() (uint16, []byte, error) {
header := make([]byte, 6)
if _, err := io.ReadFull(p.conn, header); err != nil {
return 0, nil, err
}
msgType := binary.BigEndian.Uint16(header[0:2])
// protocolVersion := binary.BigEndian.Uint32(header[2:6])
var payload []byte
if msgType == MsgPuzzleResponse {
// 读取epoch hash
epochHash := make([]byte, 32)
if _, err := io.ReadFull(p.conn, epochHash); err != nil {
return msgType, nil, err
}
// 读取block header
lenBuf := make([]byte, 4)
if _, err := io.ReadFull(p.conn, lenBuf); err != nil {
return msgType, nil, err
}
headerLen := binary.BigEndian.Uint32(lenBuf)
blockHeader := make([]byte, headerLen)
if _, err := io.ReadFull(p.conn, blockHeader); err != nil {
return msgType, nil, err
}
payload = append(epochHash, blockHeader...)
}
return msgType, payload, nil
}
func (p *Prover) getPuzzleTask() error {
// 发送请求
if err := p.sendMessage(MsgPuzzleRequest, nil); err != nil {
return err
}
// 接收响应
msgType, data, err := p.receiveMessage()
if err != nil {
return err
}
if msgType != MsgPuzzleResponse {
return fmt.Errorf("unexpected message type: %d", msgType)
}
// 解析数据
epochHash := data[0:32]
header, err := parseBlockHeader(data[32:])
if err != nil {
return err
}
// 更新状态
p.epochHashMutex.Lock()
p.latestEpochHash = epochHash
p.epochHashMutex.Unlock()
p.headerMutex.Lock()
p.latestBlockHeader = header
p.headerMutex.Unlock()
return nil
}
func (p *Prover) StartMining() error {
// 启动多个puzzle实例
for i := uint32(0); i < p.maxPuzzleInstances; i++ {
go p.puzzleLoop()
}
// 定期获取新任务
go p.taskLoop()
return nil
}
func (p *Prover) puzzleLoop() {
p.puzzleInstances.Add(1)
defer p.puzzleInstances.Add(-1)
for {
select {
case <-p.shutdown:
return
default:
// 获取当前状态
p.epochHashMutex.RLock()
epochHash := p.latestEpochHash
p.epochHashMutex.RUnlock()
p.headerMutex.RLock()
header := p.latestBlockHeader
p.headerMutex.RUnlock()
if epochHash != nil && header != nil {
// 尝试找到解
solution, err := p.findSolution(epochHash, header.ProofTarget)
if err == nil {
// 提交解
if err := p.submitSolution(solution); err != nil {
log.Printf("提交解失败: %v", err)
}
}
}
time.Sleep(100 * time.Millisecond)
}
}
}
func (p *Prover) taskLoop() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-p.shutdown:
return
case <-ticker.C:
if err := p.getPuzzleTask(); err != nil {
log.Printf("获取任务失败: %v", err)
}
}
}
}
func (p *Prover) submitSolution(solution *Solution) error {
// 序列化solution
var buf bytes.Buffer
buf.Write(solution.ID[:])
buf.Write(solution.EpochHash)
nonceBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(nonceBytes, solution.Nonce)
buf.Write(nonceBytes)
buf.Write(solution.Address)
buf.Write(solution.Proof)
// 发送消息
return p.sendMessage(MsgUnconfirmedSolution, buf.Bytes())
}
func main() {
// 创建矿工地址
minerAddress := []byte("your_miner_address_here")
// 创建Prover
prover, err := NewProver(minerAddress)
if err != nil {
log.Fatalf("创建Prover失败: %v", err)
}
// 启动挖矿
if err := prover.StartMining(); err != nil {
log.Fatalf("启动挖矿失败: %v", err)
}
// 等待中断信号
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
// 优雅关闭
close(prover.shutdown)
}
func (p *Prover) findSolution(epochHash []byte, proofTarget uint64) (*Solution, error) {
var nonce uint64 = 0
maxNonce := ^uint64(0) // 最大uint64值
// 将proofTarget转换为字节数组用于比较
targetBytes := make([]byte, 32)
targetBytes[0] = byte(proofTarget)
for nonce < maxNonce {
// 计算proof
proof, err := p.computeProof(epochHash, p.minerAddress, nonce)
if err != nil {
return nil, fmt.Errorf("计算proof失败: %v", err)
}
// 验证proof是否满足难度要求
if p.verifyProof(proof, targetBytes) {
// 构造解
solution := &Solution{
EpochHash: epochHash,
Nonce: nonce,
Address: p.minerAddress,
Proof: proof,
}
// 计算解的ID
id, err := p.computeSolutionID(solution)
if err != nil {
return nil, fmt.Errorf("计算解ID失败: %v", err)
}
copy(solution.ID[:], id)
log.Printf("找到有效解 - Nonce: %d, ID: %x", nonce, id)
return solution, nil
}
// 每处理1000个nonce检查一次是否需要退出
if nonce%1000 == 0 {
select {
case <-p.shutdown:
return nil, fmt.Errorf("挖矿已停止")
default:
}
}
nonce++
}
return nil, fmt.Errorf("未找到有效解")
}
// computeProof 计算工作量证明
func (p *Prover) computeProof(epochHash []byte, address []byte, nonce uint64) ([]byte, error) {
hasher := sha256.New()
// 写入epoch hash
if _, err := hasher.Write(epochHash); err != nil {
return nil, fmt.Errorf("写入epoch hash失败: %v", err)
}
// 写入地址
if _, err := hasher.Write(address); err != nil {
return nil, fmt.Errorf("写入地址失败: %v", err)
}
// 写入nonce (小端字节序)
nonceBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(nonceBytes, nonce)
if _, err := hasher.Write(nonceBytes); err != nil {
return nil, fmt.Errorf("写入nonce失败: %v", err)
}
return hasher.Sum(nil), nil
}
// verifyProof 验证工作量证明是否满足难度要求
func (p *Prover) verifyProof(proof []byte, target []byte) bool {
// 比较proof和target
// proof必须小于target才是有效的
for i := 0; i < len(proof) && i < len(target); i++ {
if proof[i] < target[i] {
return true
}
if proof[i] > target[i] {
return false
}
}
return false
}
// computeSolutionID 计算解的唯一标识符
func (p *Prover) computeSolutionID(solution *Solution) ([]byte, error) {
hasher := sha256.New()
// 写入所有字段
if _, err := hasher.Write(solution.EpochHash); err != nil {
return nil, fmt.Errorf("写入epoch hash失败: %v", err)
}
if _, err := hasher.Write(solution.Address); err != nil {
return nil, fmt.Errorf("写入地址失败: %v", err)
}
nonceBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(nonceBytes, solution.Nonce)
if _, err := hasher.Write(nonceBytes); err != nil {
return nil, fmt.Errorf("写入nonce失败: %v", err)
}
if _, err := hasher.Write(solution.Proof); err != nil {
return nil, fmt.Errorf("写入proof失败: %v", err)
}
return hasher.Sum(nil), nil
}
type PuzzleInstances struct {
count uint32
}
// Sub 原子减少实例计数
func (p *PuzzleInstances) Sub(delta uint32) {
atomic.AddUint32(&p.count, ^(delta - 1))
}
// Add 原子增加实例计数
func (p *PuzzleInstances) Add(delta uint32) {
atomic.AddUint32(&p.count, delta)
}
// Get 获取当前实例数
func (p *PuzzleInstances) Get() uint32 {
return atomic.LoadUint32(&p.count)
}
func parseBlockHeader(data []byte) (*BlockHeader, error) {
if len(data) < 96 { // 最小区块头长度
return nil, fmt.Errorf("区块头数据太短")
}
reader := bytes.NewReader(data)
header := &BlockHeader{}
// 读取高度 (4字节)
if err := binary.Read(reader, binary.LittleEndian, &header.Height); err != nil {
return nil, fmt.Errorf("读取区块高度失败: %v", err)
}
// 读取前一个区块哈希 (32字节)
if _, err := io.ReadFull(reader, header.PreviousHash[:]); err != nil {
return nil, fmt.Errorf("读取前一个区块哈希失败: %v", err)
}
// 读取时间戳 (8字节)
if err := binary.Read(reader, binary.LittleEndian, &header.Timestamp); err != nil {
return nil, fmt.Errorf("读取时间戳失败: %v", err)
}
// 读取coinbase目标值 (8字节)
if err := binary.Read(reader, binary.LittleEndian, &header.CoinbaseTarget); err != nil {
return nil, fmt.Errorf("读取coinbase目标值失败: %v", err)
}
// 读取proof目标值 (8字节)
if err := binary.Read(reader, binary.LittleEndian, &header.ProofTarget); err != nil {
return nil, fmt.Errorf("读取proof目标值失败: %v", err)
}
// 读取交易根 (32字节)
if _, err := io.ReadFull(reader, header.TransactionsRoot[:]); err != nil {
return nil, fmt.Errorf("读取交易根失败: %v", err)
}
// 读取状态根 (32字节)
if _, err := io.ReadFull(reader, header.StateRoot[:]); err != nil {
return nil, fmt.Errorf("读取状态根失败: %v", err)
}
return header, nil
}
func (p *Prover) performHandshake() error {
// 发送握手消息
if err := p.sendMessage(MsgHandshake, nil); err != nil {
return fmt.Errorf("发送握手消息失败: %v", err)
}
// 设置读取超时
if err := p.conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
return fmt.Errorf("设置读取超时失败: %v", err)
}
defer p.conn.SetReadDeadline(time.Time{}) // 清除超时
// 接收握手响应
msgType, payload, err := p.receiveMessage()
if err != nil {
return fmt.Errorf("接收握手响应失败: %v", err)
}
// 验证消息类型
if msgType != MsgHandshakeResponse {
return fmt.Errorf("收到意外的消息类型: %d, 期望类型: %d", msgType, MsgHandshakeResponse)
}
// 验证协议版本
if len(payload) >= 4 {
version := binary.BigEndian.Uint32(payload[0:4])
if version != ProtocolVersion {
return fmt.Errorf("协议版本不匹配: 收到 %d, 期望 %d", version, ProtocolVersion)
}
}
log.Printf("握手成功 - 协议版本: %d", ProtocolVersion)
return nil
}

View File

@ -9,7 +9,6 @@ import (
"pool/internal/utility"
"github.com/btcsuite/btcd/rpcclient"
kaspad "github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
"github.com/redis/go-redis/v9"
"github.com/zeromq/goczmq"
"go.uber.org/zap"
@ -58,12 +57,12 @@ type GbtContext struct {
PushCh *goczmq.Sock
Started bool
Config GbtConfig
Client *rpcclient.Client
ClientAlph *net.Conn
ClientAlphApi *http.HttpClient
ClientEnx *kaspad.RPCClient
Started bool
Config GbtConfig
Client *rpcclient.Client
ClientAlph *net.Conn
ClientAlphApi *http.HttpClient
// ClientEnx *kaspad.RPCClient
ExitNotifyChan chan bool
ExitGbtChan chan bool
ExitBlockChan chan bool

View File

@ -1,247 +0,0 @@
package enx
import (
"encoding/hex"
"fmt"
"pool/internal/db"
"pool/internal/gbt/coin"
"pool/internal/gbt/enx/templatemanager"
"pool/internal/msg"
"sync"
"sync/atomic"
"time"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
"github.com/kaspanet/kaspad/util/difficulty"
"go.uber.org/zap"
)
const GBT_ENX_VERSION string = "enx v1.15.2"
type EnxAddrConfig struct {
Addr string `json:"addr"`
}
type EnxConfig struct {
Enx EnxAddrConfig `json:"enx"`
}
type GbtEnxContext struct {
Config EnxConfig
GbtCtx *coin.GbtContext
last_time time.Time
last_gbt EnxGbtTemplate
Submits float64
addressIndex int
new_block_chan chan int
new_block_index int
last_height uint32
}
var logg *zap.Logger
var GbtEnxCtx GbtEnxContext
// Kaspa GetBlockTemplate 结构体
type EnxGbtTemplate struct {
Block struct {
Header struct {
Version int `json:"version"`
ParentsByLevel [][]string `json:"parents_by_level"`
HashMerkleRoot string `json:"hash_merkle_root"`
AcceptedIdMerkleRoot string `json:"accepted_id_merkle_root"`
UtxoCommitment string `json:"utxo_commitment"`
Timestamp uint64 `json:"timestamp"`
Bits uint32 `json:"bits"`
Nonce uint64 `json:"nonce"`
DaaScore uint64 `json:"daa_score"`
BlueWork [3]uint64 `json:"blue_work"` // 可改为 big.Int
BlueScore uint64 `json:"blue_score"`
PruningPoint string `json:"pruning_point"`
} `json:"header"`
Transactions []struct {
Version int `json:"version"`
LockTime uint64 `json:"lock_time"`
SubnetworkId string `json:"subnetwork_id"`
Gas uint64 `json:"gas"`
PayLoad string `json:"payload"`
Mass uint64 `json:"mass"`
Inputs []struct{} `json:"inputs"`
Outputs []struct{} `json:"outputs"`
VerboseData interface{} `json:"verbose_data"`
} `json:"transactions"`
} `json:"block"`
IsSync bool `json:"is_sync"`
}
type BlockCheckData struct {
Height int
Nonce string
User string
Miner string
MinerId string
Hash string
SubIdx int
}
type PushBlkNewMsg struct {
Coin string `json:"coin"`
Height int `json:"height"`
Nonce string `json:"nonce"`
}
type EnxJob struct {
JobID uint32
Job *externalapi.DomainBlock
State *pow.State
}
type EnxContext struct {
GbtCtx *coin.GbtContext
SLock sync.Mutex
JobID uint32
Jobs []EnxJob
LastHeight uint64
Submits float64
}
var enxCtx EnxContext
func update_block_confirm(gbt *GbtEnxContext) {}
var hashesTried uint64
func get_blocktemplate(gbt *GbtEnxContext, mineWhenNotSynced bool) (*externalapi.DomainBlock, *pow.State) {
tryCount := 0
const sleepTime = 500 * time.Millisecond
const sleepTimeWhenNotSynced = 5 * time.Second
for {
tryCount++
shouldLog := (tryCount-1)%10 == 0
template, state, isSynced := templatemanager.Get()
if template == nil {
if shouldLog {
logg.Info("Waiting for the initial template")
}
time.Sleep(sleepTime)
continue
}
if !isSynced && !mineWhenNotSynced {
if shouldLog {
logg.Warn("Kaspad is not synced. Skipping current block template")
}
time.Sleep(sleepTimeWhenNotSynced)
continue
}
return template, state
}
}
func get_gbt_msg(gbt *GbtEnxContext) []byte {
// 这里从节点获取区块模版(block template)
dagInfoMsg, err := gbt.GbtCtx.ClientEnx.GetBlockDAGInfo()
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockDAGInfo ", err.Error()))
return nil
}
height := dagInfoMsg.VirtualDAAScore
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockCount ", err.Error()))
return nil
}
height = height + 1
block, state := getBlockForMining(mineWhenNotSynced)
//state.Nonce = nonce
state.Nonce = 0
atomic.AddUint64(&hashesTried, 1)
var job msg.EnxStratumJob
enxCtx.SLock.Lock()
job.Job_id = 0
job.Gbt_id = enxCtx.JobID
enxCtx.SLock.Unlock()
job.CurTime = uint64(state.Timestamp)
job.Target = hex.EncodeToString(state.Target.Bytes())
job.Bits = difficulty.BigToCompact(&(state.Target))
job.Nonce = ""
job.Extranonce1 = ""
job.Extranonce2_size = 6
job.Extranonce2 = ""
job.Data = hex.EncodeToString(state.GetPrePowHash())
job.PrevBlockHash = fmt.Sprint("%s", block.Header.DirectParents())
job.Height = block.Header.BlueScore()
return []byte{}
}
func getBlockForMining(mineWhenNotSynced bool) (*externalapi.DomainBlock, *pow.State) {
tryCount := 0
const sleepTime = 500 * time.Millisecond
const sleepTimeWhenNotSynced = 5 * time.Second
for {
tryCount++
shouldLog := (tryCount-1)%10 == 0
template, state, isSynced := templatemanager.Get()
if template == nil {
if shouldLog {
logg.Info("Waiting for the initial template")
}
time.Sleep(sleepTime)
continue
}
if !isSynced && !mineWhenNotSynced {
if shouldLog {
logg.Warn("Kaspad is not synced. Skipping current block template")
}
time.Sleep(sleepTimeWhenNotSynced)
continue
}
return template, state
}
}
func gbt_notify_running(gbt *GbtEnxContext) {}
func gbt_running(gbt *GbtEnxContext) {}
func enxInit(config *EnxConfig) {}
func Init(GbtCtx *coin.GbtContext, DbCtx *db.DbContext) {}
func Start() {
go gbt_running(&GbtEnxCtx)
go gbt_notify_running(&GbtEnxCtx)
go submit_block_running(&GbtEnxCtx)
}
func Stop() {
defer close(GbtEnxCtx.new_block_chan)
}
func new_block_into_db(block *GbtEnxContext, user string, miner string, minerid string, height int64, nonce string, hash string, subidx int64) bool {
return true
}
func submit_block_running(block *GbtEnxContext) {}
func new_job_from_gbt(gbt *GbtEnxContext, rxmsg *msg.GbtMsg) []byte { return []byte{} }

View File

@ -1,49 +0,0 @@
package templatemanager
import (
"sync"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
)
var currentTemplate *externalapi.DomainBlock
var currentState *pow.State
var prevState *pow.State
var isSynced bool
var lock = &sync.Mutex{}
// Get returns the template to work on
func Get() (*externalapi.DomainBlock, *pow.State, bool) {
lock.Lock()
defer lock.Unlock()
// Shallow copy the block so when the user replaces the header it won't affect the template here.
if currentTemplate == nil {
return nil, nil, false
}
if prevState != nil {
if currentState.Target.Cmp(&(prevState.Target)) == 0 {
return nil, nil, false
}
}
block := *currentTemplate
state := *currentState
prevState = currentState
currentTemplate = nil
return &block, &state, isSynced
}
// Set sets the current template to work on
func Set(template *appmessage.GetBlockTemplateResponseMessage) error {
block, err := appmessage.RPCBlockToDomainBlock(template.Block)
if err != nil {
return err
}
lock.Lock()
defer lock.Unlock()
currentTemplate = block
currentState = pow.NewState(block.Header.ToMutable())
isSynced = template.IsSynced
return nil
}

View File

@ -24,7 +24,6 @@ import (
"pool/internal/gbt/alph/http"
"pool/internal/gbt/coin"
"pool/internal/gbt/dgb"
"pool/internal/gbt/enx"
"pool/internal/gbt/grs"
"pool/internal/gbt/mona"
"pool/internal/gbt/nexa"
@ -37,7 +36,6 @@ import (
"time"
"github.com/btcsuite/btcd/rpcclient"
kaspad "github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
@ -74,23 +72,23 @@ func InitClient(gbt *coin.GbtContext) error {
gbt.ClientAlphApi = apiClient
// blockCount := apiClient.GetBlockCount()
return nil
case "enx":
host := gbt.Config.Rpc.Host
port := gbt.Config.Rpc.Port
client, err := kaspad.NewRPCClient(host + ":" + port)
if err != nil {
logg.Info("[gbt]", zap.String("rpcclient new ", err.Error()))
return err
}
gbt.ClientEnx = client
dagInfoMsg, err := client.GetBlockDAGInfo()
if err != nil {
logg.Info("[gbt]", zap.String("GetBlockDAGInfo ", err.Error()))
return err
}
blockCount := dagInfoMsg.VirtualDAAScore
logg.Info("[gbt]", zap.Int64("Block count ", int64(blockCount)))
return nil
// case "enx":
// host := gbt.Config.Rpc.Host
// port := gbt.Config.Rpc.Port
// client, err := kaspad.NewRPCClient(host + ":" + port)
// if err != nil {
// logg.Info("[gbt]", zap.String("rpcclient new ", err.Error()))
// return err
// }
// gbt.ClientEnx = client
// dagInfoMsg, err := client.GetBlockDAGInfo()
// if err != nil {
// logg.Info("[gbt]", zap.String("GetBlockDAGInfo ", err.Error()))
// return err
// }
// blockCount := dagInfoMsg.VirtualDAAScore
// logg.Info("[gbt]", zap.Int64("Block count ", int64(blockCount)))
// return nil
default:
var config rpcclient.ConnConfig
if gbt.Config.Rpc.Type == "testnet" {
@ -183,7 +181,6 @@ var coinobjs = []coinobj{
{Coin: "dgbq", Init: dgb.Init, Start: dgb.Start, Stop: dgb.Stop},
{Coin: "dgbs", Init: dgb.Init, Start: dgb.Start, Stop: dgb.Stop},
{Coin: "alph", Init: alph.Init, Start: alph.Start, Stop: alph.Stop},
{Coin: "enx", Init: enx.Init, Start: enx.Start, Stop: enx.Stop},
}
func register_signal(dbctx *db.DbContext) {

View File

@ -1,272 +0,0 @@
package enx
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"pool/internal/msg"
"pool/internal/server/coin"
"pool/internal/stratum"
"pool/internal/utility"
"github.com/btcsuite/btcd/wire"
"go.uber.org/zap"
)
const SERVER_ENX_VERSION string = "enx v1.15.2"
type ServerEnxContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
Job msg.StratumJob
}
var logg *zap.Logger
var ServerEnxCtx ServerEnxContext
// headerHash:本身的pow计算结果收到后根据nonce和timestamp重新计算该值确保该值正确
// headerHash本身可以通过计算得出难度
func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, headerHash 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.StratumJob)
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
}
if miner.LastNonce != nonce {
miner.LastNonce = nonce
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + fmt.Sprintf("%d", job.Height) + " target " + job.Target + " extra1 " + job.Extranonce1 + " size " + fmt.Sprintf("%d", job.Extranonce2_size) + " " + miner.User + "." + miner.Miner)
}
}
vb := make([]byte, 4)
binary.LittleEndian.PutUint32(vb, uint32(job.Version))
vBuffer := bytes.NewBuffer(vb)
binary.Read(vBuffer, binary.BigEndian, &(miner.Version))
job.Nonce = nonce
job.Extranonce2 = headerHash
var calc_hash []byte
var header wire.BlockHeader
}
}
// 构造提交至节点的区块
func Produce_block_submit(miner *coin.MinerObj, header wire.BlockHeader, job *msg.StratumJob, PowHash string, SubIdx int64) {
}
// server-->miner
func enx_parse_miner_notify(miner *coin.MinerObj, msg msg.StratumJob) int {}
func Init(server *coin.ServerContext) {
ServerEnxCtx.ServerCtx = server
logg = server.Logg
logg.Info("[server]", zap.String("server_mona_version", SERVER_ENX_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {}
func Handle_subscribe_enx(miner *coin.MinerObj, id float64, extranonce1 string) {
stratum.Handle_subscribe(miner, id, extranonce1)
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
Handle_subscribe_enx(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) {
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 set_difficulty(miner *coin.MinerObj) {}
func SetDifficulty(miner *coin.MinerObj) {
set_difficulty(miner)
}
/**
id: int, method: string, params:[string(jobid), string(headerHash, 32 byte serialized header, 8 bytes timestamp)]
*/
func EnxNotify(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
//Set_difficulty(miner)
miner.Server.CoinCtx.SetDifficulty(miner)
} else {
miner.DifficultyNext = -1
}
}
miner.TxLock.Lock()
//log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId)
var params [9]interface{}
var tlist []string = make([]string, 0)
idb := make([]byte, 4)
binary.BigEndian.PutUint32(idb, miner.JobId)
miner.Job.Job_id = hex.EncodeToString(idb)
params[0] = miner.Job.Job_id
if len(miner.Job.PrevblockS) > 0 {
params[1] = miner.Job.PrevblockBig
} else {
p_big := utility.Convert_big_endian(miner.Job.Prevblock.CloneBytes())
params[1] = hex.EncodeToString(p_big)
}
params[2] = miner.Job.Coinbase1
params[3] = miner.Job.Coinbase2
params[4] = tlist
miner.CurHeight = miner.Job.Height
if miner.Job.Transactions != nil {
if len(*miner.Job.Transactions) > 0 {
params[4] = miner.Job.Transactions
/*miner.Server.Logg.Error("[notify]", zap.String("coinbase1", miner.Job.Coinbase1), zap.String("coinbase2", miner.Job.Coinbase2), zap.Uint32("height", miner.Job.Height))
for i := 0; i < len(*miner.Job.Transactions); i++ {
miner.Server.Logg.Error("[notify]", zap.String("trans", (*miner.Job.Transactions)[i]))
}*/
}
}
vb := make([]byte, 4)
binary.LittleEndian.PutUint32(vb, uint32(miner.Job.Version))
params[5] = hex.EncodeToString(vb)
bb := make([]byte, 4)
binary.LittleEndian.PutUint32(bb, miner.Job.Bits)
params[6] = hex.EncodeToString(bb)
t := miner.Job.Timestamp.Unix()
if t > int64(^uint32(0)) {
tb := make([]byte, 8)
binary.LittleEndian.PutUint64(tb, uint64(t))
params[7] = hex.EncodeToString(tb)
} else {
tb := make([]byte, 4)
binary.LittleEndian.PutUint32(tb, uint32(t))
params[7] = hex.EncodeToString(tb)
}
if miner.Reconnect {
params[8] = true
miner.Reconnect = false
} else {
params[8] = miner.Job.IsClean
}
miner.Job.JobDifficulty = miner.Difficulty
//miner.Jobs[miner.Job.Job_id] = miner.Job
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.Job)
/*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 msg stratum.Notify_msg
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) {
EnxNotify(miner)
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {}
func IsMhsLow(miner *coin.MinerObj) bool {
return miner.Mhs5M < 1
}
func GetBlockInterval() int {
return 30 // 30秒没获取到任务发送退出信号
}

View File

@ -1,35 +0,0 @@
package enx
/*
#cgo CFLAGS: -I../include/heavyHash
#cgo LDFLAGS: -L../lib/heavyHash -lheavyhash
#include "heavyhash.h"
*/
import "C"
import (
"fmt"
"strings"
"unsafe"
)
func EnxHash(data []byte) string {
// 初始化 CSHA3_256 结构体
var sha3 C.CSHA3_256
// 调用 C 语言的 Write 方法
C.CSHA3_256_Write(&sha3, (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 调用 C 语言的 Finalize 方法来生成哈希
var hash [C.OUTPUT_SIZE]C.uchar
C.CSHA3_256_Finalize(&sha3, &hash[0])
// 使用 strings.Builder 来拼接字符串
var builder strings.Builder
for i := 0; i < C.OUTPUT_SIZE; i++ {
// 以十六进制方式格式化每个字节
builder.WriteString(fmt.Sprintf("%02x", hash[i]))
}
// 返回最终的哈希值
return builder.String()
}