예제 #1
0
        private void BlockPoller(object stats)
        {
            if (_jobTracker.Current == null) // make sure we already have succesfully created a previous job.
            {
                return;                      // else just skip block-polling until we do so.
            }
            try
            {
                var blockTemplate = _daemonClient.GetBlockTemplate(_poolConfig.Coin.Options.BlockTemplateModeRequired);

                if (blockTemplate.Height == _jobTracker.Current.Height) // if network reports the same block-height with our current job.
                {
                    return;                                             // just return.
                }
                _logger.Verbose("A new block {0} emerged in network, rebroadcasting new work", blockTemplate.Height);
                CreateAndBroadcastNewJob(false); // broadcast a new job.
            }
            catch (RpcException) { } // just skip any exceptions caused by the block-pooler queries.

            _blockPollerTimer.Change(_poolConfig.Job.BlockRefreshInterval, Timeout.Infinite); // reset the block-poller timer so we can keep polling.
        }
예제 #2
0
        private void BlockPoller(object stats)
        {
            if (_jobTracker.Current == null)
            {
                // CreateAndBroadcastNewJob(false);
                // make sure we already have succesfully created a previous job.
                return; // else just skip block-polling until we do so.
            }

            try
            {
                _logger.Verbose("Trying to get new BlockTemplate... (1)");

                var blockTemplate = _daemonClient.GetBlockTemplate(_poolConfig.Coin.Options.BlockTemplateModeRequired);

                MetronomeTracker.CurrentMetronomeHash = blockTemplate.MetronomeHash;

                if (metronomeActive && BigInteger.Parse(blockTemplate.MetronomeHash, System.Globalization.NumberStyles.HexNumber).IsZero)
                {
                    if (_jobTracker.Current != null)
                    {
                        _jobTracker.Current.CleanJobs = true;
                        SendSleepSignal();
                    }
                    return;
                }

                _logger.Information("NEW Metro Hash: {0}", blockTemplate.MetronomeHash);

                if (blockTemplate.Height == _jobTracker.Current.Height) // if network reports the same block-height with our current job.
                {
                    return;                                             // just return.
                }
                _logger.Verbose("A new block {0} emerged in network, rebroadcasting new work", blockTemplate.Height);
                CreateAndBroadcastNewJob(false); // broadcast a new job.
            }
            catch (RpcException) { } // just skip any exceptions caused by the block-pooler queries.

            _blockPollerTimer.Change(_poolConfig.Job.BlockRefreshInterval, Timeout.Infinite); // reset the block-poller timer so we can keep polling.
        }
예제 #3
0
        public void Recache()
        {
            try // read getinfo() based data.
            {
                var info = _daemonClient.GetInfo();

                // read data.
                CoinVersion     = info.Version;
                ProtocolVersion = info.ProtocolVersion;
                WalletVersion   = info.WalletVersion;
                Testnet         = info.Testnet;
                Connections     = info.Connections;
                Errors          = info.Errors;

                // check if our network connection is healthy.
                Healthy = Connections >= 0 && string.IsNullOrEmpty(Errors);
            }
            catch (RpcException e)
            {
                _logger.Error("Can not read getinfo(): {0:l}", e.Message);
                Healthy = false; // set healthy status to false as we couldn't get a reply.
            }

            try // read getmininginfo() based data.
            {
                var miningInfo = _daemonClient.GetMiningInfo();

                // read data.
                Hashrate   = miningInfo.NetworkHashPerSec;
                Difficulty = miningInfo.Difficulty;
                Round      = miningInfo.Blocks + 1;
            }
            catch (RpcException e)
            {
                _logger.Error("Can not read getmininginfo(): {0:l}", e.Message);
                Hashrate   = 0;
                Difficulty = 0;
                Round      = -1;
                Healthy    = false; // set healthy status to false as we couldn't get a reply.
            }

            try // read getblocktemplate() based data.
            {
                var blockTemplate = _daemonClient.GetBlockTemplate(_poolConfig.Coin.Options.BlockTemplateModeRequired);
                Reward = (UInt64)blockTemplate.Coinbasevalue / 100000000; // coinbasevalue is in satoshis, convert it to actual coins.
            }
            catch (RpcException e)
            {
                _logger.Error("Can not read getblocktemplate(): {0:l}", e.Message);
                Reward = 0;
            }
        }
예제 #4
0
        private bool SubmitBlock(IShare share)
        {
            // TODO: we should try different submission techniques and probably more then once: https://github.com/ahmedbodi/stratum-mining/blob/master/lib/bitcoin_rpc.py#L65-123
            try
            {
                if (_poolConfig.Coin.Options.SubmitBlockSupported)           // see if submitblock() is available.
                {
                    _daemonClient.SubmitBlock(share.BlockHex.ToHexString()); // submit the block.
                }
                else
                {
                    _daemonClient.GetBlockTemplate(share.BlockHex.ToHexString(), _poolConfig.Wallet.Address); // use getblocktemplate() if submitblock() is not supported.
                }
                var block = _daemonClient.GetBlock(share.BlockHash.ToHexString());                            // query the block.

                if (block == null)                                                                            // make sure the block exists
                {
                    _logger.Debug("Submitted block [{0}] cannot be found with getblock; [{1}]", share.BlockHash.ToHexString(), block.Hash);
                    return(false);
                }

                if (block.Confirmations == -1) // make sure the block is accepted.
                {
                    _logger.Debug("Submitted block [{0}] is orphaned; [{1:l}]", block.Height, block.Hash);
                    return(false);
                }

                var expectedTxHash = share.CoinbaseHash.Bytes.ReverseBuffer().ToHexString(); // calculate our expected generation transactions's hash
                var genTxHash      = block.Tx.First();                                       // read the hash of very first (generation transaction) of the block

                if (expectedTxHash != genTxHash)                                             // make sure our calculated generated transaction and one reported by coin daemon matches.
                {
                    _logger.Debug("Submitted block [{0}] doesn't seem to belong us as reported generation transaction hash [{1:l}] doesn't match our expected one [{2:l}]", block.Height, genTxHash, expectedTxHash);
                    return(false);
                }

                var genTx = _daemonClient.GetTransaction(block.Tx.First()); // get the generation transaction.

                // make sure we were able to read the generation transaction
                if (genTx == null)
                {
                    _logger.Debug("Submitted block [{0}] doesn't seem to belong us as we can't read the generation transaction on our records [{1:l}]", block.Height, block.Tx.First());
                    return(false);
                }

                var poolOutput = genTx.GetPoolOutput(_poolConfig.Wallet.Address, _poolAccount); // get the output that targets pool's central address.

                // make sure the blocks generation transaction contains our central pool wallet address
                if (poolOutput == null)
                {
                    _logger.Debug("Submitted block [{0}] doesn't seem to belong us as generation transaction doesn't contain an output for pool's central wallet address: {0:}", block.Height, _poolConfig.Wallet.Address);
                    return(false);
                }

                // if the code flows here, then it means the block was succesfully submitted and belongs to us.
                share.SetFoundBlock(block, genTx); // assign the block to share.

                _logger.Information("Found block [{0}] with hash [{1:l}]", share.Height, share.BlockHash.ToHexString());

                return(true);
            }
            catch (RpcException e)
            {
                // unlike BlockProcessor's detailed exception handling and decision making based on the error,
                // here in share-manager we only one-shot submissions. If we get an error, basically we just don't care about the rest
                // and flag the submission as failed.
                _logger.Debug("We thought a block was found but it was rejected by the coin daemon; [{0:l}] - reason; {1:l}", share.BlockHash.ToHexString(), e.Message);
                return(false);
            }
            catch (Exception e)
            {
                _logger.Debug("We thought a block was found but it was rejected by the coin daemon; [{0:l}] - reason; {1:l}", share.BlockHash.ToHexString(), e.Message);
                return(false);
            }
        }
예제 #5
0
        public void Recache()
        {
            try // read getnetworkinfo() followed by getwalletinfo() based data.
            {
                var info = _daemonClient.GetNetworkInfo();

                // read Getnetwork
                CoinVersion     = info.Version;
                ProtocolVersion = info.ProtocolVersion;
                Connections     = info.Connections;
                Errors          = info.Errors;

                try // read getwalletinfo() based data.
                {
                    var infoWall = _daemonClient.GetWalletInfo();

                    // read data
                    WalletVersion = infoWall.WalletVersion;
                }
                catch (RpcException e)
                {
                    _logger.Error("Can not read getwalletinfo(): {0:l}", e.Message);
                    Healthy = false; // set healthy status to false as we couldn't get a reply.
                }

                // check if our network connection is healthy. info: based errors are warnings only so ignore.
                Healthy = Connections >= 0 && (string.IsNullOrEmpty(Errors) || Errors.Contains("Info:"));
            }
            catch (RpcException) // catch exception, provide backwards compatability for getinfo() based data.
            {
                // do not log this as an actual error, but rather as info only, then proceed to try getinfo().
                //_logger.Error("Can not read getnetworkinfo(), trying getinfo() instead: {0:l}", c.Message); // do not log original error, try getinfo() first.

                try // catch exception, provide backwards compatability for getinfo() based data.
                {
                    var info = _daemonClient.GetInfo();

                    // read data.
                    CoinVersion     = info.Version;
                    ProtocolVersion = info.ProtocolVersion;
                    WalletVersion   = info.WalletVersion;
                    Testnet         = info.Testnet;
                    Connections     = info.Connections;
                    Errors          = info.Errors;

                    // check if our network connection is healthy. info: based errors are warnings only so ignore.
                    Healthy = Connections >= 0 && (string.IsNullOrEmpty(Errors) || Errors.Contains("Info:"));
                }
                catch (RpcException ee)
                {
                    _logger.Error("Can not read getinfo(): {0:l}", ee.Message);
                    Healthy = false; // set healthy status to false as we couldn't get a reply.
                }
            }

            try // read getmininginfo() based data.
            {
                var miningInfo = _daemonClient.GetMiningInfo();

                // read data.
                Hashrate   = miningInfo.NetworkHashPerSec;
                Difficulty = miningInfo.Difficulty;
                Round      = miningInfo.Blocks + 1;
                if (!Testnet)
                {
                    Testnet = miningInfo.Testnet;
                }
            }
            catch (RpcException e)
            {
                _logger.Error("Can not read getmininginfo(): {0:l}", e.Message);
                Hashrate   = 0;
                Difficulty = 0;
                Round      = -1;
                Healthy    = false; // set healthy status to false as we couldn't get a reply.
            }

            try // read getblocktemplate() based data.
            {
                var blockTemplate = _daemonClient.GetBlockTemplate(_poolConfig.Coin.Options.BlockTemplateModeRequired);
                Reward = (UInt64)blockTemplate.Coinbasevalue / 100000000; // coinbasevalue is in satoshis, convert it to actual coins.
            }
            catch (RpcException e)
            {
                _logger.Error("Can not read getblocktemplate(): {0:l}", e.Message);
                Reward = 0;
            }
        }