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);
            }
        }
Exemple #2
0
    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;
        }
    }
Exemple #3
0
    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);
            }
        }
Exemple #5
0
 public void Reset()
 {
     _startAt = _clock.Time;
     _point   = null;
     _inTrial = false;
 }
Exemple #6
0
        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);
            }
        }
Exemple #7
0
 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);
 }
Exemple #8
0
        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));
        }
Exemple #9
0
        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;
        }
Exemple #12
0
 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));
 }
Exemple #13
0
 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));
 }
Exemple #14
0
 public override void Accept(Timestamped <IMarker> value) => SendEvent((byte)(value.Value.Code & 0xFF));
 private async Task OnSubmitAsync(IStratumClient client, Timestamped <JsonRpcRequest> tsRequest)
 {
 }
Exemple #16
0
 public override void Accept(Timestamped <ISample> value)
 {
 }
Exemple #17
0
 // Interface implementation
 public int GetHashCode(Timestamped <long> obj) => 0;
Exemple #18
0
 /// <inheritdoc />
 public bool Equals(Timestamped <T> other) => Timestamp == other.Timestamp && EqualityComparer <T> .Default.Equals(Value, other.Value);
Exemple #19
0
        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);
        }
Exemple #20
0
        /// <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)
 {
 }
Exemple #22
0
 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));
 }
Exemple #23
0
        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}");
        }
Exemple #24
0
 protected virtual void OnElement(Timestamped <IElement> element)
 {
     _logger.Debug("{0}: OnElement ({1}): {2}", Id, element.Timestamp, element.Value);
 }
Exemple #25
0
        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;
            }
        }
Exemple #26
0
        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);
 }
Exemple #28
0
        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}");
            }
        }
Exemple #29
0
    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);
        }
    }
Exemple #30
0
        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);
Exemple #32
0
        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);
        }
Exemple #33
0
        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);
            }
        }
Exemple #34
0
        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;
            }
        }
Exemple #35
0
 public bool Equals(Timestamped <long> x, Timestamped <long> y)
 => x.Value == y.Value && AreDateTimeOffsetsClose(x.Timestamp, y.Timestamp, TimeSpan.FromMilliseconds(10));
Exemple #36
0
        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}");
            }
        }
Exemple #37
0
        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;
 }
Exemple #39
0
 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;
 }
Exemple #42
0
        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);
            }
        }