m2pool-core/internal/server/monero/hash_randomx.go

118 lines
2.6 KiB
Go
Raw Normal View History

2025-09-03 08:00:42 +00:00
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
}