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