private void OnGetJob(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <MoneroWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.MinusOne, "missing request id", request.Id); return; } var getJobRequest = request.ParamsAs <MoneroGetJobRequest>(); // validate worker if (client.ConnectionId != getJobRequest?.WorkerId || !context.IsAuthorized) { client.RespondError(StratumError.MinusOne, "unauthorized", request.Id); return; } // respond var job = CreateWorkerJob(client); client.Respond(job, request.Id); }
protected override async Task OnRequestAsync(StratumClient <EthereumWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { case EthereumStratumMethods.Subscribe: OnSubscribe(client, tsRequest); break; case EthereumStratumMethods.Authorize: OnAuthorize(client, tsRequest); break; case EthereumStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest); break; case EthereumStratumMethods.ExtraNonceSubscribe: client.RespondError(StratumError.Other, "not supported", request.Id, false); break; default: logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
private void OnLogin(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <MoneroWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.MinusOne, "missing request id", request.Id); return; } var loginRequest = request.ParamsAs <MoneroLoginRequest>(); if (string.IsNullOrEmpty(loginRequest?.Login)) { client.RespondError(StratumError.MinusOne, "missing login", request.Id); return; } // extract worker/miner/paymentid var split = loginRequest.Login.Split('.'); context.MinerName = split[0]; context.WorkerName = split.Length > 1 ? split[1] : null; context.UserAgent = loginRequest.UserAgent; // extract paymentid var index = context.MinerName.IndexOf('#'); if (index != -1) { context.PaymentId = context.MinerName.Substring(index + 1); context.MinerName = context.MinerName.Substring(0, index); } // validate login var result = manager.ValidateAddress(context.MinerName); context.IsSubscribed = result; context.IsAuthorized = result; if (!context.IsAuthorized) { client.RespondError(StratumError.MinusOne, "invalid login", request.Id); return; } // respond var loginResponse = new MoneroLoginResponse { Id = client.ConnectionId, Job = CreateWorkerJob(client) }; client.Respond(loginResponse, request.Id); // log association logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {loginRequest.Login} = {client.RemoteEndpoint.Address}"); }
protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var context = client.GetContextAs <BitcoinWorkerContext>(); var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; var password = requestParams?.Length > 1 ? requestParams[1] : null; var passParts = password?.Split(PasswordControlVarsSeparator); var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault()?.Trim(); var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty; context.IsAuthorized = !string.IsNullOrEmpty(minerName) && await manager.ValidateAddressAsync(minerName); context.MinerName = minerName; context.WorkerName = workerName; if (context.IsAuthorized) { client.Respond(context.IsAuthorized, request.Id); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}"); var staticDiff = GetStaticDiffFromPassparts(passParts); if (staticDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; context.SetDifficulty(staticDiff.Value); client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } } else { client.RespondError(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Banning unauthorized worker for 60 sec"); banManager.Ban(client.RemoteEndpoint.Address, TimeSpan.FromSeconds(60)); DisconnectClient(client); } }
private void OnSubmitLogin(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <EthereumWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); if (requestParams == null || requestParams.Length < 1 || requestParams.Any(string.IsNullOrEmpty)) { client.RespondError(StratumError.MinusOne, "invalid request", request.Id); return; } manager.PrepareWorker(client); client.Respond(true, request.Id); // setup worker context context.IsSubscribed = true; context.IsAuthorized = true; context.MinerName = requestParams[0].Trim(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; // extract worker/miner var workerParts = workerValue?.Split('.'); var minerName = workerParts?.Length > 0 ? workerParts[0].Trim() : null; var workerName = workerParts?.Length > 1 ? workerParts[1].Trim() : null; if (!string.IsNullOrEmpty(minerName)) { context.MinerName = minerName.ToLower(); } if (!string.IsNullOrEmpty(workerName)) { context.WorkerName = workerName; } // log association if (!string.IsNullOrEmpty(context.WorkerName)) { logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved SubmitLogin command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}"); } else { logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved SubmitLogin command for {context.MinerName} from {client.RemoteEndpoint.Address}"); } }
private void OnSubscribe(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <EthereumWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); manager.PrepareWorker(client); var data = new object[] { new object[] { EthereumStratumMethods.MiningNotify, client.ConnectionId, EthereumConstants.EthereumStratumVersion }, context.ExtraNonce1 } .ToArray(); client.Respond(data, request.Id); // setup worker context context.IsSubscribed = true; context.IsNiceHashClient = true; //context.UserAgent = requestParams[0].Trim(); }
private void OnGetWork(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <EthereumWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } object[] newJobParams = (object[])currentJobParams; var header = newJobParams[2]; var seed = newJobParams[1]; var target = EthereumUtils.GetTargetHex(new BigInteger(context.Difficulty * EthereumConstants.StratumDiffFactor)); client.Respond(new object[] { header, seed, target }, request.Id); context.IsInitialWorkSent = true; var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; // log association if (!string.IsNullOrEmpty(context.WorkerName)) { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] recieved GetWork command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}"); } else { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] received GetWork command for {context.MinerName} from {client.RemoteEndpoint.Address}"); } }
protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <BitcoinWorkerContext>(); try { if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; if (requestAge > maxShareAge) { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Dropping stale share submission request (not client's fault)"); return; } context.LastActivity = clock.Now; if (!context.IsAuthorized) { throw new StratumException(StratumError.UnauthorizedWorker, "Unauthorized worker"); } else if (!context.IsSubscribed) { throw new StratumException(StratumError.NotSubscribed, "Not subscribed"); } var requestParams = request.ParamsAs <string[]>(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty); client.Respond(true, request.Id); messageBus.SendMessage(new ClientShare(client, share)); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); if (share.IsBlockCandidate) { poolStats.LastPoolBlockTime = clock.Now; } context.Stats.ValidShares++; UpdateVarDiff(client); } catch (StratumException ex) { client.RespondError(ex.Code, ex.Message, request.Id, false); context.Stats.InvalidShares++; logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share rejected: {ex.Code}"); ConsiderBan(client, context, poolConfig.Banning); } }
protected override async Task OnRequestAsync(StratumClient <MoneroWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { case MoneroStratumMethods.Login: OnLogin(client, tsRequest); break; case MoneroStratumMethods.GetJob: OnGetJob(client, tsRequest); break; case MoneroStratumMethods.Submit: await OnSubmitAsync(client, tsRequest); break; case MoneroStratumMethods.KeepAlive: // recognize activity client.Context.LastActivity = clock.UtcNow; break; default: logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var context = client.GetContextAs <BitcoinWorkerContext>(); var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; //var password = requestParams?.Length > 1 ? requestParams[1] : null; // extract worker/miner var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault(); var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty; // assumes that workerName is an address context.IsAuthorized = !string.IsNullOrEmpty(minerName) && await manager.ValidateAddressAsync(minerName); context.MinerName = minerName; context.WorkerName = workerName; // respond client.Respond(context.IsAuthorized, request.Id); // log association logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}"); }
protected virtual void OnSubscribe(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var data = new object[] { new object[] { new object[] { BitcoinStratumMethods.SetDifficulty, client.ConnectionId }, new object[] { BitcoinStratumMethods.MiningNotify, client.ConnectionId } } } .Concat(manager.GetSubscriberData(client)) .ToArray(); client.Respond(data, request.Id); // setup worker context client.Context.IsSubscribed = true; client.Context.UserAgent = requestParams?.Length > 0 ? requestParams[0].Trim() : null; // send intial update client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { client.Context.Difficulty }); client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams); }
private void OnAuthorize(StratumClient <EthereumWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; //var password = requestParams?.Length > 1 ? requestParams[1] : null; // extract worker/miner var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault(); var workerName = split?.LastOrDefault(); // assumes that workerName is an address client.Context.IsAuthorized = manager.ValidateAddress(minerName); client.Context.MinerName = minerName; client.Context.WorkerName = workerName; client.Respond(client.Context.IsAuthorized, request.Id); // send intial update client.Notify(EthereumStratumMethods.SetDifficulty, new object[] { client.Context.Difficulty }); client.Notify(EthereumStratumMethods.MiningNotify, currentJobParams); }
private void OnAuthorize(StratumClient <EthereumWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; //var password = requestParams?.Length > 1 ? requestParams[1] : null; // extract worker/miner var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault()?.Trim(); var workerName = split?.Skip(1).LastOrDefault()?.Trim(); // assumes that workerName is an address client.Context.IsAuthorized = !string.IsNullOrEmpty(minerName) && manager.ValidateAddress(minerName); client.Context.MinerName = minerName; client.Context.WorkerName = workerName; // respond client.Respond(client.Context.IsAuthorized, request.Id); EnsureInitialWorkSent(client); // log association logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}"); }
protected override void OnSubscribe(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <BitcoinWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var data = new object[] { client.ConnectionId, } .Concat(manager.GetSubscriberData(client)) .ToArray(); client.Respond(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams?.Length > 0 ? requestParams[0].Trim() : null; }
private void OnSuggestTarget(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <BitcoinWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var target = requestParams.FirstOrDefault(); if (!string.IsNullOrEmpty(target)) { if (System.Numerics.BigInteger.TryParse(target, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var targetBig)) { var newDiff = (double)new BigRational(ZCashConstants.Diff1b, targetBig); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; if (newDiff >= poolEndpoint.Difficulty) { context.EnqueueNewDifficulty(newDiff); context.ApplyPendingDifficulty(); client.Notify(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); } else { client.RespondError(StratumError.Other, "suggested difficulty too low", request.Id); } } else { client.RespondError(StratumError.Other, "invalid target", request.Id); } } else { client.RespondError(StratumError.Other, "invalid target", request.Id); } }
protected override async Task OnRequestAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { #region Nicehash case EthereumStratumMethods.Subscribe: OnSubscribe(client, tsRequest); break; case EthereumStratumMethods.Authorize: OnAuthorize(client, tsRequest); break; case EthereumStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest); break; case EthereumStratumMethods.ExtraNonceSubscribe: // unsupported break; #endregion #region Classic case EthereumStratumMethods.SubmitLogin: OnSubmitLogin(client, tsRequest); break; case EthereumStratumMethods.GetWork: OnGetWork(client, tsRequest); break; case EthereumStratumMethods.SubmitHasrate: OnSubmitHashrate(client, tsRequest); break; case EthereumStratumMethods.SubmitWork: await OnSubmitAsync(client, tsRequest); break; #endregion default: logger.Error(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
private void OnSubscribe(StratumClient <EthereumWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); if (requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) { client.RespondError(StratumError.MinusOne, "invalid request", request.Id); return; } manager.PrepareWorker(client); var data = new object[] { new object[] { EthereumStratumMethods.MiningNotify, client.ConnectionId, EthereumConstants.EthereumStratumVersion }, client.Context.ExtraNonce1 } .ToArray(); client.Respond(data, request.Id); // setup worker context client.Context.IsSubscribed = true; client.Context.UserAgent = requestParams[0].Trim(); }
protected override async Task OnRequestAsync(StratumClient <EthereumWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { default: logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
protected override async Task OnRequestAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; try { switch (request.Method) { case AionStratumMethods.Subscribe: OnSubscribeAsync(client, tsRequest); break; case AionStratumMethods.Authorize: await OnAuthorizeAsync(client, tsRequest); break; case AionStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest); break; default: logger.Debug(() => $"[{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); //await client.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } } catch (StratumException ex) { // await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); client.RespondError(ex.Code, ex.Message, request.Id, false); } }
private async void OnAuthorize(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <AionWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; var password = requestParams?.Length > 1 ? requestParams[1] : null; var passParts = password?.Split(PasswordControlVarsSeparator); // extract worker/miner var workerParts = workerValue?.Split('.'); var minerName = workerParts?.Length > 0 ? workerParts[0].Trim() : null; var workerName = workerParts?.Length > 1 ? workerParts[1].Trim() : null; // assumes that workerName is an address context.IsAuthorized = !string.IsNullOrEmpty(minerName) && await manager.ValidateAddressAsync(minerName); context.MinerName = minerName; context.WorkerName = workerName; // respond client.Respond(context.IsAuthorized, request.Id); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); if (staticDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); } EnsureInitialWorkSent(client); // log association logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}"); }
protected override async Task OnRequestAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { case SonoStratumMethods.Subscribe: OnSubscribe(client, tsRequest); break; case SonoStratumMethods.Authorize: await OnAuthorizeAsync(client, tsRequest); break; case SonoStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest); break; case SonoStratumMethods.SuggestDifficulty: OnSuggestDifficulty(client, tsRequest); break; case SonoStratumMethods.GetTransactions: //OnGetTransactions(client, tsRequest); // ignored break; case SonoStratumMethods.ExtraNonceSubscribe: // ignored break; case SonoStratumMethods.MiningMultiVersion: // ignored break; default: logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
private void OnAuthorize(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <EthereumWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; var password = requestParams?.Length > 1 ? requestParams[1] : null; var passParts = password?.Split(PasswordControlVarsSeparator); // extract worker/miner var workerParts = workerValue?.Split('.'); var minerName = workerParts?.Length > 0 ? workerParts[0].Trim() : null; var workerName = workerParts?.Length > 1 ? workerParts[1].Trim() : null; // assumes that workerName is an address context.IsAuthorized = !string.IsNullOrEmpty(minerName) && manager.ValidateAddress(minerName); context.MinerName = minerName.ToLower(); context.WorkerName = workerName; context.IsNiceHashClient = true; // respond client.Respond(context.IsAuthorized, request.Id); // send the first job to the client EnsureInitialWorkSent(client); // log association if (!string.IsNullOrEmpty(context.WorkerName)) { logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved Authorize command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}"); } else { logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved Authorize command for {context.MinerName} from {client.RemoteEndpoint.Address}"); } }
protected void OnGetTransactions(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; try { var transactions = manager.GetTransactions(client, request.ParamsAs <object[]>()); client.Respond(transactions, request.Id); } catch (StratumException ex) { client.RespondError(ex.Code, ex.Message, request.Id, false); } catch (Exception ex) { logger.Error(ex, () => $"[{LogCat}] Unable to convert suggested difficulty {request.Params}"); } }
protected virtual async Task OnAuthorizeAsync(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : null; //var password = requestParams?.Length > 1 ? requestParams[1] : null; // extract worker/miner var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault(); // assumes that workerName is an address client.Context.IsAuthorized = await manager.ValidateAddressAsync(minerName); client.Respond(client.Context.IsAuthorized, request.Id); }
protected override async Task OnRequestAsync(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; switch (request.Method) { case BitcoinStratumMethods.Subscribe: OnSubscribe(client, tsRequest); break; case BitcoinStratumMethods.Authorize: await OnAuthorizeAsync(client, tsRequest); break; case BitcoinStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest); break; case ZCashStratumMethods.SuggestTarget: //OnSuggestTarget(client, tsRequest); break; case BitcoinStratumMethods.GetTransactions: OnGetTransactions(client, tsRequest); break; default: logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } }
private void OnSubmitHashrate(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { client.RespondError(StratumError.Other, "missing request id", request.Id); return; } // Dummy command, just predend like you did something with it and send true to keep the miner happy client.Respond(true, request.Id); var context = client.GetContextAs <EthereumWorkerContext>(); if (!string.IsNullOrEmpty(context.WorkerName)) { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] received SubmitHashrate command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}"); } else { logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] received SubmitHashrate command for {context.MinerName} from {client.RemoteEndpoint.Address}"); } }
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 <EthereumWorkerContext> 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; } // validate worker if (!client.Context.IsAuthorized) { throw new StratumException(StratumError.UnauthorizedWorker, "Unauthorized worker"); } else if (!client.Context.IsSubscribed) { throw new StratumException(StratumError.NotSubscribed, "Not subscribed"); } // check request var submitRequest = request.ParamsAs <string[]>(); if (submitRequest.Length != 3 || submitRequest.Any(string.IsNullOrEmpty)) { throw new StratumException(StratumError.MinusOne, "malformed PoW result"); } // recognize activity client.Context.LastActivity = clock.UtcNow; var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; var share = await manager.SubmitShareAsync(client, submitRequest, client.Context.Difficulty, poolEndpoint.Difficulty); // success client.Respond(true, request.Id); shareSubject.OnNext(Tuple.Create((object)client, share)); EnsureInitialWorkSent(client); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty / EthereumConstants.Pow2x32, 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.Code}"); // 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 <AionWorkerContext>(); 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.Warn(() => $"[{client.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; } // validate worker if (!context.IsAuthorized) { throw new StratumException(StratumError.UnauthorizedWorker, "Unauthorized worker"); } else if (!context.IsSubscribed) { throw new StratumException(StratumError.NotSubscribed, "Not subscribed"); } // check request var submitRequest = request.ParamsAs <string[]>(); if (submitRequest.Length != 5 || submitRequest.Any(string.IsNullOrEmpty)) { throw new StratumException(StratumError.MinusOne, "malformed PoW result"); } // recognize activity context.LastActivity = clock.Now; var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; try { var share = await manager.SubmitShareAsync(client, submitRequest, context.Difficulty, poolEndpoint.Difficulty); // success // await client.RespondAsync(true, request.Id); client.Respond(true, request.Id); // publish messageBus.SendMessage(new ClientShare(client, share)); // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); logger.Debug(() => $"[{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); EnsureInitialWorkSent(client); // update pool stats if (share.IsBlockCandidate) { poolStats.LastPoolBlockTime = clock.Now; } context.Stats.ValidShares++; await UpdateVarDiffAsync(client); } catch (StratumException ex) { // 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); throw; } } catch (StratumException ex) { // await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); client.RespondError(ex.Code, ex.Message, request.Id, false); messageBus.SendMessage(new InvalidShare { PoolId = poolConfig.Id, Miner = context.MinerName, Worker = context.WorkerName, Created = clock.Now }); // 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); throw; } }
private void OnLogin(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <MoneroWorkerContext>(); if (request.Id == null) { client.RespondError(StratumError.MinusOne, "missing request id", request.Id); return; } var loginRequest = request.ParamsAs <MoneroLoginRequest>(); if (string.IsNullOrEmpty(loginRequest?.Login)) { client.RespondError(StratumError.MinusOne, "missing login", request.Id); return; } // extract worker/miner/paymentid var split = loginRequest.Login.Split('.'); context.MinerName = split[0].Trim(); context.WorkerName = split.Length > 1 ? split[1].Trim() : null; context.UserAgent = loginRequest.UserAgent?.Trim(); var passParts = loginRequest.Password?.Split(PasswordControlVarsSeparator); // extract paymentid var index = context.MinerName.IndexOf('#'); if (index != -1) { context.PaymentId = context.MinerName.Substring(index + 1).Trim(); context.MinerName = context.MinerName.Substring(0, index).Trim(); } // validate login var result = manager.ValidateAddress(context.MinerName); context.IsSubscribed = result; context.IsAuthorized = result; if (!context.IsAuthorized) { client.RespondError(StratumError.MinusOne, "invalid login", request.Id); return; } // validate payment Id if (!string.IsNullOrEmpty(context.PaymentId) && context.PaymentId.Length != MoneroConstants.PaymentIdHexLength) { client.RespondError(StratumError.MinusOne, "invalid payment id", request.Id); return; } // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); if (staticDiff.HasValue && (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || context.VarDiff == null && staticDiff.Value > context.Difficulty)) { context.VarDiff = null; // disable vardiff context.SetDifficulty(staticDiff.Value); } // respond var loginResponse = new MoneroLoginResponse { Id = client.ConnectionId, Job = CreateWorkerJob(client) }; client.Respond(loginResponse, request.Id); // log association logger.Info(() => $"[{client.ConnectionId}] Authorized worker {loginRequest.Login}"); }