diff --git a/src/CoiniumServ/Blocks/BlockProcessor.cs b/src/CoiniumServ/Blocks/BlockProcessor.cs new file mode 100644 index 000000000..954ddd449 --- /dev/null +++ b/src/CoiniumServ/Blocks/BlockProcessor.cs @@ -0,0 +1,98 @@ +#region License +// +// CoiniumServ - Crypto Currency Mining Pool Server Software +// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org +// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ +// +// This software is dual-licensed: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// For the terms of this license, see licenses/gpl_v3.txt. +// +// Alternatively, you can license this software under a commercial +// license or white-label it as set out in licenses/commercial.txt. +// +#endregion + +using System; +using System.Linq; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Pools.Config; +using Serilog; + +namespace CoiniumServ.Blocks +{ + public class BlockProcessor:IBlockProcessor + { + private readonly IDaemonClient _daemonClient; + + private readonly IPoolConfig _poolConfig; + + private readonly ILogger _logger; + + public BlockProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient) + { + _poolConfig = poolConfig; + _daemonClient = daemonClient; + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); + } + + public bool GetBlockDetails(string blockHash, out Block block, out Transaction generationTransaction) + { + block = null; + generationTransaction = null; + + try + { + // query the block. + block = _daemonClient.GetBlock(blockHash); + + // read the very first (generation transaction) of the block + var generationTx = block.Tx.First(); + + // also make sure the transaction includes our pool wallet address. + generationTransaction = _daemonClient.GetTransaction(generationTx); + + return true; + } + catch (RpcException e) + { + _logger.Error("Queried block does not exist {0:l}, {1:l}", blockHash, e.Message); + return false; + } + } + + public bool CheckGenTxHash(Block block, string expectedTxHash) + { + // get the generation transaction for the block. + var genTx = block.Tx.First(); + + if (expectedTxHash == genTx) + return true; + + Log.Debug("Queried block {0:l} doesn't seem to belong us as reported generation transaction hash [{1:l}] doesn't match our expected one [{2:l}]", block.Hash, genTx, expectedTxHash); + return false; + } + + public bool ContainsPoolOutput(Transaction transaction) + { + // check if the transaction includes output for the configured central pool wallet address. + var gotPoolOutput = transaction.Details.Any(x => x.Address == _poolConfig.Wallet.Adress); + + if (gotPoolOutput) // if we got the correct pool output + return true; // then the block seems to belong us. + + Log.Debug("Queried block doesn't seem to belong us as generation transaction doesn't contain an output for pool's central wallet address: {0:}", _poolConfig.Wallet.Adress); + return false; + } + } +} diff --git a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs b/src/CoiniumServ/Blocks/IBlockProcessor.cs similarity index 75% rename from src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs rename to src/CoiniumServ/Blocks/IBlockProcessor.cs index f91adf0e3..011f51bd2 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs +++ b/src/CoiniumServ/Blocks/IBlockProcessor.cs @@ -21,20 +21,16 @@ // #endregion -using System.Collections.Generic; +using CoiniumServ.Daemon.Responses; -namespace CoiniumServ.Persistance.Blocks +namespace CoiniumServ.Blocks { - public interface IPendingBlock: IPersistedBlock + public interface IBlockProcessor { - bool IsFinalized { get; } + bool GetBlockDetails(string blockHash, out Block block, out Transaction generationTransaction); - IFinalizedBlock Finalized { get; } + bool CheckGenTxHash(Block block, string expectedTxHash); - List Candidates { get; } - - void AddHashCandidate(IHashCandidate hash); - - void Check(); + bool ContainsPoolOutput(Transaction transaction); } } diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 84b26803b..c27f682c4 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -109,6 +109,8 @@ + + @@ -143,6 +145,7 @@ + @@ -153,8 +156,8 @@ - - + + @@ -200,18 +203,7 @@ - - - - - - - - - - - diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index bd8d3b256..7af91c6a1 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -22,6 +22,7 @@ #endregion using CoiniumServ.Banning; +using CoiniumServ.Blocks; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Jobs.Manager; @@ -78,9 +79,11 @@ IJobManager GetJobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJ IJobTracker GetJobTracker(); - IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage); + IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, IBlockProcessor blockProcessor); - IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage); + IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage, IBlockProcessor blockProcessor); + + IBlockProcessor GetBlockProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient); IBanManager GetBanManager(IPoolConfig poolConfig, IShareManager shareManager); @@ -98,9 +101,9 @@ IJobManager GetJobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJ IPools GetPoolStats(); - IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage); + IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocksCount blockStatistics, IStorage storage); - IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage); + IBlocksCount GetBlockStats(ILatestBlocks latestBlocks, IStorage storage); ILatestBlocks GetLatestBlocks(IStorage storage); diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index 3f7bec4a3..99fe822c4 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -22,6 +22,7 @@ #endregion using CoiniumServ.Banning; +using CoiniumServ.Blocks; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Jobs.Manager; @@ -145,7 +146,7 @@ public IJobTracker GetJobTracker() return _applicationContext.Container.Resolve(); } - public IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) + public IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, IBlockProcessor blockProcessor) { var @params = new NamedParameterOverloads { @@ -153,23 +154,36 @@ public IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemo {"daemonClient", daemonClient}, {"jobTracker", jobTracker}, {"storage", storage}, + {"blockProcessor", blockProcessor} }; return _applicationContext.Container.Resolve(@params); } - public IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage) + public IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage, IBlockProcessor blockProcessor) { var @params = new NamedParameterOverloads { {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, - {"storage", storage}, + {"storage", storage}, + {"blockProcessor", blockProcessor}, }; return _applicationContext.Container.Resolve(@params); } + public IBlockProcessor GetBlockProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient) + { + var @params = new NamedParameterOverloads + { + {"poolConfig", poolConfig}, + {"daemonClient", daemonClient}, + }; + + return _applicationContext.Container.Resolve(@params); + } + public IBanManager GetBanManager(IPoolConfig poolConfig, IShareManager shareManager) { var @params = new NamedParameterOverloads @@ -216,7 +230,7 @@ public IPools GetPoolStats() return _applicationContext.Container.Resolve(); } - public IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) + public IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocksCount blockStatistics, IStorage storage) { var @params = new NamedParameterOverloads { @@ -241,7 +255,7 @@ public ILatestBlocks GetLatestBlocks(IStorage storage) return _applicationContext.Container.Resolve(@params); } - public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) + public IBlocksCount GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) { var @params = new NamedParameterOverloads { @@ -249,7 +263,7 @@ public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) {"storage", storage}, }; - return _applicationContext.Container.Resolve(@params); + return _applicationContext.Container.Resolve(@params); } #endregion diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index e7626a098..f1e760458 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -28,7 +28,7 @@ namespace CoiniumServ.Payments { public interface IPaymentRound { - IFinalizedBlock Block { get; } + IPersistedBlock Block { get; } Dictionary Shares { get; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index db242ca93..9e420c0b6 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -26,10 +26,13 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using CoiniumServ.Blocks; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Daemon.Responses; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Blocks; +using CoiniumServ.Pools; using CoiniumServ.Pools.Config; using Serilog; @@ -42,8 +45,13 @@ public class PaymentProcessor : IPaymentProcessor public bool IsEnabled { get; private set; } private readonly IDaemonClient _daemonClient; + private readonly IStorage _storage; + private IPaymentConfig _config; + + private readonly IBlockProcessor _blockProcessor; + private Timer _timer; private Int32 _precision; // coin's precision. @@ -54,15 +62,19 @@ public class PaymentProcessor : IPaymentProcessor private readonly Stopwatch _stopWatch = new Stopwatch(); private readonly IWalletConfig _walletConfig; + private string _poolAccount = string.Empty; private readonly ILogger _logger; - public PaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage ) + public PaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage, IBlockProcessor blockProcessor) { _daemonClient = daemonClient; _storage = storage; + _blockProcessor = blockProcessor; + _walletConfig = poolConfig.Wallet; + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } @@ -102,10 +114,9 @@ private void RunPayments(object state) { _stopWatch.Start(); - var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. - var finalizedBlocks = GetFinalizedBlocks(pendingBlocks); - - var rounds = GetPaymentRounds(finalizedBlocks); // get the list of rounds that should be paid. + var pendingBlocks = _storage.GetBlocks(BlockStatus.Pending); // get all the pending blocks. + var nonPendingBlocks = GetNonPendingBlocks(pendingBlocks); // get the confirmed blocks that are either orphan or mature. + var rounds = GetPaymentRounds(nonPendingBlocks); // get the list of rounds that should be paid. AssignSharesToRounds(rounds); // process the rounds, calculate shares and payouts per rounds. var previousBalances = GetPreviousBalances(); // get previous balances of workers. var workerBalances = CalculateRewards(rounds, previousBalances); // calculate the payments. @@ -215,7 +226,6 @@ private void ProcessRounds(IEnumerable rounds) _storage.DeleteShares(round); // delete the associated shares. _storage.MoveBlock(round); // move pending block to appropriate place. break; - case BlockStatus.Kicked: case BlockStatus.Orphaned: _storage.MoveSharesToCurrentRound(round); // move shares to current round so the work of miners aren't gone to void. _storage.MoveBlock(round); // move pending block to appropriate place. @@ -239,79 +249,82 @@ private void AssignSharesToRounds(IList rounds) } } - private IList GetFinalizedBlocks(IEnumerable blocks) + private IEnumerable GetNonPendingBlocks(IEnumerable blocks) { - var finalizedBlocks = new List(); + var nonPendingBlocks = new List(); - foreach (var block in blocks) + foreach (var item in blocks) { - foreach (var candidate in block.Candidates) - { - CheckCandidates(candidate); - } - - block.Check(); + var block = item; // get a local copy of the block + QueryBlock(ref block); // check the block. - if(block.IsFinalized) - finalizedBlocks.Add(block.Finalized); + if (!block.IsPending) // only add non-pending blocks to list. + nonPendingBlocks.Add(block); } - return finalizedBlocks; + return nonPendingBlocks; } - private IEnumerable GetConfirmedBlocks(IEnumerable blocks) + private void QueryBlock(ref IPersistedBlock block) { - return blocks.OfType().ToList(); - } + // query the block against coin daemon and see if seems all good. + Block blockInfo; // the block repsonse from coin daemon. + Transaction genTx; // generation transaction response from coin daemon. + var exists = _blockProcessor.GetBlockDetails(block.BlockHash, out blockInfo, out genTx); // query the coin daemon for the block details. - private void CheckCandidates(IHashCandidate candidate) - { - try + if (!exists) // make sure the block exists. { - // get the transaction. - var transaction = _daemonClient.GetTransaction(candidate.TransactionHash); + block.Status = BlockStatus.Orphaned; + return; + } - // total amount of coins contained in the block. - candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); + // calculate our expected generation transactions's hash + var expectedTxHash = block.TransactionHash; - // get the output transaction that targets pools central wallet. - var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == _walletConfig.Adress); + // make sure our calculated and reported generation tx hashes match. + if (!_blockProcessor.CheckGenTxHash(blockInfo, expectedTxHash)) + { + block.Status = BlockStatus.Orphaned; + return; + } - // make sure output for the pool central wallet exists - if (poolOutput == null) - { - candidate.Status = BlockStatus.Kicked; // kick the hash. - candidate.Reward = 0; - } - else - { - switch (poolOutput.Category) - { - case "immature": - candidate.Status = BlockStatus.Pending; - break; - case "orphan": - candidate.Status = BlockStatus.Orphaned; - break; - case "generate": - candidate.Status = BlockStatus.Confirmed; - break; - default: - candidate.Status = BlockStatus.Pending; - break; - } + // make sure the blocks generation transaction contains our central pool wallet address + if (!_blockProcessor.ContainsPoolOutput(genTx)) + { + block.Status = BlockStatus.Orphaned; + return; + } - candidate.Reward = (decimal) poolOutput.Amount; - } + // get the output transaction that targets pools central wallet. + var poolOutput = genTx.Details.FirstOrDefault(output => output.Address == _walletConfig.Adress); + + // make sure we have a valid reference to poolOutput + if (poolOutput == null) + { + block.Status = BlockStatus.Orphaned; + return; } - catch (RpcException) + + switch (poolOutput.Category) { - candidate.Status = BlockStatus.Kicked; // kick the hash. - candidate.Reward = 0; - } + case "immature": + block.Status = BlockStatus.Pending; + break; + case "orphan": + block.Status = BlockStatus.Orphaned; + break; + case "generate": + block.Status = BlockStatus.Confirmed; + break; + } + + // TODO: add back these. + // total amount of coins contained in the block. + // candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); + // candidate.Reward = (decimal) poolOutput.Amount; } - private IList GetPaymentRounds(IEnumerable blocks) + private IList GetPaymentRounds(IEnumerable blocks) { var rounds = new List(); diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs index 6961a3801..eb08f1d04 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -29,12 +29,12 @@ namespace CoiniumServ.Payments { public class PaymentRound:IPaymentRound { - public IFinalizedBlock Block { get; private set; } + public IPersistedBlock Block { get; private set; } public Dictionary Shares { get; private set; } public Dictionary Payouts { get; private set; } - public PaymentRound(IFinalizedBlock block) + public PaymentRound(IPersistedBlock block) { Block = block; Payouts = new Dictionary(); diff --git a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs index 1fe25c1c1..d56e88ff9 100644 --- a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs +++ b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs @@ -25,7 +25,6 @@ namespace CoiniumServ.Persistance.Blocks public enum BlockStatus { Pending, - Kicked, Orphaned, Confirmed } diff --git a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs deleted file mode 100644 index 9402d8f74..000000000 --- a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs +++ /dev/null @@ -1,53 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion -namespace CoiniumServ.Persistance.Blocks -{ - public class ConfirmedBlock:IConfirmedBlock - { - public uint Height { get; private set; } - public BlockStatus Status { get; private set; } - public string BlockHash { get; private set; } - public string TransactionHash { get; private set; } - public decimal Reward { get; set; } - public decimal Amount { get; set; } - - public ConfirmedBlock(uint height, string blockHash, string transactionHash, decimal amount, decimal reward) - { - Height = height; - BlockHash = blockHash; - TransactionHash = transactionHash; - Amount = amount; - Reward = reward; - Status = BlockStatus.Confirmed; - } - - public ConfirmedBlock(uint height, IHashCandidate candidate) - : this(height, candidate.BlockHash, candidate.TransactionHash, candidate.Amount, candidate.Reward) - { } - - public override string ToString() - { - return string.Format("Height: {0}, Status: Confirmed.", Height); - } - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs deleted file mode 100644 index 93b6ec30d..000000000 --- a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs +++ /dev/null @@ -1,45 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion -namespace CoiniumServ.Persistance.Blocks -{ - public class HashCandidate : IHashCandidate - { - public string BlockHash { get; private set; } - public string TransactionHash { get; private set; } - public decimal Amount { get; set; } - public decimal Reward { get; set; } - public BlockStatus Status { get; set; } - - public HashCandidate(string blockHash, string transactionHash) - { - BlockHash = blockHash; - TransactionHash = transactionHash; - Status = BlockStatus.Pending; - } - - public override string ToString() - { - return string.Format("Status: {0}, Block Hash: {1}, Transaction Hash: {2}", Status, BlockHash, TransactionHash); - } - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs deleted file mode 100644 index 48110a899..000000000 --- a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs +++ /dev/null @@ -1,29 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion - -namespace CoiniumServ.Persistance.Blocks -{ - public interface IConfirmedBlock:IFinalizedBlock - { - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs deleted file mode 100644 index c7b507f5b..000000000 --- a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs +++ /dev/null @@ -1,28 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion -namespace CoiniumServ.Persistance.Blocks -{ - public interface IFinalizedBlock:IPersistedBlock - { - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs deleted file mode 100644 index f6fd48ae7..000000000 --- a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs +++ /dev/null @@ -1,33 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion -namespace CoiniumServ.Persistance.Blocks -{ - public interface IHashCandidate - { - string BlockHash { get; } - string TransactionHash { get; } - decimal Amount { get; set; } - decimal Reward { get; set; } - BlockStatus Status { get; set; } - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs deleted file mode 100644 index 75957c8ff..000000000 --- a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs +++ /dev/null @@ -1,29 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion - -namespace CoiniumServ.Persistance.Blocks -{ - public interface IKickedBlock:IFinalizedBlock - { - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs deleted file mode 100644 index af81db90f..000000000 --- a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs +++ /dev/null @@ -1,29 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion - -namespace CoiniumServ.Persistance.Blocks -{ - public interface IOrphanedBlock:IFinalizedBlock - { - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs index 9904db196..7baf2c469 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs @@ -28,10 +28,12 @@ namespace CoiniumServ.Persistance.Blocks public interface IPersistedBlock { UInt32 Height { get; } - BlockStatus Status { get; } + BlockStatus Status { get; set; } string BlockHash { get; } string TransactionHash { get; } decimal Reward { get; } decimal Amount { get; } + + bool IsPending { get; } } } diff --git a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs deleted file mode 100644 index 20f6e1f14..000000000 --- a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs +++ /dev/null @@ -1,53 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion -namespace CoiniumServ.Persistance.Blocks -{ - public class OrphanedBlock:IOrphanedBlock - { - public uint Height { get; private set; } - public BlockStatus Status { get; private set; } - public string BlockHash { get; private set; } - public string TransactionHash { get; private set; } - public decimal Reward { get; set; } - public decimal Amount { get; set; } - - public OrphanedBlock(uint height, string blockHash, string transactionHash, decimal amount, decimal reward) - { - Height = height; - BlockHash = blockHash; - TransactionHash = transactionHash; - Reward = reward; - Amount = amount; - Status = BlockStatus.Orphaned; - } - - public OrphanedBlock(uint height, IHashCandidate candidate) - : this(height, candidate.BlockHash, candidate.TransactionHash,candidate.Amount, candidate.Reward) - { } - - public override string ToString() - { - return string.Format("Height: {0}, Status: Orphaned.", Height); - } - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs deleted file mode 100644 index 7545de775..000000000 --- a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs +++ /dev/null @@ -1,108 +0,0 @@ -#region License -// -// CoiniumServ - Crypto Currency Mining Pool Server Software -// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// http://www.coiniumserv.com - https://github.com/CoiniumServ/CoiniumServ -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// For the terms of this license, see licenses/gpl_v3.txt. -// -// Alternatively, you can license this software under a commercial -// license or white-label it as set out in licenses/commercial.txt. -// -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace CoiniumServ.Persistance.Blocks -{ - public class PendingBlock : IPendingBlock - { - public uint Height { get; private set; } - - public bool IsFinalized - { - get { return Finalized != null; } - } - - public BlockStatus Status - { - get { return IsFinalized ? Finalized.Status : BlockStatus.Pending; } - } - - public string BlockHash - { - get { return IsFinalized ? Finalized.BlockHash : Candidates.First().BlockHash; } - } - - public string TransactionHash - { - get { return IsFinalized ? Finalized.BlockHash : Candidates.First().TransactionHash; } - } - - public decimal Reward - { - get { return IsFinalized ? Finalized.Reward : 0; } - } - - public decimal Amount - { - get { return IsFinalized ? Finalized.Amount : 0; } - } - - public IFinalizedBlock Finalized { get; private set; } - public List Candidates { get; private set; } - - public PendingBlock(uint height) - { - Height = height; - Candidates = new List(); - Finalized = null; - } - - public void AddHashCandidate(IHashCandidate hash) - { - Candidates.Add(hash); - } - - public void Check() - { - var confirmedCandidate = Candidates.FirstOrDefault( x => x.Status == BlockStatus.Confirmed); - - if (confirmedCandidate != null) - { - Finalized = new ConfirmedBlock(Height, confirmedCandidate); - return; - } - - var orphanedCandidate = Candidates.FirstOrDefault(x => x.Status == BlockStatus.Orphaned); - if (orphanedCandidate != null) - { - Finalized = new OrphanedBlock(Height, orphanedCandidate); - return; - } - - var kickedCandidate = Candidates.FirstOrDefault(x => x.Status == BlockStatus.Kicked); - if (kickedCandidate != null) - { - Finalized = new KickedBlock(Height, kickedCandidate); - return; - } - } - - public override string ToString() - { - return string.Format("Height: {0}, Status: {1}.", Height, Finalized == null ? BlockStatus.Pending : Finalized.Status); - } - } -} diff --git a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs similarity index 68% rename from src/CoiniumServ/Persistance/Blocks/KickedBlock.cs rename to src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs index 6a5df9612..076616d7c 100644 --- a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs @@ -20,34 +20,36 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System.Diagnostics; + namespace CoiniumServ.Persistance.Blocks { - public class KickedBlock:IKickedBlock + [DebuggerDisplay("Height: {Height}, Status: {Status}")] + public class PersistedBlock:IPersistedBlock { public uint Height { get; private set; } - public BlockStatus Status { get; private set; } + + public BlockStatus Status { get; set; } + public string BlockHash { get; private set; } + public string TransactionHash { get; private set; } - public decimal Reward { get; set; } - public decimal Amount { get; set; } - public KickedBlock(uint height, string blockHash, string transactionHash, decimal amount, decimal reward) + public decimal Reward { get; private set; } + + public decimal Amount { get; private set; } + + public bool IsPending { get { return Status != BlockStatus.Orphaned && Status != BlockStatus.Confirmed; } } + + public PersistedBlock(BlockStatus status, uint height, string blockHash, string transactionHash, decimal amount, decimal reward) { + Status = status; Height = height; BlockHash = blockHash; TransactionHash = transactionHash; Amount = amount; Reward = reward; - Status = BlockStatus.Kicked; - } - - public KickedBlock(uint height, IHashCandidate candidate) - : this(height, candidate.BlockHash, candidate.TransactionHash, candidate.Amount, candidate.Reward) - { } - - public override string ToString() - { - return string.Format("Height: {0}, Status: Kicked.", Height); } } } diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index e577a8c6e..85a45a384 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -51,7 +51,7 @@ public interface IStorage IDictionary GetHashrateData(int since); - IList GetPendingBlocks(); + IEnumerable GetBlocks(BlockStatus status); IDictionary GetAllBlocks(); diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index cc4065443..e4c409c71 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -231,9 +231,6 @@ public void MoveBlock(IPaymentRound round) switch (round.Block.Status) { - case BlockStatus.Kicked: - newKey = string.Format("{0}:blocks:kicked", coin); - break; case BlockStatus.Orphaned: newKey = string.Format("{0}:blocks:orphaned", coin); break; @@ -340,64 +337,22 @@ public IDictionary GetHashrateData(int since) return hashrates; } - public IList GetPendingBlocks() - { - var blocks = new Dictionary(); - - try - { - if (!IsEnabled || !IsConnected) - return blocks.Values.ToList(); - - var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - var pendingKey = string.Format("{0}:blocks:pending", coin); - - var results = _client.ZRevRangeByScoreWithScores(pendingKey, double.PositiveInfinity, 0, true); - - foreach (var result in results) - { - var item = result.Item1; - var score = result.Item2; - - var data = item.Split(':'); - var blockHash = data[0]; - var transactionHash = data[1]; - var hashCandidate = new HashCandidate(blockHash, transactionHash); - - if (!blocks.ContainsKey((UInt32) score)) - blocks.Add((UInt32) score, new PendingBlock((UInt32) score)); - - var persistedBlock = blocks[(UInt32) score]; - persistedBlock.AddHashCandidate(hashCandidate); - } - } - catch (Exception e) - { - _logger.Error("An exception occured while getting pending blocks: {0:l}", e.Message); - } - - return blocks.Values.ToList(); - } - - private IEnumerable GetFinalizedBlocks(BlockStatus status) + public IEnumerable GetBlocks(BlockStatus status) { - var blocks = new Dictionary(); + var blocks = new Dictionary(); try { if (!IsEnabled || !IsConnected) return blocks.Values.ToList(); - if (status == BlockStatus.Pending) - throw new Exception("Pending is not a valid finalized block status"); - var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - string key = string.Empty; + var key = string.Empty; switch (status) { - case BlockStatus.Kicked: - key = string.Format("{0}:blocks:kicked", coin); + case BlockStatus.Pending: + key = string.Format("{0}:blocks:pending", coin); break; case BlockStatus.Orphaned: key = string.Format("{0}:blocks:orphaned", coin); @@ -418,23 +373,12 @@ private IEnumerable GetFinalizedBlocks(BlockStatus status) var blockHash = data[0]; var transactionHash = data[1]; - switch (status) - { - case BlockStatus.Kicked: - blocks.Add((UInt32) score, new KickedBlock((UInt32) score, blockHash, transactionHash, 0, 0)); - break; - case BlockStatus.Orphaned: - blocks.Add((UInt32) score,new OrphanedBlock((UInt32) score, blockHash, transactionHash, 0, 0)); - break; - case BlockStatus.Confirmed: - blocks.Add((UInt32) score, new ConfirmedBlock((UInt32) score, blockHash, transactionHash, 0, 0)); - break; - } + blocks.Add((UInt32) score, new PersistedBlock(status, (UInt32) score, blockHash, transactionHash, 0, 0)); } } catch (Exception e) { - _logger.Error("An exception occured while getting finalized blocks: {0:l}", e.Message); + _logger.Error("An exception occured while getting {0:l} blocks: {1:l}", status, e.Message); } return blocks.Values.ToList(); @@ -447,22 +391,17 @@ public IDictionary GetAllBlocks() if (!IsEnabled || !IsConnected) return blocks; - foreach (var block in GetFinalizedBlocks(BlockStatus.Confirmed)) - { - blocks.Add(block.Height, block); - } - - foreach (var block in GetFinalizedBlocks(BlockStatus.Orphaned)) + foreach (var block in GetBlocks(BlockStatus.Confirmed)) { blocks.Add(block.Height, block); } - foreach (var block in GetFinalizedBlocks(BlockStatus.Kicked)) + foreach (var block in GetBlocks(BlockStatus.Orphaned)) { blocks.Add(block.Height, block); } - foreach (var block in GetPendingBlocks()) + foreach (var block in GetBlocks(BlockStatus.Pending)) { blocks.Add(block.Height, block); } diff --git a/src/CoiniumServ/Pools/Pool.cs b/src/CoiniumServ/Pools/Pool.cs index 1b42cb281..2f5d8cac7 100644 --- a/src/CoiniumServ/Pools/Pool.cs +++ b/src/CoiniumServ/Pools/Pool.cs @@ -150,32 +150,42 @@ private void InitDaemon() private void InitManagers() { - var storage = _objectFactory.GetStorage(Storages.Redis, Config); + try + { + var storage = _objectFactory.GetStorage(Storages.Redis, Config); - var paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, storage); - paymentProcessor.Initialize(Config.Payments); + _minerManager = _objectFactory.GetMinerManager(Config, _daemonClient); - _minerManager = _objectFactory.GetMinerManager(Config, _daemonClient); + var jobTracker = _objectFactory.GetJobTracker(); - var jobTracker = _objectFactory.GetJobTracker(); + var blockProcessor = _objectFactory.GetBlockProcessor(Config, _daemonClient); - _shareManager = _objectFactory.GetShareManager(Config, _daemonClient, jobTracker, storage); + _shareManager = _objectFactory.GetShareManager(Config, _daemonClient, jobTracker, storage, blockProcessor); - var vardiffManager = _objectFactory.GetVardiffManager(Config, _shareManager); + var vardiffManager = _objectFactory.GetVardiffManager(Config, _shareManager); - _banningManager = _objectFactory.GetBanManager(Config, _shareManager); + _banningManager = _objectFactory.GetBanManager(Config, _shareManager); - _jobManager = _objectFactory.GetJobManager(Config, _daemonClient, jobTracker, _shareManager, _minerManager, _hashAlgorithm); + _jobManager = _objectFactory.GetJobManager(Config, _daemonClient, jobTracker, _shareManager, _minerManager, _hashAlgorithm); + _jobManager.Initialize(InstanceId); - _jobManager.Initialize(InstanceId); + var paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, storage, blockProcessor); + paymentProcessor.Initialize(Config.Payments); - var latestBlocks = _objectFactory.GetLatestBlocks(storage); - var blockStats = _objectFactory.GetBlockStats(latestBlocks, storage); - Statistics = _objectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, storage); + var latestBlocks = _objectFactory.GetLatestBlocks(storage); + var blockStats = _objectFactory.GetBlockStats(latestBlocks, storage); + Statistics = _objectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, storage); + } + catch (Exception e) + { + _logger.Error("Pool initialization error: {0:l}", e.Message); + } } private void InitServers() { + // todo: merge this with InitManagers so we don't have use private declaration of class instances + _servers = new Dictionary(); if (Config.Stratum != null && Config.Stratum.Enabled) diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index f8aa4261d..7af68b4af 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Blocks; using CoiniumServ.Coin.Config; using CoiniumServ.Configuration; using CoiniumServ.Daemon; @@ -55,12 +56,13 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsMultiInstance(); // statistics _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); // config diff --git a/src/CoiniumServ/Shares/ShareManager.cs b/src/CoiniumServ/Shares/ShareManager.cs index 5237ecb3c..79c94413e 100644 --- a/src/CoiniumServ/Shares/ShareManager.cs +++ b/src/CoiniumServ/Shares/ShareManager.cs @@ -25,10 +25,11 @@ using System.Diagnostics; using System.Linq; using AustinHarris.JsonRpc; +using CoiniumServ.Blocks; using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Persistance; -using CoiniumServ.Pools; using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Errors; @@ -50,6 +51,8 @@ public class ShareManager : IShareManager private readonly IStorage _storage; + private readonly IBlockProcessor _blockProcessor; + private readonly IPoolConfig _poolConfig; private readonly ILogger _logger; @@ -61,12 +64,14 @@ public class ShareManager : IShareManager /// /// /// - public ShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) + /// + public ShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, IBlockProcessor blockProcessor) { _poolConfig = poolConfig; _daemonClient = daemonClient; _jobTracker = jobTracker; _storage = storage; + _blockProcessor = blockProcessor; _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } @@ -118,13 +123,19 @@ private void HandleValidShare(IShare share) // submit block candidate to daemon. var accepted = SubmitBlock(share); - // check if it was accepted and valid. - if (!accepted) - return; + // log about the acceptance status of the block. + _logger.Information( + accepted + ? "Found block [{0}] with hash: {1:l}" + : "Submitted block [{0}] with hash {1:l} but had to kick it as it was not accepted by the coin daemon", + share.Height, share.BlockHash.ToHexString()); + + if (!accepted) // if block wasn't accepted + return; // just return as we don't need to notify about it and store it. OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. - _storage.AddBlock(share); // commit the block. + _storage.AddBlock(share); // commit the block details to storage. } private void HandleInvalidShare(IShare share) @@ -165,65 +176,39 @@ private void HandleInvalidShare(IShare share) private bool SubmitBlock(IShare share) { - // 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 + // 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 { _daemonClient.SubmitBlock(share.BlockHex.ToHexString()); - var isAccepted = CheckBlock(share); - _logger.Information( - isAccepted - ? "Found block [{0}] with hash: {1:l}" - : "Submitted block [{0}] but got denied: {1:l}", - share.Height, share.BlockHash.ToHexString()); - - return isAccepted; - } - catch (Exception e) - { - _logger.Error(e, "Submit block failed - height: {0}, hash: {1:l}", share.Height, share.BlockHash); - return false; - } - } + // query the block against coin daemon and see if seems all good. + Block blockInfo; // the block repsonse from coin daemon. + Transaction genTx; // generation transaction response from coin daemon. + var exists = _blockProcessor.GetBlockDetails(share.BlockHash.ToHexString(), out blockInfo, out genTx); // query the coin daemon for the block details. - private bool CheckBlock(IShare share) - { - try - { - var block = _daemonClient.GetBlock(share.BlockHash.ToHexString()); // query the block. - - // calculate our generation transactions's hash - var genTxHash = share.CoinbaseHash.Bytes.ReverseBuffer().ToHexString(); - - // read the very first (generation transaction) of the block - var initialTx = block.Tx.First(); - - // make sure our calculated generation transaction hash matches the very first transaction reported for block by coin daemon. - if (genTxHash != initialTx) - { - Log.Debug("Kicked submitted block {0} because reported generation transaction hash [{1:l}] doesn't match our calculated one [{2:l}]", initialTx, genTxHash); + if (!exists) // make sure the block exists. return false; - } - - // also make sure the transaction includes our pool wallet address. - var transaction = _daemonClient.GetTransaction(initialTx); - // check if the transaction includes output for the configured central pool wallet address. - var gotPoolOutput = transaction.Details.Any(test => test.Address == _poolConfig.Wallet.Adress); + // calculate our expected generation transactions's hash + var expectedTxHash = share.CoinbaseHash.Bytes.ReverseBuffer().ToHexString(); - if (!gotPoolOutput) - { - Log.Debug("Kicked submitted block {0} because generation transaction doesn't contain an output for pool's central wallet address: {1:l]", share.Height, _poolConfig.Wallet.Adress); + // make sure our calculated and reported generation tx hashes match. + if (!_blockProcessor.CheckGenTxHash(blockInfo, expectedTxHash)) return false; - } + + // make sure the blocks generation transaction contains our central pool wallet address + if (!_blockProcessor.ContainsPoolOutput(genTx)) + return false; + + // if the code flows here, then it means the block was succesfully submitted and belongs to us. + share.SetFoundBlock(blockInfo); // assign the block to share. - share.SetFoundBlock(block); // assign the block to share. return true; } catch (Exception e) { - _logger.Error("Submitted block does not exist: {0}, hash: {1:l}, {2:l}", share.Height, share.BlockHash, e.Message); + _logger.Error(e, "Submit block failed - height: {0}, hash: {1:l} - {2:l}", share.Height, share.BlockHash, e.Message); return false; } } diff --git a/src/CoiniumServ/Statistics/Blocks.cs b/src/CoiniumServ/Statistics/BlocksCount.cs similarity index 94% rename from src/CoiniumServ/Statistics/Blocks.cs rename to src/CoiniumServ/Statistics/BlocksCount.cs index ad2795798..41e90d1de 100644 --- a/src/CoiniumServ/Statistics/Blocks.cs +++ b/src/CoiniumServ/Statistics/BlocksCount.cs @@ -25,7 +25,7 @@ namespace CoiniumServ.Statistics { - public class Blocks:IBlocks + public class BlocksCount:IBlocksCount { public int Pending { get; private set; } public int Confirmed { get; private set; } @@ -35,7 +35,7 @@ public class Blocks:IBlocks private readonly IStorage _storage; - public Blocks(ILatestBlocks latestBlocks, IStorage storage) + public BlocksCount(ILatestBlocks latestBlocks, IStorage storage) { _storage = storage; Latest = latestBlocks; diff --git a/src/CoiniumServ/Statistics/IBlocks.cs b/src/CoiniumServ/Statistics/IBlocksCount.cs similarity index 95% rename from src/CoiniumServ/Statistics/IBlocks.cs rename to src/CoiniumServ/Statistics/IBlocksCount.cs index 762d64ec0..649d3c1b4 100644 --- a/src/CoiniumServ/Statistics/IBlocks.cs +++ b/src/CoiniumServ/Statistics/IBlocksCount.cs @@ -23,7 +23,7 @@ namespace CoiniumServ.Statistics { - public interface IBlocks : IStatisticsProvider + public interface IBlocksCount : IStatisticsProvider { int Pending { get; } int Confirmed { get; } diff --git a/src/CoiniumServ/Statistics/IPerPool.cs b/src/CoiniumServ/Statistics/IPerPool.cs index 66387dce3..28798be5f 100644 --- a/src/CoiniumServ/Statistics/IPerPool.cs +++ b/src/CoiniumServ/Statistics/IPerPool.cs @@ -38,7 +38,7 @@ public interface IPerPool:IJsonResponse, IStatisticsProvider int CurrentBlock { get; } - IBlocks Blocks { get; } + IBlocksCount Blocks { get; } IPoolConfig Config { get; } } diff --git a/src/CoiniumServ/Statistics/PerPool.cs b/src/CoiniumServ/Statistics/PerPool.cs index e965f83fa..7defd9181 100644 --- a/src/CoiniumServ/Statistics/PerPool.cs +++ b/src/CoiniumServ/Statistics/PerPool.cs @@ -43,7 +43,7 @@ public class PerPool:IPerPool public int WorkerCount { get; private set; } public double Difficulty { get; private set; } public int CurrentBlock { get; private set; } - public IBlocks Blocks { get; private set; } + public IBlocksCount Blocks { get; private set; } public IPoolConfig Config { get; private set; } public string Json { get; private set; } @@ -57,7 +57,7 @@ public class PerPool:IPerPool private readonly double _shareMultiplier; - public PerPool(IPoolConfig poolConfig, IConfigManager configManager, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) + public PerPool(IPoolConfig poolConfig, IConfigManager configManager, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocksCount blockStatistics, IStorage storage) { Config = poolConfig; _statisticsConfig = configManager.WebServerConfig.Statistics; diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index ac63c5b62..fa3c3f5d7 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -101,7 +101,6 @@ @block.Status break; case BlockStatus.Orphaned: - case BlockStatus.Kicked: @block.Status break; case BlockStatus.Confirmed: