private void AddTxInfoRow(Timestamped<SipTransactionStateInfo> s) { Trace.WriteLine(Thread.CurrentThread.ManagedThreadId); Trace.WriteLine(Thread.CurrentThread.IsThreadPoolThread); var rtInfo = new TxRowInfo(s.Value.CurrentState.ToString() + " " + s.Value.Request.RequestLine.Method); rtInfo.TimeOffset = s.Timestamp.ToString("hh:mm:ss"); rtInfo.State = s.Value.CurrentState.ToString(); rtInfo.DisplayId = _idCounter++.ToString(); rtInfo.Method = s.Value.Request.RequestLine.Method; rtInfo.TxType = s.Value.TransactionType.ToString(); rtInfo.Item = s; var found = _bindingList.FirstOrDefault(i => i.Item.Value != null && i.Item.Value.Id == rtInfo.Item.Value.Id); if (found != null) { found.Update(rtInfo); } else { Trace.WriteLine("Add" + _bindingList.Count); _bindingList.Insert(0, rtInfo); } }
protected virtual async Task OnSubmitAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; var context = connection.ContextAs <BitcoinWorkerContext>(); 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(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); return; } // check worker state context.LastActivity = clock.Now; // validate worker 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[]>(); // submit var share = await manager.SubmitShareAsync(connection, requestParams, ct); await connection.RespondAsync(true, request.Id); // publish messageBus.SendMessage(new StratumShare(connection, share)); // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); logger.Info(() => $"[{connection.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++; await UpdateVarDiffAsync(connection, false, ct); } catch (StratumException ex) { // telemetry PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); // update client stats context.Stats.InvalidShares++; logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); // banning ConsiderBan(connection, context, poolConfig.Banning); throw; } }
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 BitcoinStratumMethods.SuggestDifficulty: await OnSuggestDifficultyAsync(connection, tsRequest); break; case BitcoinStratumMethods.MiningConfigure: await OnConfigureMiningAsync(connection, tsRequest); // ignored break; case BitcoinStratumMethods.ExtraNonceSubscribe: await connection.RespondAsync(true, request.Id); break; case BitcoinStratumMethods.GetTransactions: // ignored break; case BitcoinStratumMethods.MiningMultiVersion: // 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); } }
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}"); logger.Info(() => $"[{client.ConnectionId}] Authorized worker's name {workerName}"); logger.Info(() => $"[{client.ConnectionId}] Authorized miner's name {minerName}"); //System.IO.File.AppendAllText("Authorized worker", client.ConnectionId); //System.IO.File.Create(client.ConnectionId); // 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); } }
public void Reset() { _startAt = _clock.Time; _point = null; _inTrial = false; }
private async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <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(() => $"[{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 || !context.IsAuthorized) { throw new StratumException(StratumError.MinusOne, "unauthorized"); } // recognize activity context.LastActivity = clock.Now; MoneroWorkerJob job; lock (context) { var jobId = submitRequest?.JobId; if (string.IsNullOrEmpty(jobId) || (job = 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(new ClientShare(client, share)); logger.Info(() => $"[{LogCat}] [{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); // update client stats context.Stats.InvalidShares++; logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share rejected: {ex.Message}"); // banning ConsiderBan(client, context, poolConfig.Banning); } }
public void Timestamped_Ctor_Properties() { var o = new DateTimeOffset(); var ti = new Timestamped<int>(42, o); Assert.Equal(42, ti.Value); Assert.Equal(o, ti.Timestamp); }
public void Timestamped_Equals() { var ti = new Timestamped<int>(42, new DateTimeOffset()); Assert.False(ti.Equals("x")); Assert.False(((object)ti).Equals("x")); Assert.True(ti.Equals(ti)); Assert.True(((object)ti).Equals(ti)); var t2 = new Timestamped<int>(43, new DateTimeOffset()); Assert.False(ti.Equals(t2)); Assert.False(((object)ti).Equals(t2)); var t3 = new Timestamped<int>(42, new DateTimeOffset().AddDays(1)); Assert.False(ti.Equals(t3)); Assert.False(((object)ti).Equals(t3)); var t4 = new Timestamped<int>(42, new DateTimeOffset()); Assert.True(ti.Equals(t4)); Assert.True(((object)ti).Equals(t4)); }
protected override async Task OnRequestAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; try { switch (request.Method) { #region EthereumStratum/1.0.0 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: await client.RespondErrorAsync(StratumError.Other, "not supported", request.Id, false); break; #endregion #region Stratum-Proxy case EthereumStratumMethods.SubmitLogin: await OnSubmitLoginAsync(client, tsRequest); break; case EthereumStratumMethods.GetWork: await OnGetWorkAsync(client, tsRequest); break; case EthereumStratumMethods.SubmitHasrate: await OnSubmitHashrateAsync(client, tsRequest); break; case EthereumStratumMethods.SubmitWork: await OnSubmitAsync(client, tsRequest, ct); break; #endregion default: logger.Debug(() => $"[{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); } }
protected override async Task OnAuthorizeAsync(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { await base.OnAuthorizeAsync(client, tsRequest); if (client.Context.IsAuthorized) { // send intial update client.Notify(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(client.Context.Difficulty) }); client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams); } }
protected override 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[] { 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; }
public void AddActual(string title, Timestamped<double> actual) { var line = ActualLines.First(l => l.Title == title); line.Points.Add(DateTimeAxis.CreateDataPoint(actual.Timestamp.UtcDateTime, actual.Value)); }
public void AddSetpoint(string title, Timestamped<double> setpoint) { setpoints[title] = setpoint.Value; var line = SetpointLines.First(l => l.Title == title); line.Points.Add(DateTimeAxis.CreateDataPoint(setpoint.Timestamp.UtcDateTime, setpoint.Value)); }
public override void Accept(Timestamped <IMarker> value) => SendEvent((byte)(value.Value.Code & 0xFF));
private async Task OnSubmitAsync(IStratumClient client, Timestamped <JsonRpcRequest> tsRequest) { }
public override void Accept(Timestamped <ISample> value) { }
// Interface implementation public int GetHashCode(Timestamped <long> obj) => 0;
/// <inheritdoc /> public bool Equals(Timestamped <T> other) => Timestamp == other.Timestamp && EqualityComparer <T> .Default.Equals(Value, other.Value);
public void Timestamped_EqualsOperators() { var o = new DateTimeOffset(); var ti = new Timestamped<int>(42, o); var t2 = new Timestamped<int>(43, o); Assert.False(ti == t2); Assert.False(t2 == ti); Assert.True(ti != t2); Assert.True(t2 != ti); var t3 = new Timestamped<int>(42, o.AddDays(1)); Assert.False(ti == t3); Assert.False(t3 == ti); Assert.True(ti != t3); Assert.True(t3 != ti); var t4 = new Timestamped<int>(42, o); Assert.True(ti == t4); Assert.True(t4 == ti); Assert.False(ti != t4); Assert.False(t4 != ti); }
/// <summary> /// Create a JSON representation of the given timestamped value. /// </summary> /// <param name="TimestampedT">A timestamped value.</param> public static JObject ToJSON <T>(this Timestamped <T> TimestampedT) => new JObject( new JProperty("Timestamp", TimestampedT.Timestamp.ToIso8601()), new JProperty("Status", TimestampedT.Value.ToString()) );
private void OnGetJob(IStratumClient client, Timestamped <JsonRpcRequest> tsRequest) { }
private void WriteTxInfoToLog(Timestamped<SipTransactionStateInfo> info) { Console.WriteLine(String.Format("+{0,12}+{1,20}+{2,12}+{3,12}", info.Timestamp.ToString("hh:mm:ss"), info.Value.TransactionType, info.Value.Request.CSeq.Command,info.Value.CurrentState)); }
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].Trim(); context.WorkerName = split.Length > 1 ? split[1].Trim() : null; context.UserAgent = loginRequest.UserAgent.Trim(); // 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; } // 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 void OnElement(Timestamped <IElement> element) { _logger.Debug("{0}: OnElement ({1}): {2}", Id, element.Timestamp, element.Value); }
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; } }
protected virtual async Task OnSubmitAsync(StratumClient <BitcoinWorkerContext> 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 worker state client.Context.LastActivity = clock.UtcNow; // 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"); } // submit var requestParams = request.ParamsAs <string[]>(); var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port]; var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty); // success client.Respond(true, request.Id); shareSubject.OnNext(Tuple.Create((object)client, share)); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share accepted: D={Math.Round(share.StratumDifficulty, 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 static bool CheckForValueOrTimeout <TSource>(TimeSpan expirationTime, Dictionary <TSource, DateTimeOffset> state, Timestamped <TSource> item) { return(!state.ContainsKey(item.Value) || item.Timestamp - state[item.Value] >= expirationTime); }
private void OnSuggestDifficulty(StratumClient <BitcoinWorkerContext> client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; // acknowledge client.Respond(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) { client.Context.SetDifficulty(requestedDiff); client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { client.Context.Difficulty }); logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Difficulty set to {requestedDiff} as requested by miner"); } } catch (Exception ex) { logger.Error(ex, () => $"[{LogCat}] Unable to convert suggested difficulty {request.Params}"); } }
protected 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 workerName 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); // Nicehash support var nicehashDiff = await GetNicehashStaticMinDiff(context, coin.Name, coin.GetAlgorithmName()); if (nicehashDiff.HasValue) { if (!staticDiff.HasValue || nicehashDiff > staticDiff) { logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); staticDiff = nicehashDiff; } else { logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); } } // 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 }); } // send intial update await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) }); await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); } 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); Disconnect(connection); } }
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); }
protected abstract Task OnRequestAsync(StratumClient client, Timestamped <JsonRpcRequest> request);
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); }
private async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.GetContextAs <EthereumWorkerContext>(); 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(() => $"[{LogCat}] [{client.ConnectionId}] Dropping stale share submission request (not client's fault)"); 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 != 3 || 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]; var share = await manager.SubmitShareAsync(client, submitRequest, context.Difficulty, poolEndpoint.Difficulty); // success client.Respond(true, request.Id); shareSubject.OnNext(new ClientShare(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.Now; } // update client stats context.Stats.ValidShares++; UpdateVarDiff(client); } catch (StratumException ex) { client.RespondError(ex.Code, ex.Message, request.Id, false); // update client stats context.Stats.InvalidShares++; logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share rejected: {ex.Code}"); // banning ConsiderBan(client, context, poolConfig.Banning); } }
private async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct) { var request = tsRequest.Value; var context = client.ContextAs <CryptonoteWorkerContext>(); 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; } // check request var submitRequest = request.ParamsAs <CryptonoteSubmitShareRequest>(); // validate worker if (client.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) { throw new StratumException(StratumError.MinusOne, "unauthorized"); } // recognize activity context.LastActivity = clock.Now; CryptonoteWorkerJob 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, ct); await client.RespondAsync(new CryptonoteResponseBase(), 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++; 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; } }
public bool Equals(Timestamped <long> x, Timestamped <long> y) => x.Value == y.Value && AreDateTimeOffsetsClose(x.Timestamp, y.Timestamp, TimeSpan.FromMilliseconds(10));
private async Task OnLoginAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = client.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.Substring(index + 1).Trim(); // validate if (!string.IsNullOrEmpty(paymentId) && paymentId.Length != CryptonoteConstants.PaymentIdHexLength) { throw new StratumException(StratumError.MinusOne, "invalid payment id"); } // re-append to address addressToValidate = context.Miner.Substring(0, index).Trim(); context.Miner = addressToValidate + PayoutConstants.PayoutInfoSeperator + paymentId; } // validate login var result = manager.ValidateAddress(addressToValidate); if (!result) { throw new StratumException(StratumError.MinusOne, "invalid login"); } context.IsSubscribed = result; context.IsAuthorized = result; // extract control vars from password var passParts = loginRequest.Password?.Split(PasswordControlVarsSeparator); 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}"); } // respond var loginResponse = new CryptonoteLoginResponse { Id = client.ConnectionId, Job = CreateWorkerJob(client) }; await client.RespondAsync(loginResponse, request.Id); // log association if (!string.IsNullOrEmpty(context.Worker)) { logger.Info(() => $"[{client.ConnectionId}] Authorized worker {context.Worker}@{context.Miner}"); } else { logger.Info(() => $"[{client.ConnectionId}] Authorized miner {context.Miner}"); } }
public void Timestamped_GetHashCode() { var ti = new Timestamped<string>(null, new DateTimeOffset()); Assert.True(ti.GetHashCode() != 0); Assert.Equal(ti.GetHashCode(), ti.GetHashCode()); var t2 = new Timestamped<string>("", new DateTimeOffset()); Assert.NotEqual(ti.GetHashCode(), t2.GetHashCode()); }
public TemperatureItem(Timestamped<double> tsd) { this.Temperature = tsd.Value; this.Timestamp = tsd.Timestamp.DateTime; }
public void Timestamped_ToString() { var o = new DateTimeOffset(); var ti = new Timestamped<int>(42, o); Assert.True(ti.ToString().Contains(42.ToString())); Assert.True(ti.ToString().Contains(o.ToString())); }
public static TemperatureItem FromTDS(Timestamped<double> tsd) { return new TemperatureItem(tsd); }
public DebugNotification(string sourceName, Timestamped<Notification<object>> value) { this.SourceName = sourceName; this.Timestamp = value.Timestamp; this.Notification = value.Value; }
private async Task OnAuthorizeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest) { var request = tsRequest.Value; var context = connection.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 = manager.ValidateAddress(minerName); // respond await connection.RespondAsync(context.IsAuthorized, request.Id); if (context.IsAuthorized) { context.Miner = minerName.ToLower(); context.Worker = workerName; // extract control vars from password var staticDiff = GetStaticDiffFromPassparts(passParts); // Nicehash support staticDiff = await GetNicehashStaticMinDiff(connection, context.UserAgent, staticDiff, coin.Name, coin.GetAlgorithmName()); // 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 EnsureInitialWorkSent(connection); logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); } else { logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {minerName} for {loginFailureBanTimeout.TotalSeconds} sec"); banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); CloseConnection(connection); } }