Ejemplo n.º 1
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 EquihashStratumMethods.SuggestTarget:
                await OnSuggestTargetAsync(connection, tsRequest);

                break;

            case BitcoinStratumMethods.ExtraNonceSubscribe:
                // ignored
                break;

            default:
                logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}");

                await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id);

                break;
            }
        }

        catch (StratumException ex)
        {
            await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false);
        }
    }
Ejemplo n.º 2
0
    private async Task OnSuggestTargetAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest)
    {
        var request = tsRequest.Value;
        var context = connection.ContextAs <BitcoinWorkerContext>();

        if (request.Id == null)
        {
            throw new StratumException(StratumError.MinusOne, "missing request id");
        }

        var requestParams = request.ParamsAs <string[]>();
        var target        = requestParams.FirstOrDefault();

        if (!string.IsNullOrEmpty(target))
        {
            if (System.Numerics.BigInteger.TryParse(target, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var targetBig))
            {
                var newDiff      = (double)new BigRational(manager.ChainConfig.Diff1BValue, targetBig);
                var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port];

                if (newDiff >= poolEndpoint.Difficulty)
                {
                    context.EnqueueNewDifficulty(newDiff);
                    context.ApplyPendingDifficulty();

                    await connection.NotifyAsync(EquihashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) });
                }

                else
                {
                    await connection.RespondErrorAsync(StratumError.Other, "suggested difficulty too low", request.Id);
                }
            }

            else
            {
                await connection.RespondErrorAsync(StratumError.Other, "invalid target", request.Id);
            }
        }

        else
        {
            await connection.RespondErrorAsync(StratumError.Other, "invalid target", request.Id);
        }
    }
Ejemplo n.º 3
0
        protected override async Task OnRequestAsync(StratumConnection client,
                                                     Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct)
        {
            var request = tsRequest.Value;

            try
            {
                switch (request.Method)
                {
                case EthereumStratumMethods.Subscribe:
                    await OnSubscribeAsync(client, tsRequest);

                    break;

                case EthereumStratumMethods.Authorize:
                    await OnAuthorizeAsync(client, tsRequest);

                    break;

                case EthereumStratumMethods.SubmitShare:
                    await OnSubmitAsync(client, tsRequest, ct);

                    break;

                case EthereumStratumMethods.ExtraNonceSubscribe:
                    // Pretend to support it even though we actually do not. Some miners drop the connection upon receiving an error from this
                    await client.RespondAsync(true, request.Id);

                    break;

                default:
                    logger.Info(() => $"[{client.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}");

                    await client.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id);

                    break;
                }
            }

            catch (StratumException ex)
            {
                await client.RespondErrorAsync(ex.Code, ex.Message, request.Id, false);
            }
        }
Ejemplo n.º 4
0
    protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct)
    {
        var request = tsRequest.Value;

        if (request.Id == null)
        {
            throw new StratumException(StratumError.MinusOne, "missing request id");
        }

        var context       = connection.ContextAs <BitcoinWorkerContext>();
        var requestParams = request.ParamsAs <string[]>();
        var workerValue   = requestParams?.Length > 0 ? requestParams[0] : null;
        var password      = requestParams?.Length > 1 ? requestParams[1] : null;
        var passParts     = password?.Split(PasswordControlVarsSeparator);

        // extract worker/miner
        var split      = workerValue?.Split('.');
        var minerName  = split?.FirstOrDefault()?.Trim();
        var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty;

        // assumes that minerName is an address
        context.IsAuthorized = await manager.ValidateAddressAsync(minerName, ct);

        context.Miner  = minerName;
        context.Worker = workerName;

        if (context.IsAuthorized)
        {
            // respond
            await connection.RespondAsync(context.IsAuthorized, request.Id);

            // log association
            logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}");

            // extract control vars from password
            var staticDiff = GetStaticDiffFromPassparts(passParts);

            // Static diff
            if (staticDiff.HasValue &&
                (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff ||
                 context.VarDiff == null && staticDiff.Value > context.Difficulty))
            {
                context.VarDiff = null; // disable vardiff
                context.SetDifficulty(staticDiff.Value);

                logger.Info(() => $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}");

                await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty });
            }
        }

        else
        {
            await connection.RespondErrorAsync(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized);

            // issue short-time ban if unauthorized to prevent DDos on daemon (validateaddress RPC)
            logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {minerName} for {loginFailureBanTimeout.TotalSeconds} sec");

            banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout);

            CloseConnection(connection);
        }
    }
Ejemplo n.º 5
0
    protected override async Task OnRequestAsync(StratumConnection connection,
                                                 Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct)
    {
        var request = tsRequest.Value;
        var context = connection.ContextAs <EthereumWorkerContext>();

        try
        {
            switch (request.Method)
            {
            // V2/Nicehash Stratum Methods
            case EthereumStratumMethods.Subscribe:
                context.ProtocolVersion = 2;        // lock in protocol version

                await OnSubscribeAsync(connection, tsRequest);

                break;

            case EthereumStratumMethods.Authorize:
                EnsureProtocolVersion(context, 2);

                await OnAuthorizeAsync(connection, tsRequest);

                break;

            case EthereumStratumMethods.SubmitShare:
                EnsureProtocolVersion(context, 2);

                await OnSubmitAsync(connection, tsRequest, ct);

                break;

            case EthereumStratumMethods.ExtraNonceSubscribe:
                EnsureProtocolVersion(context, 2);

                // Pretend to support it even though we actually do not. Some miners drop the connection upon receiving an error from this
                await connection.RespondAsync(true, request.Id);

                break;

            // V1 Stratum methods
            case EthereumStratumMethods.SubmitLogin:
                context.ProtocolVersion = 1;        // lock in protocol version

                await OnSubmitLoginAsync(connection, tsRequest);

                break;

            case EthereumStratumMethods.GetWork:
                EnsureProtocolVersion(context, 1);

                await OnGetWorkAsync(connection, tsRequest);

                break;

            case EthereumStratumMethods.SubmitWork:
                EnsureProtocolVersion(context, 1);

                await OnSubmitAsync(connection, tsRequest, ct, true);

                break;

            case EthereumStratumMethods.SubmitHashrate:
                await connection.RespondAsync(true, request.Id);

                break;

            default:
                logger.Info(() => $"[{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);
        }
    }
Ejemplo n.º 6
0
        protected virtual async Task OnAuthorizeAsync(StratumConnection connection, Timestamped <JsonRpcRequest> tsRequest, CancellationToken ct)
        {
            var request = tsRequest.Value;

            if (request.Id == null)
            {
                throw new StratumException(StratumError.MinusOne, "missing request id");
            }

            var context       = connection.ContextAs <BitcoinWorkerContext>();
            var requestParams = request.ParamsAs <string[]>();
            var workerValue   = requestParams?.Length > 0 ? requestParams[0] : null;
            var password      = requestParams?.Length > 1 ? requestParams[1] : null;
            var passParts     = password?.Split(PasswordControlVarsSeparator);

            // extract worker/miner
            var split      = workerValue?.Split('.');
            var minerName  = split?.FirstOrDefault()?.Trim();
            var workerName = split?.Skip(1).FirstOrDefault()?.Trim() ?? string.Empty;

            // assumes that minerName is an address
            context.IsAuthorized = !string.IsNullOrEmpty(minerName) && 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
                if (clusterConfig.Nicehash?.EnableAutoDiff == true &&
                    context.UserAgent.Contains(NicehashConstants.NicehashUA, StringComparison.OrdinalIgnoreCase))
                {
                    // query current diff
                    var nicehashDiff = await nicehashService.GetStaticDiff(coin.Name, coin.GetAlgorithmName(), CancellationToken.None);

                    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 custom 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 });
                }
            }

            else
            {
                // respond
                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 for 60 sec");

                banManager.Ban(connection.RemoteEndpoint.Address, TimeSpan.FromSeconds(60));

                CloseConnection(connection);
            }
        }