using System; using System.Net.Sockets; using System.Threading; using System.IO; using sharp.jsonrpc.net; using Newtonsoft.Json.Linq; using sharp.cryptonote; namespace SharpMining { public class StratumConnection : JSONClient { delegate void threadsyncdelegate(); StratumListener listener; Thread thread; bool shouldExit; public Guid UID { get; } = Guid.NewGuid(); public CryptoNoteAddress Wallet { get; set; } public string WorkerID { get; set; } public int FixedDiff { get; set; } public string Agent { get; set; } public MiningPool Pool { get; private set; } public MiningJob CurrentJob { get; private set; } public MiningJob LastJob { get; private set; } public StratumConnection(StratumListener listener,Socket socket) :base(socket) { this.listener = listener; this.thread = new Thread(()=>run()); this.thread.Start(); } public new void Close(){ Monitor.Enter(this); if (shouldExit){ return; } shouldExit = true; Monitor.Wait(this); base.Close(); Monitor.Exit(this); } private void run(){ while (!ShouldExit){ try { JToken token = readJSON(); if (token["method"] != null) { methodCalled(token["method"].ToObject(), token["id"].ToObject(), token["params"]); } } catch (IOException ioe){ Close(); } catch (Exception e){ Console.WriteLine("StratumConnection: [{0}] Exception: {1}",UID.ToString(),e.ToString()); } } if (Pool != null){ Pool.WorkManager.OnNewBlockAvailable -= WorkManager_OnNewBlockAvailable; } Monitor.Enter(this); Monitor.PulseAll(this); Monitor.Exit(this); } private bool ShouldExit { get { Monitor.Enter(this); bool se = this.shouldExit; Monitor.Exit(this); return se; } } private new void writeJSON(JToken token){ Monitor.Enter(this); base.writeJSON(token); Monitor.Exit(this); } private void methodCalled(string method,UInt64 id,JToken args){ switch (method){ case "login": rpcLogin(id,args); break; case "submit": rpcSubmit(id, args); break; default: writeJSONRPC(id, null, new JValue(String.Format("Method not implemented: {0}", method))); break; } } private string splitSuffix(char deli, ref string line) { return splitSuffix(deli, ref line, ""); } private string splitSuffix(char deli, ref string line, string def){ string result = def; int i = line.IndexOf(deli); if (i >= 0){ result = line.Substring(i + 1); line = line.Substring(0, i); }; return result; } private void rpcLogin(UInt64 id,JToken args){ string username, passwd; Agent = args["agent"].ToObject(); username = args["login"].ToObject(); passwd = args["pass"].ToObject(); try { FixedDiff = int.Parse(splitSuffix('@', ref username,"0")); WorkerID = splitSuffix('.', ref username); Wallet = new CryptoNoteAddress(username); Pool = this.listener.getAssociatedPool(Wallet.CryptoNoteCoin); if (Pool == null){ throw new Exception("No Pool for that coin available!"); } MiningJob job = Pool.WorkManager.createJob(); assignJob(job, false); Pool.WorkManager.OnNewBlockAvailable += WorkManager_OnNewBlockAvailable; } catch (Exception e){ writeJSONRPC(id,null,new JValue(String.Format("An Exception occured ({0}: {1})",e.ToString(),e.Message))); Close(); } Console.WriteLine("Miner connected: [{3}] Wallet: {0} WorkerID: {1} FixedDiff: {2}", Wallet, WorkerID, FixedDiff, UID.ToString()); writeJSONRPC(id, new JObject( new JProperty("id", "555"), new JProperty("job", CurrentJob.toJSON(100)) ), null); } private void rpcSubmit(UInt64 id,JToken args) { } private bool assignJob(MiningJob job,bool transmit){ LastJob = CurrentJob; CurrentJob = job; if (transmit){ transmitCurrentJob(); } return true; } public void transmitCurrentJob(){ writeJSON(new JObject( new JProperty("jsonrpc", "2.0"), new JProperty("method","job"), new JProperty("params", CurrentJob.toJSON()) )); } void WorkManager_OnNewBlockAvailable(WorkManager workmanager) { assignJob( this.Pool.WorkManager.createJob(), true ); } public override string ToString() { return string.Format("[StratumConnection: [{4}] MinerWallet={0}, WorkerID={1}, FixedDiff={2}, Agent={3}]", Wallet, WorkerID, FixedDiff, Agent, UID.ToString()); } } }