Пример #1
0
        public ShareRecorder(IConnectionFactory cf, IMapper mapper,
                             JsonSerializerSettings jsonSerializerSettings,
                             IShareRepository shareRepo, IBlockRepository blockRepo,
                             IMasterClock clock,
                             IMessageBus messageBus,
                             NotificationService notificationService)
        {
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(mapper, nameof(mapper));
            Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
            Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
            Contract.RequiresNonNull(jsonSerializerSettings, nameof(jsonSerializerSettings));
            Contract.RequiresNonNull(clock, nameof(clock));
            Contract.RequiresNonNull(messageBus, nameof(messageBus));
            Contract.RequiresNonNull(notificationService, nameof(notificationService));

            this.cf     = cf;
            this.mapper = mapper;
            this.jsonSerializerSettings = jsonSerializerSettings;
            this.clock               = clock;
            this.messageBus          = messageBus;
            this.notificationService = notificationService;

            this.shareRepo = shareRepo;
            this.blockRepo = blockRepo;

            BuildFaultHandlingPolicy();
        }
Пример #2
0
        /// <summary>
        /// Executes the request against all configured demons and returns their responses as an array
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="method"></param>
        /// <param name="payload"></param>
        /// <returns></returns>
        public async Task <DaemonResponse <TResponse>[]> ExecuteCmdAllAsync <TResponse>(string method,
                                                                                        object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null)
            where TResponse : class
        {
            Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty");

            logger.LogInvoke(new[] { method });

            var tasks = endPoints.Select(endPoint => BuildRequestTask(endPoint, method, payload, payloadJsonSerializerSettings)).ToArray();

            try
            {
                await Task.WhenAll(tasks);
            }

            catch (Exception)
            {
                // ignored
            }

            var results = tasks.Select((x, i) => MapDaemonResponse <TResponse>(i, x))
                          .ToArray();

            return(results);
        }
Пример #3
0
        protected PayoutHandlerBase(IConnectionFactory cf, IMapper mapper,
                                    IShareRepository shareRepo,
                                    IBlockRepository blockRepo,
                                    IBalanceRepository balanceRepo,
                                    IPaymentRepository paymentRepo,
                                    IMasterClock clock,
                                    NotificationService notificationService)
        {
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(mapper, nameof(mapper));
            Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
            Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
            Contract.RequiresNonNull(balanceRepo, nameof(balanceRepo));
            Contract.RequiresNonNull(paymentRepo, nameof(paymentRepo));
            Contract.RequiresNonNull(clock, nameof(clock));
            Contract.RequiresNonNull(notificationService, nameof(notificationService));

            this.cf                  = cf;
            this.mapper              = mapper;
            this.clock               = clock;
            this.shareRepo           = shareRepo;
            this.blockRepo           = blockRepo;
            this.balanceRepo         = balanceRepo;
            this.paymentRepo         = paymentRepo;
            this.notificationService = notificationService;

            BuildFaultHandlingPolicy();
        }
        public void Ban(IPAddress address, TimeSpan duration)
        {
            Contract.RequiresNonNull(address, nameof(address));
            Contract.Requires <ArgumentException>(duration.TotalMilliseconds > 0, $"{nameof(duration)} must not be empty");

            cache.Set(address.ToString(), string.Empty, duration);
        }
Пример #5
0
        public void Configure(DaemonEndpointConfig[] endPoints, string digestAuthRealm = null)
        {
            Contract.RequiresNonNull(endPoints, nameof(endPoints));
            Contract.Requires <ArgumentException>(endPoints.Length > 0, $"{nameof(endPoints)} must not be empty");

            this.endPoints = endPoints;

            // create one HttpClient instance per endpoint that carries the associated credentials
            httpClients = endPoints.ToDictionary(endpoint => endpoint, endpoint =>
            {
                var handler = new HttpClientHandler
                {
                    Credentials            = new NetworkCredential(endpoint.User, endpoint.Password),
                    PreAuthenticate        = true,
                    AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
                };

                if (endpoint.Ssl && !endpoint.ValidateCert)
                {
                    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
                    handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true;
                }

                return(new HttpClient(handler));
            });
        }
Пример #6
0
        protected PoolBase(IComponentContext ctx,
                           JsonSerializerSettings serializerSettings,
                           IConnectionFactory cf,
                           IStatsRepository statsRepo,
                           IMapper mapper,
                           IMasterClock clock,
                           IMessageBus messageBus,
                           NotificationService notificationService) : base(ctx, clock)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));
            Contract.RequiresNonNull(serializerSettings, nameof(serializerSettings));
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(statsRepo, nameof(statsRepo));
            Contract.RequiresNonNull(mapper, nameof(mapper));
            Contract.RequiresNonNull(clock, nameof(clock));
            Contract.RequiresNonNull(messageBus, nameof(messageBus));
            Contract.RequiresNonNull(notificationService, nameof(notificationService));

            this.serializerSettings = serializerSettings;
            this.cf                  = cf;
            this.statsRepo           = statsRepo;
            this.mapper              = mapper;
            this.messageBus          = messageBus;
            this.notificationService = notificationService;
        }
Пример #7
0
        protected StratumServer(IComponentContext ctx, IMasterClock clock)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));
            Contract.RequiresNonNull(clock, nameof(clock));

            this.ctx   = ctx;
            this.clock = clock;
        }
        public bool IsBanned(IPAddress address)
        {
            Contract.RequiresNonNull(address, nameof(address));

            var result = cache.Get(address.ToString());

            return(result != null);
        }
Пример #9
0
        public virtual void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig)
        {
            Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
            Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig));

            logger             = LogUtil.GetPoolScopedLogger(typeof(PoolBase), poolConfig);
            this.poolConfig    = poolConfig;
            this.clusterConfig = clusterConfig;
        }
Пример #10
0
        public void Start(ClusterConfig clusterConfig)
        {
            Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig));
            this.clusterConfig = clusterConfig;

            logger.Info(() => $"Launching ...");
            StartApi(clusterConfig);
            StartAdminApi(clusterConfig);
        }
        public bool ValidateAddress(string address)
        {
            Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty");

            if (EthereumConstants.ZeroHashPattern.IsMatch(address) ||
                !EthereumConstants.ValidAddressPattern.IsMatch(address))
                return false;

            return true;
        }
Пример #12
0
        public DaemonClient(JsonSerializerSettings serializerSettings)
        {
            Contract.RequiresNonNull(serializerSettings, nameof(serializerSettings));

            this.serializerSettings = serializerSettings;

            serializer = new JsonSerializer
            {
                ContractResolver = serializerSettings.ContractResolver
            };
        }
Пример #13
0
        public byte[] WithFirst(byte[] first)
        {
            Contract.RequiresNonNull(first, nameof(first));

            foreach (var step in Steps)
            {
                first = DoubleDigest(first.Concat(step)).ToArray();
            }

            return(first);
        }
Пример #14
0
        public async Task StartAsync(CancellationToken ct)
        {
            Contract.RequiresNonNull(poolConfig, nameof(poolConfig));

            logger.Info(() => $"[{LogCat}] Launching ...");

            await StartDaemonAsync(ct);
            await EnsureDaemonsSynchedAsync(ct);
            await PostStartInitAsync(ct);

            logger.Info(() => $"[{LogCat}] Online");
        }
Пример #15
0
        /// <summary>
        /// Executes the requests against all configured demons and returns the first successful response array
        /// </summary>
        /// <returns></returns>
        public async Task <DaemonResponse <JToken>[]> ExecuteBatchAnyAsync(params DaemonCmd[] batch)
        {
            Contract.RequiresNonNull(batch, nameof(batch));

            logger.LogInvoke(batch.Select(x => x.Method).ToArray());

            var tasks = endPoints.Select(endPoint => BuildBatchRequestTask(endPoint, batch)).ToArray();

            var taskFirstCompleted = await Task.WhenAny(tasks);

            var result = MapDaemonBatchResponse(0, taskFirstCompleted);

            return(result);
        }
Пример #16
0
        public ApiServer(
            IMapper mapper,
            IConnectionFactory cf,
            IBlockRepository blocksRepo,
            IPaymentRepository paymentsRepo,
            IStatsRepository statsRepo,
            IShareRepository shareRepo,
            IMasterClock clock,
            IMessageBus messageBus)
        {
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(statsRepo, nameof(statsRepo));
            Contract.RequiresNonNull(statsRepo, nameof(statsRepo));
            Contract.RequiresNonNull(blocksRepo, nameof(blocksRepo));
            Contract.RequiresNonNull(paymentsRepo, nameof(paymentsRepo));
            Contract.RequiresNonNull(mapper, nameof(mapper));
            Contract.RequiresNonNull(clock, nameof(clock));
            Contract.RequiresNonNull(messageBus, nameof(messageBus));

            this.cf           = cf;
            this.statsRepo    = statsRepo;
            this.shareRepo    = shareRepo;
            this.blocksRepo   = blocksRepo;
            this.paymentsRepo = paymentsRepo;
            this.mapper       = mapper;
            this.clock        = clock;

            messageBus.Listen <BlockNotification>().Subscribe(OnBlockNotification);

            requestMap = new Dictionary <Regex, Func <HttpContext, Match, Task> >
            {
                { new Regex("^/api/pools$", RegexOptions.Compiled), GetPoolInfosAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/performance$", RegexOptions.Compiled), GetPoolPerformanceAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/miners$", RegexOptions.Compiled), PagePoolMinersAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/blocks$", RegexOptions.Compiled), PagePoolBlocksPagedAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/payments$", RegexOptions.Compiled), PagePoolPaymentsAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)$", RegexOptions.Compiled), GetPoolInfoAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/miners/(?<address>[^/]+)/payments$", RegexOptions.Compiled), PageMinerPaymentsAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/miners/(?<address>[^/]+)/balancechanges$", RegexOptions.Compiled), PageMinerBalanceChangesAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/miners/(?<address>[^/]+)/performance$", RegexOptions.Compiled), GetMinerPerformanceAsync },
                { new Regex("^/api/pools/(?<poolId>[^/]+)/miners/(?<address>[^/]+)$", RegexOptions.Compiled), GetMinerInfoAsync },
            };

            requestMapAdmin = new Dictionary <Regex, Func <HttpContext, Match, Task> >
            {
                { new Regex("^/api/admin/forcegc$", RegexOptions.Compiled), HandleForceGcAsync },
                { new Regex("^/api/admin/stats/gc$", RegexOptions.Compiled), HandleGcStatsAsync },
            };
        }
        public SoloPaymentScheme(IConnectionFactory cf,
                                 IShareRepository shareRepo,
                                 IBlockRepository blockRepo,
                                 IBalanceRepository balanceRepo)
        {
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
            Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
            Contract.RequiresNonNull(balanceRepo, nameof(balanceRepo));

            this.cf          = cf;
            this.shareRepo   = shareRepo;
            this.blockRepo   = blockRepo;
            this.balanceRepo = balanceRepo;
        }
Пример #18
0
        /// <summary>
        /// Executes the request against all configured demons and returns the first successful response
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="method"></param>
        /// <param name="payload"></param>
        /// <returns></returns>
        public async Task <DaemonResponse <TResponse> > ExecuteCmdSingleAsync <TResponse>(string method, object payload = null,
                                                                                          JsonSerializerSettings payloadJsonSerializerSettings = null)
            where TResponse : class
        {
            Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty");

            logger.LogInvoke(new[] { method });

            var   task = BuildRequestTask(endPoints.First(), method, payload, payloadJsonSerializerSettings);
            await task;

            var result = MapDaemonResponse <TResponse>(0, task);

            return(result);
        }
Пример #19
0
        /// <summary>
        /// </summary>
        /// <example>
        /// python: http://runnable.com/U3jqtyYUmAUxtsSS/bitcoin-block-merkle-root-python
        /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/merkleTree.js#L9
        /// </example>
        /// <param name="hashList"></param>
        /// <returns></returns>
        private IList <byte[]> CalculateSteps(IEnumerable <byte[]> hashList)
        {
            Contract.RequiresNonNull(hashList, nameof(hashList));

            var steps = new List <byte[]>();

            var L = new List <byte[]> {
                null
            };

            L.AddRange(hashList);

            var startL = 2;
            var Ll     = L.Count;

            if (Ll > 1)
            {
                while (true)
                {
                    if (Ll == 1)
                    {
                        break;
                    }

                    steps.Add(L[1]);

                    if (Ll % 2 == 1)
                    {
                        L.Add(L[L.Count - 1]);
                    }

                    var Ld = new List <byte[]>();

                    //foreach (int i in Range.From(startL).To(Ll).WithStepSize(2))
                    for (var i = startL; i < Ll; i += 2)
                    {
                        Ld.Add(MerkleJoin(L[i], L[i + 1]));
                    }

                    L = new List <byte[]> {
                        null
                    };
                    L.AddRange(Ld);
                    Ll = L.Count;
                }
            }
            return(steps);
        }
Пример #20
0
        /// <summary>
        /// Executes the request against all configured demons and returns the first successful response
        /// </summary>
        /// <typeparam name="TResponse"></typeparam>
        /// <returns></returns>
        public async Task <DaemonResponse <TResponse> > ExecuteCmdAnyAsync <TResponse>(string method, object payload = null,
                                                                                       JsonSerializerSettings payloadJsonSerializerSettings = null, bool throwOnError = false)
            where TResponse : class
        {
            Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty");

            logger.LogInvoke(new[] { method });

            var tasks = endPoints.Select(endPoint => BuildRequestTask(endPoint, method, payload, payloadJsonSerializerSettings)).ToArray();

            var taskFirstCompleted = await Task.WhenAny(tasks);

            var result = MapDaemonResponse <TResponse>(0, taskFirstCompleted, throwOnError);

            return(result);
        }
        public PPLNSPaymentScheme(IConnectionFactory cf,
                                  IShareRepository shareRepo,
                                  IBlockRepository blockRepo,
                                  IBalanceRepository balanceRepo)
        {
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
            Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
            Contract.RequiresNonNull(balanceRepo, nameof(balanceRepo));

            this.cf          = cf;
            this.shareRepo   = shareRepo;
            this.blockRepo   = blockRepo;
            this.balanceRepo = balanceRepo;

            BuildFaultHandlingPolicy();
        }
        public EthereumPayoutHandler(
            IComponentContext ctx,
            IConnectionFactory cf,
            IMapper mapper,
            IShareRepository shareRepo,
            IBlockRepository blockRepo,
            IBalanceRepository balanceRepo,
            IPaymentRepository paymentRepo,
            IMasterClock clock,
            NotificationService notificationService) :
            base(cf, mapper, shareRepo, blockRepo, balanceRepo, paymentRepo, clock, notificationService)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));
            Contract.RequiresNonNull(balanceRepo, nameof(balanceRepo));
            Contract.RequiresNonNull(paymentRepo, nameof(paymentRepo));

            this.ctx = ctx;
        }
Пример #23
0
        public virtual async Task StartAsync(CancellationToken ct)
        {
            Contract.RequiresNonNull(poolConfig, nameof(poolConfig));

            logger.Info(() => $"[{LogCat}] Launching ...");

            try
            {
                SetupBanning(clusterConfig);
                await SetupJobManager(ct);

                InitStats();

                if (poolConfig.EnableInternalStratum == true)
                {
                    var ipEndpoints = poolConfig.Ports.Keys
                                      .Select(port => PoolEndpoint2IPEndpoint(port, poolConfig.Ports[port]))
                                      .ToArray();

                    StartListeners(poolConfig.Id, ipEndpoints);
                }

                logger.Info(() => $"[{LogCat}] Online");
                OutputPoolInfo();
            }

            catch (PoolStartupAbortException)
            {
                // just forward these
                throw;
            }

            catch (TaskCanceledException)
            {
                // just forward these
                throw;
            }

            catch (Exception ex)
            {
                logger.Error(ex);
                throw;
            }
        }
        public EthereumJobManager(
            IComponentContext ctx,
            NotificationService notificationService,
            IMasterClock clock,
            JsonSerializerSettings serializerSettings) :
            base(ctx)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));
            Contract.RequiresNonNull(notificationService, nameof(notificationService));
            Contract.RequiresNonNull(clock, nameof(clock));

            this.clock = clock;
            this.notificationService = notificationService;

            serializer = new JsonSerializer
            {
                ContractResolver = serializerSettings.ContractResolver
            };
        }
Пример #25
0
        public PayoutManager(IComponentContext ctx,
                             IConnectionFactory cf,
                             IBlockRepository blockRepo,
                             IShareRepository shareRepo,
                             IBalanceRepository balanceRepo,
                             NotificationService notificationService)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));
            Contract.RequiresNonNull(cf, nameof(cf));
            Contract.RequiresNonNull(blockRepo, nameof(blockRepo));
            Contract.RequiresNonNull(shareRepo, nameof(shareRepo));
            Contract.RequiresNonNull(balanceRepo, nameof(balanceRepo));
            Contract.RequiresNonNull(notificationService, nameof(notificationService));

            this.ctx                 = ctx;
            this.cf                  = cf;
            this.blockRepo           = blockRepo;
            this.shareRepo           = shareRepo;
            this.balanceRepo         = balanceRepo;
            this.notificationService = notificationService;
        }
        public async Task <Block[]> ClassifyBlocksAsync(Block[] blocks)
        {
            Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
            Contract.RequiresNonNull(blocks, nameof(blocks));

            var pageSize   = 100;
            var pageCount  = (int)Math.Ceiling(blocks.Length / (double)pageSize);
            var blockCache = new Dictionary <long, DaemonResponses.Block>();
            var result     = new List <Block>();

            for (var i = 0; i < pageCount; i++)
            {
                // get a page full of blocks
                var page = blocks
                           .Skip(i * pageSize)
                           .Take(pageSize)
                           .ToArray();

                // get latest block
                var latestBlockResponses = await daemon.ExecuteCmdAllAsync <DaemonResponses.Block>(EthCommands.GetBlockByNumber, new[] { (object)"latest", true });

                var latestBlockHeight = latestBlockResponses.First(x => x.Error == null && x.Response?.Height != null).Response.Height.Value;

                // execute batch
                var blockInfos = await FetchBlocks(blockCache, page.Select(block => (long)block.BlockHeight).ToArray());

                for (var j = 0; j < blockInfos.Length; j++)
                {
                    var blockInfo = blockInfos[j];
                    var block     = page[j];

                    // extract confirmation data from stored block
                    var mixHash = block.TransactionConfirmationData.Split(":").First();
                    var nonce   = block.TransactionConfirmationData.Split(":").Last();

                    // update progress
                    block.ConfirmationProgress = Math.Min(1.0d, (double)(latestBlockHeight - block.BlockHeight) / EthereumConstants.MinConfimations);
                    result.Add(block);

                    // is it block mined by us?
                    if (blockInfo.Miner == poolConfig.Address)
                    {
                        // mature?
                        if (latestBlockHeight - block.BlockHeight >= EthereumConstants.MinConfimations)
                        {
                            block.Status = BlockStatus.Confirmed;
                            block.ConfirmationProgress = 1;
                            block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward

                            if (extraConfig?.KeepUncles == false)
                            {
                                block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards
                            }
                            if (extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0)
                            {
                                block.Reward += await GetTxRewardAsync(blockInfo); // tx fees
                            }
                            logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}");
                        }

                        continue;
                    }

                    // search for a block containing our block as an uncle by checking N blocks in either direction
                    var heightMin = block.BlockHeight - BlockSearchOffset;
                    var heightMax = Math.Min(block.BlockHeight + BlockSearchOffset, latestBlockHeight);
                    var range     = new List <long>();

                    for (var k = heightMin; k < heightMax; k++)
                    {
                        range.Add((long)k);
                    }

                    // execute batch
                    var blockInfo2s = await FetchBlocks(blockCache, range.ToArray());

                    foreach (var blockInfo2 in blockInfo2s)
                    {
                        // don't give up yet, there might be an uncle
                        if (blockInfo2.Uncles.Length > 0)
                        {
                            // fetch all uncles in a single RPC batch request
                            var uncleBatch = blockInfo2.Uncles.Select((x, index) => new DaemonCmd(EthCommands.GetUncleByBlockNumberAndIndex,
                                                                                                  new[] { blockInfo2.Height.Value.ToStringHexWithPrefix(), index.ToStringHexWithPrefix() }))
                                             .ToArray();

                            logger.Info(() => $"[{LogCategory}] Fetching {blockInfo2.Uncles.Length} uncles for block {blockInfo2.Height}");

                            var uncleResponses = await daemon.ExecuteBatchAnyAsync(uncleBatch);

                            logger.Info(() => $"[{LogCategory}] Fetched {uncleResponses.Count(x => x.Error == null && x.Response != null)} uncles for block {blockInfo2.Height}");

                            var uncle = uncleResponses.Where(x => x.Error == null && x.Response != null)
                                        .Select(x => x.Response.ToObject <DaemonResponses.Block>())
                                        .FirstOrDefault(x => x.Miner == poolConfig.Address);

                            if (uncle != null)
                            {
                                // mature?
                                if (latestBlockHeight - uncle.Height.Value >= EthereumConstants.MinConfimations)
                                {
                                    block.Status = BlockStatus.Confirmed;
                                    block.ConfirmationProgress = 1;
                                    block.Reward      = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value);
                                    block.BlockHeight = uncle.Height.Value;
                                    block.Type        = EthereumConstants.BlockTypeUncle;

                                    logger.Info(() => $"[{LogCategory}] Unlocked uncle for block {blockInfo2.Height.Value} at height {uncle.Height.Value} worth {FormatAmount(block.Reward)}");
                                }

                                else
                                {
                                    logger.Info(() => $"[{LogCategory}] Got immature matching uncle for block {blockInfo2.Height.Value}. Will try again.");
                                }

                                break;
                            }
                        }
                    }

                    if (block.Status == BlockStatus.Pending && block.ConfirmationProgress > 0.10)
                    {
                        // we've lost this one
                        block.Status = BlockStatus.Orphaned;
                        block.Reward = 0;
                    }
                }
            }

            return(result.ToArray());
        }
        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<EthereumWorkerContext>();

            EthereumJob job;
            string miner, jobId, nonce = string.Empty;
            if (context.IsNiceHashClient)
            {
                jobId = request[1];
                nonce = request[2];
                miner = request[0];

                // stale?
                lock (jobLock)
                {
                    var jobResult = validJobs.Where(x => x.Value.Id == jobId).FirstOrDefault();
                    if (jobResult.Value == null)
                        throw new StratumException(StratumError.MinusOne, "stale share for job: " + jobId + "and nonce " + nonce);

                    job = jobResult.Value;
                }
            }
            else
            {
                jobId = request[1];
                nonce = request[0];

                // stale?
                lock (jobLock)
                {
                    var jobResult = validJobs.Where(x => x.Value.BlockTemplate.Header == jobId).FirstOrDefault();
                    if (jobResult.Value == null)
                        throw new StratumException(StratumError.MinusOne, "stale share for job: " + jobId + "and nonce " + nonce);

                    job = jobResult.Value;
                }
            }

            // validate & process
            var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, nonce, ethash);

            // enrich share with common data
            share.PoolId = poolConfig.Id;
            share.NetworkDifficulty = BlockchainStats.NetworkDifficulty;
            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.StartsWith("0x") ? fullNonceHex : $"0x{fullNonceHex}", headerHash, mixHash);

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

            return share;
        }
Пример #28
0
        protected JobManagerBase(IComponentContext ctx)
        {
            Contract.RequiresNonNull(ctx, nameof(ctx));

            this.ctx = ctx;
        }