394 lines
9.8 KiB
Go
394 lines
9.8 KiB
Go
package proxy
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"net"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestMiner_Login_Good(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
before := miner.LastActivityAt()
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
time.Sleep(5 * time.Millisecond)
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 1,
|
|
"jsonrpc": "2.0",
|
|
"method": "login",
|
|
"params": map[string]interface{}{
|
|
"login": "wallet",
|
|
"pass": "x",
|
|
"agent": "xmrig",
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response["jsonrpc"] != "2.0" {
|
|
t.Fatalf("unexpected response: %#v", response)
|
|
}
|
|
if !miner.LastActivityAt().After(before) {
|
|
t.Fatalf("expected login to refresh last activity timestamp, got before=%s after=%s", before, miner.LastActivityAt())
|
|
}
|
|
|
|
result := response["result"].(map[string]interface{})
|
|
id, _ := result["id"].(string)
|
|
if result["status"] != "OK" || len(id) != 36 || id[8] != '-' || id[13] != '-' || id[18] != '-' || id[23] != '-' || id[14] != '4' || !strings.ContainsAny(string(id[19]), "89ab") {
|
|
t.Fatalf("unexpected login response: %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestMiner_Keepalived_Bad(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 2,
|
|
"jsonrpc": "2.0",
|
|
"method": "keepalived",
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result := response["result"].(map[string]interface{})
|
|
if result["status"] != "KEEPALIVED" {
|
|
t.Fatalf("unexpected keepalived response: %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestMiner_Submit_Ugly(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
miner.SetRPCID("session")
|
|
miner.SetState(MinerStateReady)
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 3,
|
|
"jsonrpc": "2.0",
|
|
"method": "submit",
|
|
"params": map[string]interface{}{
|
|
"id": "session",
|
|
"job_id": "job-1",
|
|
"nonce": "ABC123",
|
|
"result": "abc",
|
|
"algo": "cn/r",
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response["error"] == nil {
|
|
t.Fatalf("expected invalid nonce error, got %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestMiner_Login_Ugly(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.algoExtension = true
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 4,
|
|
"jsonrpc": "2.0",
|
|
"method": "login",
|
|
"params": map[string]interface{}{
|
|
"login": "wallet",
|
|
"pass": "x",
|
|
"agent": "xmrig",
|
|
"algo": []string{"cn/r"},
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result := response["result"].(map[string]interface{})
|
|
extensions, ok := result["extensions"].([]interface{})
|
|
if !ok || len(extensions) != 1 || extensions[0] != "algo" {
|
|
t.Fatalf("expected algo extension to be advertised, got %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestMiner_Login_NiceHashPatchedJob_Good(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.algoExtension = true
|
|
miner.SetCustomDiff(10000)
|
|
miner.events = NewEventBus()
|
|
miner.events.Subscribe(EventLogin, func(event Event) {
|
|
if event.Miner == nil {
|
|
return
|
|
}
|
|
event.Miner.SetNiceHashEnabled(true)
|
|
event.Miner.SetFixedByte(0x2a)
|
|
event.Miner.PrimeJob(Job{
|
|
Blob: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
JobID: "job-1",
|
|
Target: "b88d0600",
|
|
Algo: "cn/r",
|
|
Height: 42,
|
|
SeedHash: "seed-hash",
|
|
})
|
|
})
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 5,
|
|
"jsonrpc": "2.0",
|
|
"method": "login",
|
|
"params": map[string]interface{}{
|
|
"login": "wallet",
|
|
"pass": "x",
|
|
"agent": "xmrig",
|
|
"algo": []string{"cn/r"},
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
result := response["result"].(map[string]interface{})
|
|
job := result["job"].(map[string]interface{})
|
|
if blob, _ := job["blob"].(string); blob[78:80] != "2a" {
|
|
t.Fatalf("expected patched NiceHash blob, got %q", blob)
|
|
}
|
|
if target, _ := job["target"].(string); target != TargetForDifficulty(10000) {
|
|
t.Fatalf("expected custom diff target, got %q", target)
|
|
}
|
|
if height, _ := job["height"].(float64); height != 42 {
|
|
t.Fatalf("expected job height to be forwarded, got %#v", job)
|
|
}
|
|
if seedHash, _ := job["seed_hash"].(string); seedHash != "seed-hash" {
|
|
t.Fatalf("expected job seed_hash to be forwarded, got %#v", job)
|
|
}
|
|
}
|
|
|
|
func TestMiner_ForwardJob_Ugly(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.algoExtension = true
|
|
miner.extAlgo = true
|
|
miner.SetRPCID("session")
|
|
miner.SetCustomDiff(10000)
|
|
|
|
go miner.ForwardJob(Job{
|
|
Blob: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
JobID: "job-2",
|
|
Target: "b88d0600",
|
|
Algo: "rx/0",
|
|
Height: 99,
|
|
SeedHash: "seed",
|
|
}, "rx/0")
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
params := response["params"].(map[string]interface{})
|
|
if params["target"] != TargetForDifficulty(10000) {
|
|
t.Fatalf("expected custom diff target, got %#v", params)
|
|
}
|
|
if params["algo"] != "rx/0" || params["seed_hash"] != "seed" || params["height"] != float64(99) {
|
|
t.Fatalf("expected extended job fields to be forwarded, got %#v", params)
|
|
}
|
|
if miner.Diff() != 10000 {
|
|
t.Fatalf("expected miner diff to track the effective target, got %d", miner.Diff())
|
|
}
|
|
}
|
|
|
|
func TestMiner_Submit_Good(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.events = NewEventBus()
|
|
miner.algoExtension = true
|
|
miner.extAlgo = true
|
|
miner.SetRPCID("session")
|
|
miner.SetState(MinerStateReady)
|
|
|
|
submitSeen := make(chan Event, 1)
|
|
miner.events.Subscribe(EventSubmit, func(event Event) {
|
|
submitSeen <- event
|
|
miner.Success(event.RequestID, "OK")
|
|
})
|
|
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 6,
|
|
"jsonrpc": "2.0",
|
|
"method": "submit",
|
|
"params": map[string]interface{}{
|
|
"id": "session",
|
|
"job_id": "job-1",
|
|
"nonce": "deadbeef",
|
|
"result": "abc",
|
|
"algo": "cn/r",
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case event := <-submitSeen:
|
|
if event.JobID != "job-1" || event.Nonce != "deadbeef" || event.Algo != "cn/r" {
|
|
t.Fatalf("unexpected submit event: %+v", event)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("expected submit event to be dispatched")
|
|
}
|
|
|
|
clientConn.SetReadDeadline(time.Now().Add(time.Second))
|
|
line, err := bufio.NewReader(clientConn).ReadBytes('\n')
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
if err := json.Unmarshal(line, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result := response["result"].(map[string]interface{})
|
|
if result["status"] != "OK" {
|
|
t.Fatalf("unexpected submit response: %#v", response)
|
|
}
|
|
}
|
|
|
|
func TestMiner_Submit_AlgoExtension_Bad(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer clientConn.Close()
|
|
|
|
miner := NewMiner(serverConn, 3333, nil)
|
|
miner.events = NewEventBus()
|
|
miner.SetRPCID("session")
|
|
miner.SetState(MinerStateReady)
|
|
|
|
submitSeen := make(chan Event, 1)
|
|
miner.events.Subscribe(EventSubmit, func(event Event) {
|
|
submitSeen <- event
|
|
miner.Success(event.RequestID, "OK")
|
|
})
|
|
|
|
miner.Start()
|
|
defer miner.Close()
|
|
|
|
encoder := json.NewEncoder(clientConn)
|
|
if err := encoder.Encode(map[string]interface{}{
|
|
"id": 7,
|
|
"jsonrpc": "2.0",
|
|
"method": "submit",
|
|
"params": map[string]interface{}{
|
|
"id": "session",
|
|
"job_id": "job-1",
|
|
"nonce": "deadbeef",
|
|
"result": "abc",
|
|
"algo": "cn/r",
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case event := <-submitSeen:
|
|
if event.Algo != "" {
|
|
t.Fatalf("expected algo to be suppressed when extension is disabled, got %+v", event)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("expected submit event to be dispatched")
|
|
}
|
|
}
|