protected virtual async Task OnSubscribeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; if (request.Id == null) { throw new StratumException(StratumError.MinusOne, "missing request id"); } var context = client.ContextAs <BitcoinWorkerContext>(); 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(); await client.RespondAsync(data, request.Id); // setup worker context context.IsSubscribed = true; context.UserAgent = requestParams?.Length > 0 ? requestParams[0].Trim() : null; // send intial update await client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); }
protected override async Task OnAuthorizeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { await base.OnAuthorizeAsync(client, tsRequest); var context = client.ContextAs <BitcoinWorkerContext>(); if (context.IsAuthorized) { // send intial update await client.NotifyAsync(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } }
protected override async Task OnVarDiffUpdateAsync(StratumClient client, double newDiff) { var context = client.ContextAs<BitcoinWorkerContext>(); context.EnqueueNewDifficulty(newDiff); // apply immediately and notify client if (context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); await client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await client.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } }
private async Task OnSuggestDifficultyAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <BitcoinWorkerContext>(); // acknowledge await client.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[client.PoolEndpoint.Port]; if (requestedDiff > poolEndpoint.Difficulty) { context.SetDifficulty(requestedDiff); await client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); logger.Info(() => $"[{client.ConnectionId}] Difficulty set to {requestedDiff} as requested by miner"); } } catch (Exception ex) { logger.Error(ex, () => $"Unable to convert suggested difficulty {request.Params}"); } }
protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped<JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; if (request.Id == null) throw new StratumException(StratumError.MinusOne, "missing request id"); var context = client.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 workerName is an address context.IsAuthorized = !string.IsNullOrEmpty(minerName) && await manager.ValidateAddressAsync(minerName, ct); context.Miner = minerName; context.Worker = workerName; if (context.IsAuthorized) { // respond await client.RespondAsync(context.IsAuthorized, request.Id); // log association logger.Info(() => $"[{client.ConnectionId}] Authorized worker {workerValue}"); // 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 client.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); } } else { // respond await client.RespondErrorAsync(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized); // issue short-time ban if unauthorized to prevent DDos on daemon (validateaddress RPC) logger.Info(() => $"[{client.ConnectionId}] Banning unauthorized worker for 60 sec"); banManager.Ban(client.RemoteEndpoint.Address, TimeSpan.FromSeconds(60)); DisconnectClient(client); } }
protected override async Task OnVarDiffUpdateAsync(StratumClient 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 EnsureInitialWorkSent(StratumClient client) { var context = client.ContextAs <EthereumWorkerContext>(); var sendInitialWork = false; lock (context) { if (context.IsSubscribed && context.IsAuthorized && !context.IsInitialWorkSent && context.IsNiceHashClient) { context.IsInitialWorkSent = true; sendInitialWork = true; } } if (sendInitialWork) { // send intial update await client.NotifyAsync(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); await client.NotifyAsync(EthereumStratumMethods.MiningNotify, currentJobParams); } }
protected override async Task OnVarDiffUpdateAsync(StratumClient client, double newDiff) { await base.OnVarDiffUpdateAsync(client, newDiff); // apply immediately and notify client var context = client.ContextAs <CryptonoteWorkerContext>(); if (context.HasPendingDifficulty) { context.ApplyPendingDifficulty(); // re-send job var job = CreateWorkerJob(client); await client.NotifyAsync(CryptonoteStratumMethods.JobNotify, job); } }
private async Task OnSuggestTargetAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.ContextAs <BitcoinWorkerContext>(); if (request.Id == null) { await client.RespondErrorAsync(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(chainConfig.Diff1b, targetBig); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; if (newDiff >= poolEndpoint.Difficulty) { context.EnqueueNewDifficulty(newDiff); context.ApplyPendingDifficulty(); await client.NotifyAsync(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); } else { await client.RespondErrorAsync(StratumError.Other, "suggested difficulty too low", request.Id); } } else { await client.RespondErrorAsync(StratumError.Other, "invalid target", request.Id); } } else { await client.RespondErrorAsync(StratumError.Other, "invalid target", request.Id); } }