private async Task SendWork(EthereumWorkerContext context, StratumConnection connection, object requestId) { var parameters = manager.GetWorkParamsForStratum(context); // respond await connection.RespondAsync(parameters, requestId); }
protected virtual async Task OnSubscribeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var context = connection.ContextAs <BitcoinWorkerContext>(); var requestParams = request.ParamsAs <string[]>(); var data = new object[] { new object[] { new object[] { BitcoinStratumMethods.SetDifficulty, connection.ConnectionId }, new object[] { BitcoinStratumMethods.MiningNotify, connection.ConnectionId } } } .Concat(manager.GetSubscriberData(connection)) .ToArray(); await connection.RespondAsync(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams?.Length > 0 ? requestParams[0].Trim() : null; // send intial update await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); }
protected async Task OnSubscribeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <BitcoinWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var requestParams = request.ParamsAs <string[]>(); var data = new object[] { connection.ConnectionId, } .Concat(manager.GetSubscriberData(connection)) .ToArray(); await connection.RespondAsync(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams.FirstOrDefault()?.Trim(); }
private async Task OnSuggestDifficultyAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <BitcoinWorkerContext>(); // acknowledge await connection.RespondAsync(true, request.Id); try { var requestedDiff = (double)Convert.ChangeType(request.Params, TypeCode.Double) !; // client may suggest higher-than-base difficulty, but not a lower one var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port]; if (requestedDiff > poolEndpoint.Difficulty) { context.SetDifficulty(requestedDiff); await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); logger.Info(() => $"[{connection.ConnectionId}] Difficulty set to {requestedDiff} as requested by miner"); } } catch (Exception ex) { logger.Error(ex, () => $"Unable to convert suggested difficulty {request.Params}"); } }
private async Task OnConfigureMiningAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <BitcoinWorkerContext>(); var requestParams = request.ParamsAs <JToken[]>(); var extensions = requestParams[0].ToObject <string[]>(); var extensionParams = requestParams[1].ToObject <Dictionary <string, JToken> >(); var result = new Dictionary <string, object>(); if (extensions != null) { foreach (var extension in extensions) { switch (extension) { case BitcoinStratumExtensions.VersionRolling: ConfigureVersionRolling(connection, context, extensionParams, result); break; case BitcoinStratumExtensions.MinimumDiff: ConfigureMinimumDiff(connection, context, extensionParams, result); break; } } } await connection.RespondAsync(result, request.Id); }
private async Task OnLoginAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <CryptonoteWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var loginRequest = request.ParamsAs <CryptonoteLoginRequest>(); if (string.IsNullOrEmpty(loginRequest?.Login)) { throw new StratumException(StratumError.MinusOne, "missing login"); } // extract worker/miner/paymentid var split = loginRequest.Login.Split('.'); context.Miner = split[0].Trim(); context.Worker = split.Length > 1 ? split[1].Trim() : null; context.UserAgent = loginRequest.UserAgent?.Trim(); var addressToValidate = context.Miner; // extract paymentid var index = context.Miner.IndexOf('#'); if (index != -1) { var paymentId = context.Miner[(index + 1)..].Trim();
private async Task OnGetWorkAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <EthereumWorkerContext>(); await SendWork(context, connection, request.Id); }
protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) { await base.OnVarDiffUpdateAsync(connection, newDiff, ct); if (connection.Context.ApplyPendingDifficulty()) { await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(connection.Context.Difficulty) }); await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } }
private async Task SendJob(EthereumWorkerContext context, StratumConnection connection, object parameters) { // varDiff: if the client has a pending difficulty change, apply it now if (context.ApplyPendingDifficulty()) { await connection.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } // send job await connection.NotifyAsync(EthereumStratumMethods.MiningNotify, parameters); }
protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff) { var context = connection.ContextAs <ErgoWorkerContext>(); context.EnqueueNewDifficulty(newDiff); if (context.ApplyPendingDifficulty()) { await SendJob(connection, context, currentJobParams); } }
protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) { await base.OnVarDiffUpdateAsync(connection, newDiff, ct); var context = connection.ContextAs <ErgoWorkerContext>(); if (context.ApplyPendingDifficulty()) { await SendJob(connection, context, currentJobParams); } }
protected override async Task <double?> GetNicehashStaticMinDiff(StratumConnection connection, string userAgent, string coinName, string algoName) { var result = await base.GetNicehashStaticMinDiff(connection, userAgent, coinName, algoName); // adjust value to fit with our target value calculation if (result.HasValue) { result = result.Value / uint.MaxValue; } return(result); }
protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff) { var context = connection.ContextAs <BitcoinWorkerContext>(); context.EnqueueNewDifficulty(newDiff); // apply immediately and notify if (context.ApplyPendingDifficulty()) { await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } }
private async Task OnSubscribeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <EthereumWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.Other, "missing request id"); } var requestParams = request.ParamsAs <string[]>(); if (requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) { throw new StratumException(StratumError.MinusOne, "invalid request"); } manager.PrepareWorker(connection); context.UserAgent = requestParams.FirstOrDefault()?.Trim(); var data = new object[] { new object[] { EthereumStratumMethods.MiningNotify, connection.ConnectionId, EthereumConstants.EthereumStratumVersion }, context.ExtraNonce1 } .ToArray(); // Nicehash's stupid validator insists on "error" property present // in successful responses which is a violation of the JSON-RPC spec var response = new JsonRpcResponse <object[]>(data, request.Id); if (context.IsNicehash) { response.Extra = new Dictionary <string, object>(); response.Extra["error"] = null; } await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; }
protected override async Task OnRequestAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; try { switch (request.Method) { case BitcoinStratumMethods.Subscribe: await OnSubscribeAsync(connection, tsRequest); break; case BitcoinStratumMethods.Authorize: await OnAuthorizeAsync(connection, tsRequest, ct); break; case BitcoinStratumMethods.SubmitShare: await OnSubmitAsync(connection, tsRequest, ct); break; case EquihashStratumMethods.SuggestTarget: await OnSuggestTargetAsync(connection, tsRequest); break; case BitcoinStratumMethods.ExtraNonceSubscribe: // ignored break; default: logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } } catch (StratumException ex) { await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); } }
public override object[] GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker, nameof(worker)); var context = worker.ContextAs <BitcoinWorkerContext>(); // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); // setup response data var responseData = new object[] { context.ExtraNonce1 }; return(responseData); }
protected override async Task OnVarDiffUpdateAsync(StratumConnection client, double newDiff) { await base.OnVarDiffUpdateAsync(client, newDiff); // apply immediately and notify client var context = client.ContextAs <EthereumWorkerContext>(); if (context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); // send job await client.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await client.NotifyAsync(EthereumStratumMethods.MiningNotify, currentJobParams); } }
private async Task OnAuthorizeAsync(StratumConnection client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <EthereumWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var requestParams = request.ParamsAs <string[]>(); var workerValue = requestParams?.Length > 0 ? requestParams[0] : "0"; 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() : "0"; // assumes that workerName is an address context.IsAuthorized = !string.IsNullOrEmpty(minerName) && manager.ValidateAddress(minerName); context.Miner = minerName.ToLower(); context.Worker = workerName; // respond await client.RespondAsync(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); logger.Info(() => $"[{client.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); } await EnsureInitialWorkSent(client); // log association logger.Info(() => $"[{client.ConnectionId}] Authorized worker {workerValue}"); }
protected virtual async Task OnSubscribeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var context = connection.ContextAs <BitcoinWorkerContext>(); var requestParams = request.ParamsAs <string[]>(); var data = new object[] { new object[] { new object[] { BitcoinStratumMethods.SetDifficulty, connection.ConnectionId }, new object[] { BitcoinStratumMethods.MiningNotify, connection.ConnectionId } } } .Concat(manager.GetSubscriberData(connection)) .ToArray(); await connection.RespondAsync(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams.FirstOrDefault()?.Trim(); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); if (nicehashDiff.HasValue) { logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); context.VarDiff = null; // disable vardiff context.SetDifficulty(nicehashDiff.Value); } // send intial update await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); }
private async Task OnSuggestTargetAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <BitcoinWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } 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(manager.ChainConfig.Diff1BValue, targetBig); var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port]; if (newDiff >= poolEndpoint.Difficulty) { context.EnqueueNewDifficulty(newDiff); context.ApplyPendingDifficulty(); await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); } else { await connection.RespondErrorAsync(StratumError.Other, "suggested difficulty too low", request.Id); } } else { await connection.RespondErrorAsync(StratumError.Other, "invalid target", request.Id); } } else { await connection.RespondErrorAsync(StratumError.Other, "invalid target", request.Id); } }
public virtual object[] GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker, nameof(worker)); var context = worker.ContextAs <BitcoinWorkerContext>(); // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); // setup response data var responseData = new object[] { context.ExtraNonce1, BitcoinConstants.ExtranoncePlaceHolderLength - ExtranonceBytes, }; return(responseData); }
protected override async Task OnRequestAsync(StratumConnection client, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; try { switch (request.Method) { case EthereumStratumMethods.Subscribe: await OnSubscribeAsync(client, tsRequest); break; case EthereumStratumMethods.Authorize: await OnAuthorizeAsync(client, tsRequest); break; case EthereumStratumMethods.SubmitShare: await OnSubmitAsync(client, tsRequest, ct); break; case EthereumStratumMethods.ExtraNonceSubscribe: // Pretend to support it even though we actually do not. Some miners drop the connection upon receiving an error from this await client.RespondAsync(true, request.Id); break; default: logger.Info(() => $"[{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); await client.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); break; } } catch (StratumException ex) { await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); } }
private void ConfigureMinimumDiff(StratumConnection connection, BitcoinWorkerContext context, IReadOnlyDictionary <string, JToken> extensionParams, Dictionary <string, object> result) { var requestedDiff = extensionParams[BitcoinStratumExtensions.MinimumDiffValue].Value <double>(); // client may suggest higher-than-base difficulty, but not a lower one var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port]; if (requestedDiff > poolEndpoint.Difficulty) { context.VarDiff = null; // disable vardiff context.SetDifficulty(requestedDiff); logger.Info(() => $"[{connection.ConnectionId}] Difficulty set to {requestedDiff} as requested by miner. VarDiff now disabled."); // enabled result[BitcoinStratumExtensions.MinimumDiff] = true; } }
static void Mainasdfasdfasdf(string[] args) { var serversList = new List <StratumConnection> { //groestl - StratumConnection.Parse("hub.miningpoolhub.com,12004,wchasik,home,x"); //myr-gr - StratumConnection.Parse("hub.miningpoolhub.com,12005,wchasik,home,x"); StratumConnection.Parse(AlgoNiceHashEnum.X11, "hub.miningpoolhub.com,12007,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.X13, "hub.miningpoolhub.com,12008,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.X15, "hub.miningpoolhub.com,12009,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.NeoScrypt, "hub.miningpoolhub.com,12012,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.Qubit, "hub.miningpoolhub.com,12014,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.Quark, "hub.miningpoolhub.com,12015,wchasik,home,x"), // skein - StratumConnection.Parse("hub.miningpoolhub.com,12016,wchasik,home,x"); StratumConnection.Parse(AlgoNiceHashEnum.Lyra2REv2, "hub.miningpoolhub.com,12018,wchasik,home,x"), // vanilla - StratumConnection.Parse("hub.miningpoolhub.com,12019,wchasik,home,x"); StratumConnection.Parse(AlgoNiceHashEnum.DaggerHashimoto, "europe.ethash-hub.miningpoolhub.com,12020,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.Equihash, "europe.equihash-hub.miningpoolhub.com,12023,wchasik,home,x"), StratumConnection.Parse(AlgoNiceHashEnum.CryptoNight, "europe.cryptonight-hub.miningpoolhub.com,12024,wchasik,home,x") }; serversList.Where(sc => sc.Algo == AlgoNiceHashEnum.NeoScrypt || sc.Algo == AlgoNiceHashEnum.Equihash || sc.Algo == AlgoNiceHashEnum.CryptoNight || sc.Algo == AlgoNiceHashEnum.Lyra2REv2) .ToList().ForEach(server => { var pinger = new PingServer(server, 10000); pinger.PingResultChanged += result => { //System.Console.BackgroundColor = result.Success ? ConsoleColor.Cyan : ConsoleColor.Red; System.Console.WriteLine($"minutes: {(DateTime.Now - result.DateTime).TotalMinutes:#######.##} ; {result.Success} ; {result.Result}"); }; pinger.GotResponse += (sender, stratumEventArgs) => { }; }); System.Console.ReadLine(); }
private void ConfigureVersionRolling(StratumConnection connection, BitcoinWorkerContext context, IReadOnlyDictionary <string, JToken> extensionParams, Dictionary <string, object> result) { //var requestedBits = extensionParams[BitcoinStratumExtensions.VersionRollingBits].Value<int>(); var requestedMask = BitcoinConstants.VersionRollingPoolMask; if (extensionParams.TryGetValue(BitcoinStratumExtensions.VersionRollingMask, out var requestedMaskValue)) { requestedMask = uint.Parse(requestedMaskValue.Value <string>(), NumberStyles.HexNumber); } // Compute effective mask context.VersionRollingMask = BitcoinConstants.VersionRollingPoolMask & requestedMask; // enabled result[BitcoinStratumExtensions.VersionRolling] = true; result[BitcoinStratumExtensions.VersionRollingMask] = context.VersionRollingMask.Value.ToStringHex8(); logger.Info(() => $"[{connection.ConnectionId}] Using version-rolling mask {result[BitcoinStratumExtensions.VersionRollingMask]}"); }
private async Task SendJob(StratumConnection connection, ErgoWorkerContext context, object[] jobParams) { // clone job params var jobParamsActual = new object[jobParams.Length]; for (var i = 0; i < jobParamsActual.Length; i++) { jobParamsActual[i] = jobParams[i]; } var target = new BigRational(BitcoinConstants.Diff1 * (BigInteger)(1 / context.Difficulty * 0x10000), 0x10000).GetWholePart(); jobParamsActual[6] = target.ToString(); // send static diff of 1 since actual diff gets pre-multiplied to target await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { 1 }); // send target await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, jobParamsActual); }
private async Task EnsureInitialWorkSent(StratumConnection connection) { var context = connection.ContextAs <EthereumWorkerContext>(); var sendInitialWork = false; lock (context) { if (context.IsSubscribed && context.IsAuthorized && !context.IsInitialWorkSent) { context.IsInitialWorkSent = true; sendInitialWork = true; } } if (sendInitialWork) { // send intial update await connection.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await connection.NotifyAsync(EthereumStratumMethods.MiningNotify, currentJobParams); } }
protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) { await base.OnVarDiffUpdateAsync(connection, newDiff, ct); var context = connection.ContextAs <EthereumWorkerContext>(); if (context.ApplyPendingDifficulty()) { switch (context.ProtocolVersion) { case 1: await SendWork(context, connection, 0); break; case 2: await SendJob(context, connection, manager.GetJobParamsForStratum()); break; } } }
private async Task OnSubscribeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.ContextAs <EthereumWorkerContext>(); if (request.Id == null) { throw new StratumException(StratumError.Other, "missing request id"); } var requestParams = request.ParamsAs <string[]>(); if (requestParams == null || requestParams.Length < 2 || requestParams.Any(string.IsNullOrEmpty)) { throw new StratumException(StratumError.MinusOne, "invalid request"); } manager.PrepareWorker(connection); var data = new object[] { new object[] { EthereumStratumMethods.MiningNotify, connection.ConnectionId, EthereumConstants.EthereumStratumVersion }, context.ExtraNonce1 } .ToArray(); await connection.RespondAsync(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams[0].Trim(); }
protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var context = connection.ContextAs <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); // extract worker/miner var split = workerValue?.Split('.'); var minerName = split?.FirstOrDefault()?.Trim(); var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty; // assumes that minerName is an address context.IsAuthorized = await manager.ValidateAddressAsync(minerName, ct); context.Miner = minerName; context.Worker = workerName; if (context.IsAuthorized) { // respond await connection.RespondAsync(context.IsAuthorized, request.Id); // log association logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); // Static diff 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); logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } } else { await connection.RespondErrorAsync(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized); // issue short-time ban if unauthorized to prevent DDos on daemon (validateaddress RPC) logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {minerName} for {loginFailureBanTimeout.TotalSeconds} sec"); banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); CloseConnection(connection); } }