118 lines
2.6 KiB
Go
118 lines
2.6 KiB
Go
|
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
|
|||
|
}
|