예제 #1
0
        private void OnSuggestDifficulty(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <BitcoinWorkerContext>();

            client.Respond(true, request.Id);

            try
            {
                var requestedDiff = (double)Convert.ChangeType(request.Params, TypeCode.Double);

                var poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port];

                if (requestedDiff > poolEndpoint.Difficulty)
                {
                    context.SetDifficulty(requestedDiff);
                    client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { 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}");
            }
        }
예제 #2
0
        private MoneroJobParams CreateWorkerJob(StratumClient client)
        {
            var context = client.GetContextAs <MoneroWorkerContext>();
            var job     = new MoneroWorkerJob(NextJobId(), context.Difficulty);

            manager.PrepareWorkerJob(job, out var blob, out var target);

            // should never happen
            if (string.IsNullOrEmpty(blob) || string.IsNullOrEmpty(blob))
            {
                return(null);
            }

            var result = new MoneroJobParams
            {
                JobId  = job.Id,
                Blob   = blob,
                Target = target
            };

            // update context
            lock (context)
            {
                context.AddJob(job);
            }

            return(result);
        }
예제 #3
0
        protected virtual async Task OnSubmitAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <BitcoinWorkerContext>();

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

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

                context.LastActivity = clock.Now;

                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[]>();
                var poolEndpoint  = poolConfig.Ports[client.PoolEndpoint.Port];

                var share = await manager.SubmitShareAsync(client, requestParams, poolEndpoint.Difficulty);

                client.Respond(true, request.Id);
                messageBus.SendMessage(new ClientShare(client, share));

                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}");

                if (share.IsBlockCandidate)
                {
                    poolStats.LastPoolBlockTime = clock.Now;
                }

                context.Stats.ValidShares++;
                UpdateVarDiff(client);
            }

            catch (StratumException ex)
            {
                client.RespondError(ex.Code, ex.Message, request.Id, false);

                context.Stats.InvalidShares++;
                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Share rejected: {ex.Code}");

                ConsiderBan(client, context, poolConfig.Banning);
            }
        }
예제 #4
0
        private void OnGetWork(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <EthereumWorkerContext>();

            if (request.Id == null)
            {
                client.RespondError(StratumError.Other, "missing request id", request.Id);
                return;
            }

            object[] newJobParams = (object[])currentJobParams;
            var      header       = newJobParams[2];
            var      seed         = newJobParams[1];
            var      target       = EthereumUtils.GetTargetHex(new BigInteger(context.Difficulty * EthereumConstants.StratumDiffFactor));

            client.Respond(new object[] { header, seed, target }, request.Id);
            context.IsInitialWorkSent = true;

            var requestParams = request.ParamsAs <string[]>();
            var workerValue   = requestParams?.Length > 0 ? requestParams[0] : null;

            // log association
            if (!string.IsNullOrEmpty(context.WorkerName))
            {
                logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] recieved GetWork command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}");
            }
            else
            {
                logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] received GetWork command for {context.MinerName} from {client.RemoteEndpoint.Address}");
            }
        }
예제 #5
0
        private void OnSubscribe(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <EthereumWorkerContext>();

            if (request.Id == null)
            {
                client.RespondError(StratumError.Other, "missing request id", request.Id);
                return;
            }

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

            manager.PrepareWorker(client);

            var data = new object[]
            {
                new object[]
                {
                    EthereumStratumMethods.MiningNotify,
                    client.ConnectionId,
                    EthereumConstants.EthereumStratumVersion
                },
                context.ExtraNonce1
            }
            .ToArray();

            client.Respond(data, request.Id);

            // setup worker context
            context.IsSubscribed     = true;
            context.IsNiceHashClient = true;
            //context.UserAgent = requestParams[0].Trim();
        }
예제 #6
0
        protected void UpdateVarDiff(StratumClient client, bool isIdleUpdate = false)
        {
            var context = client.GetContextAs <WorkerContextBase>();

            if (context.VarDiff != null)
            {
                logger.Debug(() => $"[{LogCat}] [{client.ConnectionId}] Updating VarDiff" + (isIdleUpdate ? " [idle]" : string.Empty));

                VarDiffManager varDiffManager;
                var            poolEndpoint = poolConfig.Ports[client.PoolEndpoint.Port];

                lock (varDiffManagers)
                {
                    if (!varDiffManagers.TryGetValue(poolEndpoint, out varDiffManager))
                    {
                        varDiffManager = new VarDiffManager(poolEndpoint.VarDiff, clock);
                        varDiffManagers[poolEndpoint] = varDiffManager;
                    }
                }

                lock (context.VarDiff)
                {
                    StartVarDiffIdleUpdate(client, poolEndpoint);

                    var newDiff = varDiffManager.Update(context.VarDiff, context.Difficulty, isIdleUpdate);

                    if (newDiff != null)
                    {
                        logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] VarDiff update to {Math.Round(newDiff.Value, 2)}");

                        OnVarDiffUpdate(client, newDiff.Value);
                    }
                }
            }
        }
예제 #7
0
        protected override async Task OnRequestAsync(StratumClient client,
                                                     Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <MoneroWorkerContext>();

            switch (request.Method)
            {
            case MoneroStratumMethods.Login:
                OnLogin(client, tsRequest);
                break;

            case MoneroStratumMethods.GetJob:
                OnGetJob(client, tsRequest);
                break;

            case MoneroStratumMethods.Submit:
                await OnSubmitAsync(client, tsRequest);

                break;

            case MoneroStratumMethods.KeepAlive:
                // recognize activity
                context.LastActivity = clock.Now;
                break;

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

                client.RespondError(StratumError.Other, $"Unsupported request {request.Method}", request.Id);
                break;
            }
        }
예제 #8
0
        public override (Share Share, string BlockHex) ProcessShare(StratumClient worker, string extraNonce2, string nTime, string solution)
        {
            Assertion.RequiresNonNull(worker, nameof(worker));
            Assertion.Requires<ArgumentException>(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty");
            Assertion.Requires<ArgumentException>(!string.IsNullOrEmpty(nTime), $"{nameof(nTime)} must not be empty");
            Assertion.Requires<ArgumentException>(!string.IsNullOrEmpty(solution), $"{nameof(solution)} must not be empty");

            var context = worker.GetContextAs<BitcoinWorkerContext>();

                        if (nTime.Length != 8)
                throw new StratumException(StratumError.Other, "incorrect size of ntime");

            var nTimeInt = uint.Parse(nTime.HexToByteArray().ReverseArray().ToHexString(), NumberStyles.HexNumber);
            if (nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + 7200)
                throw new StratumException(StratumError.Other, "ntime out of range");

            var nonce = context.ExtraNonce1 + extraNonce2;

                        if (nonce.Length != 64)
                throw new StratumException(StratumError.Other, "incorrect size of extraNonce2");

                        if (solution.Length != 2694)
                throw new StratumException(StratumError.Other, "incorrect size of solution");

                        if (!RegisterSubmit(nonce, solution))
                throw new StratumException(StratumError.DuplicateShare, "duplicate share");

            return ProcessShareInternal(worker, nonce, nTimeInt, solution);
        }
예제 #9
0
        protected override void OnSubscribe(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <BitcoinWorkerContext>();

            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
            context.IsSubscribed = true;
            context.UserAgent    = requestParams?.Length > 0 ? requestParams[0].Trim() : null;
        }
예제 #10
0
        private void OnGetJob(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 getJobRequest = request.ParamsAs <MoneroGetJobRequest>();

            // validate worker
            if (client.ConnectionId != getJobRequest?.WorkerId || !context.IsAuthorized)
            {
                client.RespondError(StratumError.MinusOne, "unauthorized", request.Id);
                return;
            }

            // respond
            var job = CreateWorkerJob(client);

            client.Respond(job, request.Id);
        }
예제 #11
0
        protected virtual void OnSubscribe(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;

            if (request.Id == null)
            {
                client.RespondError(StratumError.Other, "missing request id", request.Id);
                return;
            }

            var context       = client.GetContextAs <BitcoinWorkerContext>();
            var requestParams = request.ParamsAs <string[]>();

            var data = new object[]
            {
                new object[]
                {
                    new object[] { BitcoinStratumMethods.SetDifficulty, client.ConnectionId },
                    new object[] { BitcoinStratumMethods.MiningNotify, client.ConnectionId }
                }
            }
            .Concat(manager.GetSubscriberData(client))
            .ToArray();

            client.Respond(data, request.Id);

            context.IsSubscribed = true;
            context.UserAgent    = requestParams?.Length > 0 ? requestParams[0].Trim() : null;

            client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty });
            client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams);
        }
예제 #12
0
        private void OnAuthorize(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <EthereumWorkerContext>();

            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()?.Trim();
            var workerName = split?.Skip(1).LastOrDefault()?.Trim();

            // assumes that workerName is an address
            context.IsAuthorized = !string.IsNullOrEmpty(minerName) && manager.ValidateAddress(minerName);
            context.MinerName    = minerName;
            context.WorkerName   = workerName;

            // respond
            client.Respond(context.IsAuthorized, request.Id);

            EnsureInitialWorkSent(client);

            // log association
            logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}");
        }
예제 #13
0
        protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string extraNonce2, uint nTime, uint nonce)
        {
            var context     = worker.GetContextAs <BitcoinWorkerContext>();
            var extraNonce1 = context.ExtraNonce1;

            var coinbase     = SerializeCoinbase(extraNonce1, extraNonce2);
            var coinbaseHash = coinbaseHasher.Digest(coinbase);

            var headerBytes = SerializeHeader(coinbaseHash, nTime, nonce);
            var headerHash  = headerHasher.Digest(headerBytes, (ulong)nTime);
            var headerValue = new uint256(headerHash);

            var shareDiff         = (double)new BigRational(BitcoinConstants.Diff1, headerHash.ToBigInteger()) * shareMultiplier;
            var stratumDifficulty = context.Difficulty;
            var ratio             = shareDiff / stratumDifficulty;

            var isBlockCandidate = headerValue <= blockTargetValue;

            if (!isBlockCandidate && ratio < 0.99)
            {
                if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue)
                {
                    ratio = shareDiff / context.PreviousDifficulty.Value;

                    if (ratio < 0.99)
                    {
                        throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                    }

                    stratumDifficulty = context.PreviousDifficulty.Value;
                }

                else
                {
                    throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                }
            }

            var result = new Share
            {
                BlockHeight       = BlockTemplate.Height,
                NetworkDifficulty = Difficulty * shareMultiplier,
                Difficulty        = stratumDifficulty,
            };

            if (isBlockCandidate)
            {
                result.IsBlockCandidate = true;
                result.BlockReward      = rewardToPool.ToDecimal(MoneyUnit.BTC);
                result.BlockHash        = blockHasher.Digest(headerBytes, nTime).ToHexString();

                var blockBytes = SerializeBlock(headerBytes, coinbase);
                var blockHex   = blockBytes.ToHexString();

                return(result, blockHex);
            }

            return(result, null);
        }
예제 #14
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];
            context.WorkerName = split.Length > 1 ? split[1] : null;
            context.UserAgent  = loginRequest.UserAgent;

            // extract paymentid
            var index = context.MinerName.IndexOf('#');

            if (index != -1)
            {
                context.PaymentId = context.MinerName.Substring(index + 1);
                context.MinerName = context.MinerName.Substring(0, index);
            }

            // 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;
            }

            // 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}");
        }
예제 #15
0
        private async Task <(Share Share, string nonce, string solution, string headerHash, string nTime)> ProcessShareInternal(
            StratumClient worker, string nonce, string nTime, string solution)
        {
            var context       = worker.GetContextAs <AionWorkerContext>();
            var solutionBytes = solution.HexToByteArray();

            // serialize block-header
            var headerBytes = SerializeHeader(nonce);

            // verify solution
            if (!equihash.Verify210(headerBytes, solutionBytes))
            {
                throw new StratumException(StratumError.Other, "invalid solution");
            }

            // hash block-header
            var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            var headerHash          = headerHasher.Digest(headerSolutionBytes);
            var headerHashReversed  = headerHash.ToReverseArray();
            var headerBigInt        = headerHashReversed.ToBigInteger();
            var target = new BigInteger(blockTarget.ToBytes());

            var isBlockCandidate = target > headerBigInt;

            // calc share-diff
            var stratumDifficulty = context.Difficulty > Difficulty ? Difficulty : context.Difficulty;
            var shareDiff         = stratumDifficulty;
            var ratio             = shareDiff / stratumDifficulty;

            var sentTargetInt  = new uint256(AionUtils.diffToTarget(context.Difficulty).HexToByteArray().ReverseArray());
            var sentTarget     = new BigInteger(sentTargetInt.ToBytes());
            var isLowDiffShare = sentTarget <= headerBigInt;

            if (isLowDiffShare)
            {
                throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
            }

            var result = new Share
            {
                BlockHeight                 = (long)BlockTemplate.Height,
                IpAddress                   = worker.RemoteEndpoint?.Address?.ToString(),
                Miner                       = context.MinerName,
                Worker                      = context.WorkerName,
                UserAgent                   = context.UserAgent,
                NetworkDifficulty           = Difficulty,
                Difficulty                  = stratumDifficulty,
                IsBlockCandidate            = isBlockCandidate,
                TransactionConfirmationData = headerHash.ToHexString(),
            };

            if (isBlockCandidate)
            {
                result.BlockReward = AionUtils.calculateReward((long)BlockTemplate.Height);
                result.BlockHash   = headerHashReversed.ToHexString();
            }

            return(result, nonce, solution, BlockTemplate.HeaderHash, nTime);
        }
예제 #16
0
        protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string nonce,
            uint nTime, string solution)
        {
            var context = worker.GetContextAs<BitcoinWorkerContext>();
            var solutionBytes = solution.HexToByteArray();

                        var headerBytes = SerializeHeader(nTime, nonce); 
                        if (!equihash.Verify(headerBytes, solutionBytes.Skip(3).ToArray()))                 throw new StratumException(StratumError.Other, "invalid solution");

                        var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            var headerHash = headerHasher.Digest(headerSolutionBytes, (ulong) nTime);
            var headerHashReversed = headerHash.ToReverseArray();
            var headerValue = new uint256(headerHash);

                        var shareDiff = (double) new BigRational(coinbaseTxConfig.Diff1b, headerHash.ToBigInteger()) * shareMultiplier;
            var stratumDifficulty = context.Difficulty;
            var ratio = shareDiff / stratumDifficulty;

                        var isBlockCandidate = headerValue <= blockTargetValue;

                        if (!isBlockCandidate && ratio < 0.99)
            {
                                if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue)
                {
                    ratio = shareDiff / context.PreviousDifficulty.Value;

                    if (ratio < 0.99)
                        throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");

                                        stratumDifficulty = context.PreviousDifficulty.Value;
                }

                else
                    throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
            }

            var result = new Share
            {
                BlockHeight = BlockTemplate.Height,
                NetworkDifficulty = Difficulty,
                Difficulty = stratumDifficulty,
            };

            if (isBlockCandidate)
            {
                result.IsBlockCandidate = true;
                result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);
                result.BlockHash = headerHashReversed.ToHexString();

                var blockBytes = SerializeBlock(headerBytes, coinbaseInitial, solutionBytes);
                var blockHex = blockBytes.ToHexString();

                return (result, blockHex);
            }

            return (result, null);
        }
예제 #17
0
        public async Task <Share> SubmitShareAsync(StratumClient worker,
                                                   MoneroSubmitShareRequest request, MoneroWorkerJob workerJob, double stratumDifficultyBase)
        {
            Contract.RequiresNonNull(worker, nameof(worker));
            Contract.RequiresNonNull(request, nameof(request));

            logger.LogInvoke(LogCat, new[] { worker.ConnectionId });
            var context = worker.GetContextAs <MoneroWorkerContext>();

            var job = currentJob;

            if (workerJob.Height != job?.BlockTemplate.Height)
            {
                throw new StratumException(StratumError.MinusOne, "block expired");
            }

            // validate & process
            var(share, blobHex, blobHash) = job.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker);

            // enrich share with common data
            share.PoolId            = poolConfig.Id;
            share.IpAddress         = worker.RemoteEndpoint.Address.ToString();
            share.Miner             = context.MinerName;
            share.Worker            = context.WorkerName;
            share.PayoutInfo        = context.PaymentId;
            share.UserAgent         = context.UserAgent;
            share.Source            = clusterConfig.ClusterName;
            share.NetworkDifficulty = job.BlockTemplate.Difficulty;
            share.Created           = clock.Now;

            // if block candidate, submit & check if accepted by network
            if (share.IsBlockCandidate)
            {
                logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight} [{blobHash.Substring(0, 6)}]");

                share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, blobHash);

                if (share.IsBlockCandidate)
                {
                    logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} [{blobHash.Substring(0, 6)}] submitted by {context.MinerName}");
                    blockSubmissionSubject.OnNext(Unit.Default);

                    share.TransactionConfirmationData = blobHash;
                }

                else
                {
                    // clear fields that no longer apply
                    share.TransactionConfirmationData = null;
                }
            }

            return(share);
        }
예제 #18
0
        protected override async Task OnAuthorizeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            await base.OnAuthorizeAsync(client, tsRequest);

            var context = client.GetContextAs <BitcoinWorkerContext>();

            if (context.IsAuthorized)
            {
                client.Notify(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) });
                client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams);
            }
        }
예제 #19
0
        private void OnSubmitLogin(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;
            var context = client.GetContextAs <EthereumWorkerContext>();

            if (request.Id == null)
            {
                client.RespondError(StratumError.Other, "missing request id", request.Id);
                return;
            }

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

            if (requestParams == null || requestParams.Length < 1 || requestParams.Any(string.IsNullOrEmpty))
            {
                client.RespondError(StratumError.MinusOne, "invalid request", request.Id);
                return;
            }

            manager.PrepareWorker(client);
            client.Respond(true, request.Id);

            // setup worker context
            context.IsSubscribed = true;
            context.IsAuthorized = true;
            context.MinerName    = requestParams[0].Trim();

            var workerValue = requestParams?.Length > 0 ? requestParams[0] : null;

            // extract worker/miner
            var workerParts = workerValue?.Split('.');
            var minerName   = workerParts?.Length > 0 ? workerParts[0].Trim() : null;
            var workerName  = workerParts?.Length > 1 ? workerParts[1].Trim() : null;

            if (!string.IsNullOrEmpty(minerName))
            {
                context.MinerName = minerName.ToLower();
            }
            if (!string.IsNullOrEmpty(workerName))
            {
                context.WorkerName = workerName;
            }

            // log association
            if (!string.IsNullOrEmpty(context.WorkerName))
            {
                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved SubmitLogin command for {context.MinerName}.{context.WorkerName} from {client.RemoteEndpoint.Address}");
            }
            else
            {
                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] recieved SubmitLogin command for {context.MinerName} from {client.RemoteEndpoint.Address}");
            }
        }
예제 #20
0
        protected virtual async Task OnAuthorizeAsync(StratumClient client, Timestamped <JsonRpcRequest> tsRequest)
        {
            var request = tsRequest.Value;

            if (request.Id == null)
            {
                client.RespondError(StratumError.Other, "missing request id", request.Id);
                return;
            }

            var context       = client.GetContextAs <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);

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

            context.IsAuthorized = !string.IsNullOrEmpty(minerName) && await manager.ValidateAddressAsync(minerName);

            context.MinerName  = minerName;
            context.WorkerName = workerName;

            if (context.IsAuthorized)
            {
                client.Respond(context.IsAuthorized, request.Id);

                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] = {workerValue} = {client.RemoteEndpoint.Address}");

                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; context.SetDifficulty(staticDiff.Value);

                    client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty });
                }
            }

            else
            {
                client.RespondError(StratumError.UnauthorizedWorker, "Authorization failed", request.Id, context.IsAuthorized);

                logger.Info(() => $"[{LogCat}] [{client.ConnectionId}] Banning unauthorized worker for 60 sec");

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

                DisconnectClient(client);
            }
        }
예제 #21
0
        protected override void DisconnectClient(StratumClient client)
        {
            var context = client.GetContextAs <WorkerContextBase>();

            if (context.VarDiff != null)
            {
                lock (context.VarDiff)
                {
                    context.VarDiff.Dispose();
                }
            }

            base.DisconnectClient(client);
        }
예제 #22
0
        protected override void OnVarDiffUpdate(StratumClient client, double newDiff)
        {
            var context = client.GetContextAs <BitcoinWorkerContext>();

            context.EnqueueNewDifficulty(newDiff);

            if (context.HasPendingDifficulty)
            {
                context.ApplyPendingDifficulty();

                client.Notify(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty });
                client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams);
            }
        }
예제 #23
0
        protected override void OnVarDiffUpdate(StratumClient client, double newDiff)
        {
            base.OnVarDiffUpdate(client, newDiff);

            var context = client.GetContextAs <EthereumWorkerContext>();

            if (context.HasPendingDifficulty)
            {
                context.ApplyPendingDifficulty();

                client.Notify(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty });
                client.Notify(EthereumStratumMethods.MiningNotify, currentJobParams);
            }
        }
예제 #24
0
        protected override void OnVarDiffUpdate(StratumClient client, double newDiff)
        {
            var context = client.GetContextAs <BitcoinWorkerContext>();

            context.EnqueueNewDifficulty(newDiff);

            // apply immediately and notify client
            if (context.HasPendingDifficulty)
            {
                context.ApplyPendingDifficulty();

                client.Notify(ZCashStratumMethods.SetTarget, new object[] { EncodeTarget(context.Difficulty) });
                client.Notify(BitcoinStratumMethods.MiningNotify, currentJobParams);
            }
        }
예제 #25
0
        private void EnsureInitialWorkSent(StratumClient client)
        {
            var context = client.GetContextAs <EthereumWorkerContext>();

            lock (context)
            {
                if (context.IsAuthorized && context.IsAuthorized && !context.IsInitialWorkSent)
                {
                    context.IsInitialWorkSent = true;

                    client.Notify(EthereumStratumMethods.SetDifficulty, new object[] { context.Difficulty });
                    client.Notify(EthereumStratumMethods.MiningNotify, currentJobParams);
                }
            }
        }
        public override object[] GetSubscriberData(StratumClient worker)
        {
            Assertion.RequiresNonNull(worker, nameof(worker));

            var context = worker.GetContextAs <BitcoinWorkerContext>();

            context.ExtraNonce1 = extraNonceProvider.Next();

            var responseData = new object[]
            {
                context.ExtraNonce1
            };

            return(responseData);
        }
예제 #27
0
        public async Task <Share> SubmitShareAsync(StratumClient worker,
                                                   string[] request, double stratumDifficulty, double stratumDifficultyBase)
        {
            Contract.RequiresNonNull(worker, nameof(worker));
            Contract.RequiresNonNull(request, nameof(request));

            logger.LogInvoke(LogCat, new[] { worker.ConnectionId });
            var context = worker.GetContextAs <AionWorkerContext>();

            var     miner = request[0];
            var     jobId = request[1];
            var     time  = request[2];
            var     nonce = request[3];
            var     soln  = request[4];
            AionJob job;

            // stale?
            lock (jobLock)
            {
                if (!validJobs.TryGetValue(jobId, out job))
                {
                    throw new StratumException(StratumError.MinusOne, "stale share");
                }
            }

            // validate & process
            var(share, fullNonceHex, solution, headerHash, nTime) = await job.ProcessShare(worker, nonce, time, soln);

            // enrich share with common data
            share.PoolId  = poolConfig.Id;
            share.Source  = clusterConfig.ClusterName;
            share.Created = clock.Now;

            // if block candidate, submit & check if accepted by network
            if (share.IsBlockCandidate)
            {
                logger.Info(() => $"[{LogCat}] Submitting block {share.BlockHeight}");

                share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, solution, nTime);

                if (share.IsBlockCandidate)
                {
                    logger.Info(() => $"[{LogCat}] Daemon accepted block {share.BlockHeight} submitted by {context.MinerName}");
                }
            }

            return(share);
        }
예제 #28
0
        public virtual object[] GetSubscriberData(StratumClient worker)
        {
            Assertion.RequiresNonNull(worker, nameof(worker));

            var context = worker.GetContextAs <BitcoinWorkerContext>();

            context.ExtraNonce1 = extraNonceProvider.Next();

            var responseData = new object[]
            {
                context.ExtraNonce1,
                BitcoinConstants.ExtranoncePlaceHolderLength - ExtranonceBytes,
            };

            return(responseData);
        }
예제 #29
0
        protected override void OnVarDiffUpdate(StratumClient client, double newDiff)
        {
            base.OnVarDiffUpdate(client, newDiff);

            // apply immediately and notify client
            var context = client.GetContextAs <MoneroWorkerContext>();

            if (context.HasPendingDifficulty)
            {
                context.ApplyPendingDifficulty();

                // re-send job
                var job = CreateWorkerJob(client);
                client.Notify(MoneroStratumMethods.JobNotify, job);
            }
        }
예제 #30
0
        protected override void OnVarDiffUpdate(StratumClient client, double newDiff)
        {
            base.OnVarDiffUpdate(client, newDiff);

            // apply immediately and notify client
            var context = client.GetContextAs <AionWorkerContext>();

            if (context.HasPendingDifficulty)
            {
                context.ApplyPendingDifficulty();

                // send job
                client.Notify(AionStratumMethods.SetDifficulty, new object[] { context.Difficulty });
                client.Notify(AionStratumMethods.MiningNotify, currentJobParams);
            }
        }