Esempio n. 1
0
 Uri BurstRequestUri(string requestType, QueryString parameters = default(QueryString))
 {
     parameters = parameters.Add("requestType", requestType);
     return(_uriFactory.GetUri(requestType, "/burst", parameters));
 }
Esempio n. 2
0
        public async Task <IActionResult> RespondAsync(string requestType)
        {
            Uri baseUri = null;

            switch (requestType)
            {
            case "submitNonce":
                if (!HttpMethods.IsPost(Request.Method))
                {
                    ModelState.AddModelError("", "This request must be sent as a POST request.");
                }
                if (!ulong.TryParse(GetQueryParameter("blockHeight"), out var blockHeight))
                {
                    ModelState.AddModelError("blockHeight", "Your miner must send blockHeight with the request to mine in this pool.");
                }
                if (!ulong.TryParse(GetQueryParameter("nonce"), out var nonce))
                {
                    ModelState.AddModelError("nonce", "Nonce is invalid or missing, a valid nonce is required.");
                }
                ulong? accountId    = null;
                string secretPhrase = GetQueryParameter("secretPhrase");
                if (ulong.TryParse(GetQueryParameter("accountId"), out var accountIdTemp))
                {
                    accountId = accountIdTemp;
                }
                else if (HasParameter("accountId"))
                {
                    ModelState.AddModelError("accountId", "Invalid account ID");
                }

                if (accountId == null && secretPhrase == null)
                {
                    ModelState.AddModelError(nameof(accountId), "Account ID or secretPhrase is required.");
                    ModelState.AddModelError(nameof(secretPhrase), "Account ID or secretPhrase is required.");
                }

                if (!ModelState.IsValid)
                {
                    return(BadRequest(ModelState));
                }
                var block = await _blockHeightTracker.GetCurrentBlockHeightAsync();

                if (blockHeight > 0)
                {
                    bool firstWait = true;
                    while (true)
                    {
                        block = await _blockHeightTracker.GetCurrentBlockHeightAsync();

                        if (!ulong.TryParse(block.Height, out var newHeight))
                        {
                            await Task.Delay(250, HttpContext.RequestAborted).ConfigureAwait(false);

                            continue;
                        }
                        if (newHeight == blockHeight)
                        {
                            break;
                        }
                        else if (newHeight > blockHeight || (newHeight + _configuration.GetSection("Pool").GetValue <ulong>("MaximumPremineBlocks", 0L)) < blockHeight)
                        {
                            return(Ok(new
                            {
                                error = $"Your deadline is for a different block, your block: {blockHeight}, current block: {newHeight}"
                            }));
                        }
                        else
                        {
                            await Task.Delay(100);
                        }
                        if (firstWait)
                        {
                            _logger.LogInformation($"Client {HttpContext.Connection.RemoteIpAddress} submitted a nonce for a future block, blocking client until block {blockHeight} appears on the network.");
                            firstWait = false;
                        }
                    }
                }

                var queryString = new QueryString();
                queryString = queryString
                              .Add("requestType", "submitNonce")
                              .Add("nonce", nonce.ToString())
                              .Add("blockHeight", blockHeight.ToString());
                if (accountId != null)
                {
                    queryString = queryString.Add("accountId", accountId.Value.ToString());
                }
                var poolSecret = GetPoolSecretPhrase();
                secretPhrase = secretPhrase ?? poolSecret;

                if (!string.IsNullOrWhiteSpace(secretPhrase))
                {
                    queryString = queryString.Add("secretPhrase", secretPhrase ?? poolSecret);
                }
                bool isPoolUser = string.IsNullOrWhiteSpace(secretPhrase) || (!string.IsNullOrWhiteSpace(poolSecret) && string.Equals(poolSecret, secretPhrase));
                try
                {
                    var response = await _httpClient.SendAsync(CreateProxyHttpRequest(HttpContext, _uriFactory.GetUri(requestType, "/burst", Request.QueryString)), HttpContext.RequestAborted).ConfigureAwait(false);

                    var responseStringJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                    var responseObject = JObject.Parse(responseStringJson);
                    var newContent     = new StringContent(responseStringJson);
                    newContent.Headers.Clear();
                    foreach (var header in response.Content.Headers)
                    {
                        newContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
                    }
                    response.Content = newContent;
                    if (accountId != null && responseObject.TryGetValue("deadline", StringComparison.OrdinalIgnoreCase, out var deadlineToken))
                    {
                        var deadline = deadlineToken.ToObject <ulong>();
                        var shares   = _shareCalculator.GetShares(deadline, ulong.Parse(block.Height));
                        if (isPoolUser)
                        {
                            _logger.LogInformation($"{accountId} earned {shares} shares.");
                            await _shareTracker.RecordSharesAsync(accountId.Value, long.Parse(block.Height), shares, nonce, deadline).ConfigureAwait(false);
                        }
                        else
                        {
                            _logger.LogInformation($"{accountId} earned {shares} shares, but they are not a member of the pool. Not recording.");
                        }
                    }
                    return(ResponseMessage(response));
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Failed submit nonce to server, or failed to record shares.");
                    return(BadGateway());
                }

            default:
                baseUri = _uriFactory.GetUri(requestType, "/burst", Request.QueryString);
                var request = CreateProxyHttpRequest(Request.HttpContext, baseUri);
                try
                {
                    var response = await _httpClient.SendAsync(request, Request.HttpContext.RequestAborted);

                    return(ResponseMessage(response));
                }
                catch
                {
                    return(BadGateway());
                }
            }
        }