private async Task OnSubmitAsync(StratumClient <MoneroWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; try { if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } // check age of submission (aged submissions are usually caused by high server load) var requestAge = clock.UtcNow - tsRequest.Timestamp.UtcDateTime; if (requestAge > maxShareAge) { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Dropping stale share submission request (not client's fault)"); return; } // check request var submitRequest = request.ParamsAs <MoneroSubmitShareRequest>(); // validate worker if (client.ConnectionId != submitRequest?.WorkerId || !client.Context.IsAuthorized) { throw new StratumException(StratumError.MinusOne, "unauthorized"); } // recognize activity client.Context.LastActivity = clock.UtcNow; MoneroWorkerJob job; lock (client.Context) { var jobId = submitRequest?.JobId; if (string.IsNullOrEmpty(jobId) || (job = client.Context.ValidJobs.FirstOrDefault(x => x.Id == jobId)) == null) { throw new StratumException(StratumError.MinusOne, "invalid jobid"); } } // dupe check var nonceLower = submitRequest.Nonce.ToLower(); lock (job) { if (job.Submissions.Contains(nonceLower)) { throw new StratumException(StratumError.MinusOne, "duplicate share"); } job.Submissions.Add(nonceLower); } var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; var share = await manager.SubmitShareAsync(client, submitRequest, job, poolEndpoint.Difficulty); // success client.Respond(new MoneroResponseBase(), request.Id); shareSubject.OnNext(Tuple.Create((object)client, share)); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); // update pool stats if (share.IsBlockCandidate) { poolStats.LastPoolBlockTime = clock.UtcNow; } // update client stats client.Context.Stats.ValidShares++; } catch (StratumException ex) { client.RespondError(ex.Code, ex.Message, request.Id, false); // update client stats client.Context.Stats.InvalidShares++; logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share rejected: {ex.Message}"); // banning if (poolConfig.Banning?.Enabled == true) { ConsiderBan(client, client.Context, poolConfig.Banning); } } }
private async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <MoneroWorkerContext>(); try { if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } // check age of submission (aged submissions are usually caused by high server load) var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; if (requestAge > maxShareAge) { logger.Debug(() => $"[{client.ConnectionId}] Dropping stale share submission request (not client's fault)"); return; } // check request var submitRequest = request.ParamsAs <MoneroSubmitShareRequest>(); // validate worker if (client.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) { throw new StratumException(StratumError.MinusOne, "unauthorized"); } // recognize activity context.LastActivity = clock.Now; MoneroWorkerJob job; lock (context) { var jobId = submitRequest?.JobId; if ((job = context.FindJob(jobId)) == null) { throw new StratumException(StratumError.MinusOne, "invalid jobid"); } } // dupe check var nonceLower = submitRequest.Nonce.ToLower(); lock (job) { if (job.Submissions.Contains(nonceLower)) { throw new StratumException(StratumError.MinusOne, "duplicate share"); } job.Submissions.Add(nonceLower); } var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; var share = await manager.SubmitShareAsync(client, submitRequest, job, poolEndpoint.Difficulty); client.Respond(new MoneroResponseBase(), request.Id); // publish messageBus.SendMessage(new ClientShare(client, share)); // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); logger.Info(() => $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); // update pool stats if (share.IsBlockCandidate) { poolStats.LastPoolBlockTime = clock.Now; } // update client stats context.Stats.ValidShares++; UpdateVarDiff(client); } catch (StratumException ex) { client.RespondError(ex.Code, ex.Message, request.Id, false); // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); // update client stats context.Stats.InvalidShares++; logger.Info(() => $"[{client.ConnectionId}] Share rejected: {ex.Message}"); // banning ConsiderBan(client, context, poolConfig.Banning); } }