Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
|
6a9ba51a73 | |
|
c065a36142 | |
|
4d4596a641 |
|
@ -1,10 +1,15 @@
|
||||||
|
# start
|
||||||
|
```
|
||||||
cd cmd/server
|
cd cmd/server
|
||||||
go build -o server
|
go build -o server
|
||||||
cd cmd/gbt
|
cd cmd/gbt
|
||||||
go build -o gbt
|
go build -o gbt
|
||||||
|
```
|
||||||
|
# config
|
||||||
|
```
|
||||||
Add the following config files to the same directory as the compiled files
|
Add the following config files to the same directory as the compiled files
|
||||||
|
```
|
||||||
|
```
|
||||||
gbt.conf like this:
|
gbt.conf like this:
|
||||||
{
|
{
|
||||||
"coin": "test",
|
"coin": "test",
|
||||||
|
@ -55,7 +60,8 @@ gbt.conf like this:
|
||||||
"compress": true
|
"compress": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
server.conf like this:
|
server.conf like this:
|
||||||
{
|
{
|
||||||
"coin": "test",
|
"coin": "test",
|
||||||
|
@ -101,7 +107,8 @@ server.conf like this:
|
||||||
"compress": true
|
"compress": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
db.conf like this:
|
db.conf like this:
|
||||||
{
|
{
|
||||||
"db": {
|
"db": {
|
||||||
|
@ -136,4 +143,5 @@ db.conf like this:
|
||||||
"maxage": 31,
|
"maxage": 31,
|
||||||
"compress": true
|
"compress": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
|
@ -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
|
||||||
|
}
|
|
@ -217,17 +217,17 @@ func update_block_confirm(gbt *GbtAlphContext) {
|
||||||
blockInfo := gbt.GbtCtx.ClientAlphApi.GetBlcokInfo(blockHash)
|
blockInfo := gbt.GbtCtx.ClientAlphApi.GetBlcokInfo(blockHash)
|
||||||
var total_amount float64 = 0
|
var total_amount float64 = 0
|
||||||
fromGroup, toGroup, nonce, height := blockInfo.ChainFrom, blockInfo.ChainTo, blockInfo.Nonce, blockInfo.Height
|
fromGroup, toGroup, nonce, height := blockInfo.ChainFrom, blockInfo.ChainTo, blockInfo.Nonce, blockInfo.Height
|
||||||
for _, tx := range blockInfo.Transactions {
|
// for _, tx := range blockInfo.Transactions {
|
||||||
for _, out := range tx.Unsigned.FixedOutputs {
|
for _, out := range blockInfo.Transactions[len(blockInfo.Transactions)-1].Unsigned.FixedOutputs {
|
||||||
if out.Address == addr[fromGroup] && nonce == blockInfo.Nonce {
|
if out.Address == addr[fromGroup] && nonce == blockInfo.Nonce {
|
||||||
amount := out.AttoAlphAmount
|
amount := out.AttoAlphAmount
|
||||||
total_amount += savePoint4(stringToFloat64(amount) / math.Pow(10, 18))
|
total_amount += savePoint4(stringToFloat64(amount) / math.Pow(10, 18))
|
||||||
fmt.Println(fromGroup, "->", toGroup, "(", height, "):", total_amount, ",", nonce, " ", blockHash, " ", out.Address, " 报块成功")
|
fmt.Println(fromGroup, "->", toGroup, "(", height, "):", total_amount, ",", nonce, " ", blockHash, " ", out.Address, " 报块成功")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(fromGroup, "->", toGroup, "(", height, "):", total_amount, ",", nonce, "不是报块,实际报块地址为:", out.Address)
|
fmt.Println(fromGroup, "->", toGroup, "(", height, "):", total_amount, ",", nonce, "不是报块,实际报块地址为:", out.Address)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// }
|
||||||
block_height := height // 用区块链返回的height,防止某个块成为下一个高度的叔块,导致高度变化
|
block_height := height // 用区块链返回的height,防止某个块成为下一个高度的叔块,导致高度变化
|
||||||
dbif.AlphNotifyPoolBlkStatsSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx), total_amount, 0)
|
dbif.AlphNotifyPoolBlkStatsSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx), total_amount, 0)
|
||||||
dbif.NotifyAlphBlkDetailSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx))
|
dbif.NotifyAlphBlkDetailSuccess(gbt.GbtCtx, uint32(fromGroup), uint32(toGroup), block_height, "", block.Nonce, int64(block.SubIdx))
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"pool/internal/utility"
|
"pool/internal/utility"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
kaspad "github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"github.com/zeromq/goczmq"
|
"github.com/zeromq/goczmq"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -58,12 +57,12 @@ type GbtContext struct {
|
||||||
|
|
||||||
PushCh *goczmq.Sock
|
PushCh *goczmq.Sock
|
||||||
|
|
||||||
Started bool
|
Started bool
|
||||||
Config GbtConfig
|
Config GbtConfig
|
||||||
Client *rpcclient.Client
|
Client *rpcclient.Client
|
||||||
ClientAlph *net.Conn
|
ClientAlph *net.Conn
|
||||||
ClientAlphApi *http.HttpClient
|
ClientAlphApi *http.HttpClient
|
||||||
ClientEnx *kaspad.RPCClient
|
// ClientEnx *kaspad.RPCClient
|
||||||
ExitNotifyChan chan bool
|
ExitNotifyChan chan bool
|
||||||
ExitGbtChan chan bool
|
ExitGbtChan chan bool
|
||||||
ExitBlockChan chan bool
|
ExitBlockChan chan bool
|
||||||
|
|
|
@ -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{} }
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"pool/internal/gbt/alph/http"
|
"pool/internal/gbt/alph/http"
|
||||||
"pool/internal/gbt/coin"
|
"pool/internal/gbt/coin"
|
||||||
"pool/internal/gbt/dgb"
|
"pool/internal/gbt/dgb"
|
||||||
"pool/internal/gbt/enx"
|
|
||||||
"pool/internal/gbt/grs"
|
"pool/internal/gbt/grs"
|
||||||
"pool/internal/gbt/mona"
|
"pool/internal/gbt/mona"
|
||||||
"pool/internal/gbt/nexa"
|
"pool/internal/gbt/nexa"
|
||||||
|
@ -37,7 +36,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
"github.com/btcsuite/btcd/rpcclient"
|
||||||
kaspad "github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -74,23 +72,23 @@ func InitClient(gbt *coin.GbtContext) error {
|
||||||
gbt.ClientAlphApi = apiClient
|
gbt.ClientAlphApi = apiClient
|
||||||
// blockCount := apiClient.GetBlockCount()
|
// blockCount := apiClient.GetBlockCount()
|
||||||
return nil
|
return nil
|
||||||
case "enx":
|
// case "enx":
|
||||||
host := gbt.Config.Rpc.Host
|
// host := gbt.Config.Rpc.Host
|
||||||
port := gbt.Config.Rpc.Port
|
// port := gbt.Config.Rpc.Port
|
||||||
client, err := kaspad.NewRPCClient(host + ":" + port)
|
// client, err := kaspad.NewRPCClient(host + ":" + port)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
logg.Info("[gbt]", zap.String("rpcclient new ", err.Error()))
|
// logg.Info("[gbt]", zap.String("rpcclient new ", err.Error()))
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
gbt.ClientEnx = client
|
// gbt.ClientEnx = client
|
||||||
dagInfoMsg, err := client.GetBlockDAGInfo()
|
// dagInfoMsg, err := client.GetBlockDAGInfo()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
logg.Info("[gbt]", zap.String("GetBlockDAGInfo ", err.Error()))
|
// logg.Info("[gbt]", zap.String("GetBlockDAGInfo ", err.Error()))
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
blockCount := dagInfoMsg.VirtualDAAScore
|
// blockCount := dagInfoMsg.VirtualDAAScore
|
||||||
logg.Info("[gbt]", zap.Int64("Block count ", int64(blockCount)))
|
// logg.Info("[gbt]", zap.Int64("Block count ", int64(blockCount)))
|
||||||
return nil
|
// return nil
|
||||||
default:
|
default:
|
||||||
var config rpcclient.ConnConfig
|
var config rpcclient.ConnConfig
|
||||||
if gbt.Config.Rpc.Type == "testnet" {
|
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: "dgbq", Init: dgb.Init, Start: dgb.Start, Stop: dgb.Stop},
|
||||||
{Coin: "dgbs", 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: "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) {
|
func register_signal(dbctx *db.DbContext) {
|
||||||
|
|
|
@ -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秒没获取到任务发送退出信号
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
Loading…
Reference in New Issue