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) miner.Start() defer miner.Close() 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) } 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.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", }) }) 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) } } func TestMiner_Submit_Good(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": 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) } }