diff --git a/Changelog.md b/Changelog.md index 72a9c2743..219f49c62 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,9 @@ +##### [v0.1.2 alpha - Piri Reis](https://github.com/CoiniumServ/CoiniumServ/releases/tag/v0.1.2-alpha) - 14.08.2014 + +**Payments** +* Fixed a major bug in payment processor which was preventing payments to miners. +* Fixed a bug in statistics manager. + ##### [v0.1.1 alpha - Piri Reis](https://github.com/CoiniumServ/CoiniumServ/releases/tag/v0.1.1-alpha) - 10.08.2014 **Mining** * Improved SocketServiceContext and removed unnecessary overhead. diff --git a/README.md b/README.md index 1294543ad..4b12762db 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ You can send tips and furher support the project or get tips for contributing by ### Status -Expect a functioning alpha soon. +[v0.1.2 alpha](https://github.com/CoiniumServ/CoiniumServ/releases/tag/v0.1.2-alpha) released ### Features diff --git a/src/CoiniumServ/Blocks/BlockProcessor.cs b/src/CoiniumServ/Blocks/BlockProcessor.cs index 05254b0ee..9967f233d 100644 --- a/src/CoiniumServ/Blocks/BlockProcessor.cs +++ b/src/CoiniumServ/Blocks/BlockProcessor.cs @@ -75,19 +75,11 @@ public Block GetBlock(string blockHash) } } - public TransactionDetail GetPoolOutput(Block block) + public Transaction GetGenerationTransaction(Block block) { try { - var genTx = _daemonClient.GetTransaction(block.Tx.First()); // query the transaction - - if (genTx == null) // make sure the generation transaction exists - return null; - - // check if coin includes output address data in transaction details. - return genTx.Details.Any(x => x.Address == null) - ? genTx.Details.FirstOrDefault(x => x.Account == _poolAccount) // some coins doesn't include address field in outputs, so try to determine using the associated account name. - : genTx.Details.FirstOrDefault(x => x.Address == _poolConfig.Wallet.Adress); // if coin includes address field in outputs, just use it. + return _daemonClient.GetTransaction(block.Tx.First()); // query the transaction } catch (RpcException e) { @@ -95,5 +87,10 @@ public TransactionDetail GetPoolOutput(Block block) return null; } } + + public TransactionDetail GetPoolOutput(Transaction transaction) + { + return transaction.GetPoolOutput(_poolConfig.Wallet.Adress, _poolAccount); + } } } diff --git a/src/CoiniumServ/Blocks/IBlockProcessor.cs b/src/CoiniumServ/Blocks/IBlockProcessor.cs index 0620a6642..fdd8a308d 100644 --- a/src/CoiniumServ/Blocks/IBlockProcessor.cs +++ b/src/CoiniumServ/Blocks/IBlockProcessor.cs @@ -29,6 +29,8 @@ public interface IBlockProcessor { Block GetBlock(string blockHash); - TransactionDetail GetPoolOutput(Block block); + Transaction GetGenerationTransaction(Block block); + + TransactionDetail GetPoolOutput(Transaction transaction); } } diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index b69d200d7..3ad8705b5 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -22,12 +22,19 @@ #endregion using System.Collections.Generic; +using System.Linq; namespace CoiniumServ.Daemon.Responses { public class Transaction { - public double Amount { get; set; } + public double Amount { get; set; } // seems it's set to 0 for immature transactions or generation transactions. + + /// + /// As Amount may not always return the total transaction amount, TotalAmount calculates and return the value using transaction details + /// + public double TotalAmount { get { return Details.Sum(item => item.Amount); } } + public int Confirmations { get; set; } public bool Generated { get; set; } @@ -46,7 +53,22 @@ public class Transaction public int TimeReceived { get; set; } public List Details { get; set; } - + + + /// + /// Returns the transaction detail that contains the output for pool. + /// + /// + /// + /// + public TransactionDetail GetPoolOutput(string poolAddress, string poolAccount) + { + // check if coin includes output address data in transaction details. + return Details.Any(x => x.Address == null) + ? Details.FirstOrDefault(x => x.Account == poolAccount) // some coins doesn't include address field in outputs, so try to determine using the associated account name. + : Details.FirstOrDefault(x => x.Address == poolAddress); // if coin includes address field in outputs, just use it. + } + // not sure if fields below even exists / used //public double Fee { get; set; } //public string Comment { get; set; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index c39109772..a6692ca73 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -143,6 +143,9 @@ private IList CalculateRewards(IEnumerable rounds // set previous balances foreach(var pair in previousBalances) { + if (pair.Value == 0) // skip zero balances + continue; + if (!workerBalances.ContainsKey(pair.Key)) workerBalances.Add(pair.Key, new WorkerBalance(pair.Key, _magnitude)); @@ -284,8 +287,10 @@ private void QueryBlock(ref IPersistedBlock block) return; } + var genTx = _blockProcessor.GetGenerationTransaction(blockInfo); // get the generation transaction. + // get the output transaction that targets pools central wallet. - var poolOutput = _blockProcessor.GetPoolOutput(blockInfo); + var poolOutput = _blockProcessor.GetPoolOutput(genTx); // make sure we have a valid reference to poolOutput if (poolOutput == null) @@ -294,6 +299,8 @@ private void QueryBlock(ref IPersistedBlock block) return; } + block.SetReward((decimal)poolOutput.Amount); // set the reward of the block to miners. + switch (poolOutput.Category) { case "immature": @@ -307,6 +314,7 @@ private void QueryBlock(ref IPersistedBlock block) break; } + // TODO: add back these. // total amount of coins contained in the block. // candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); diff --git a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs index 7baf2c469..994357d76 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs @@ -31,9 +31,10 @@ public interface IPersistedBlock BlockStatus Status { get; set; } string BlockHash { get; } string TransactionHash { get; } - decimal Reward { get; } decimal Amount { get; } - + decimal Reward { get; } bool IsPending { get; } + + void SetReward(decimal reward); } } diff --git a/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs index 076616d7c..26ff34b1c 100644 --- a/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/PersistedBlock.cs @@ -36,19 +36,23 @@ public class PersistedBlock:IPersistedBlock public string TransactionHash { get; private set; } - public decimal Reward { get; private set; } - public decimal Amount { get; private set; } + public decimal Reward { 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) + public PersistedBlock(BlockStatus status, uint height, string blockHash, string transactionHash, decimal amount) { Status = status; Height = height; BlockHash = blockHash; TransactionHash = transactionHash; Amount = amount; + } + + public void SetReward(decimal reward) + { Reward = reward; } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 44d875766..cefa4beac 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -119,7 +119,8 @@ public void AddBlock(IShare share) // add block to pending. var pendingKey = string.Format("{0}:blocks:pending", _coin); - var entry = string.Format("{0}:{1}", share.BlockHash.ToHexString(), share.Block.Tx.First()); + // entry format: blockHash:txHash:Amount + var entry = string.Format("{0}:{1}:{2}", share.BlockHash.ToHexString(), share.Block.Tx.First(), share.GenerationTransaction.TotalAmount); _client.ZAdd(pendingKey, Tuple.Create(share.Block.Height, entry)); } @@ -364,8 +365,9 @@ public IEnumerable GetBlocks(BlockStatus status) var data = item.Split(':'); var blockHash = data[0]; var transactionHash = data[1]; + var amount = decimal.Parse(data[2]); - blocks.Add((UInt32) score, new PersistedBlock(status, (UInt32) score, blockHash, transactionHash, 0, 0)); + blocks.Add((UInt32)score, new PersistedBlock(status, (UInt32)score, blockHash, transactionHash, amount)); } } catch (Exception e) diff --git a/src/CoiniumServ/Shares/IShare.cs b/src/CoiniumServ/Shares/IShare.cs index aa1da2066..e61dca2b8 100644 --- a/src/CoiniumServ/Shares/IShare.cs +++ b/src/CoiniumServ/Shares/IShare.cs @@ -43,6 +43,8 @@ public interface IShare Block Block { get; } + Transaction GenerationTransaction { get; } + /// /// Is the block data accepted by the coin daemon? /// @@ -89,6 +91,6 @@ public interface IShare byte[] BlockHash { get; } - void SetFoundBlock(Block block); + void SetFoundBlock(Block block, Transaction genTx); } } diff --git a/src/CoiniumServ/Shares/Share.cs b/src/CoiniumServ/Shares/Share.cs index 07484b7e1..a2472a1a4 100644 --- a/src/CoiniumServ/Shares/Share.cs +++ b/src/CoiniumServ/Shares/Share.cs @@ -41,6 +41,7 @@ public class Share : IShare public bool IsValid { get { return Error == ShareError.None; } } public bool IsBlockCandidate { get; private set; } public Block Block { get; private set; } + public Transaction GenerationTransaction { get; private set; } public bool IsBlockAccepted { get { return Block != null; } } public IMiner Miner { get; private set; } public ShareError Error { get; private set; } @@ -163,9 +164,10 @@ public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, st } } - public void SetFoundBlock(Block block) + public void SetFoundBlock(Block block, Transaction genTx) { Block = block; + GenerationTransaction = genTx; } } } diff --git a/src/CoiniumServ/Shares/ShareManager.cs b/src/CoiniumServ/Shares/ShareManager.cs index b8d231e21..89194f952 100644 --- a/src/CoiniumServ/Shares/ShareManager.cs +++ b/src/CoiniumServ/Shares/ShareManager.cs @@ -201,7 +201,9 @@ private bool SubmitBlock(IShare share) return false; } - var poolOutput = _blockProcessor.GetPoolOutput(block); // get the output that targets pool's central address. + var genTx = _blockProcessor.GetGenerationTransaction(block); // get the generation transaction. + + var poolOutput = _blockProcessor.GetPoolOutput(genTx); // get the output that targets pool's central address. // make sure the blocks generation transaction contains our central pool wallet address if (poolOutput == null) @@ -211,7 +213,7 @@ private bool SubmitBlock(IShare share) } // if the code flows here, then it means the block was succesfully submitted and belongs to us. - share.SetFoundBlock(block); // assign the block to share. + share.SetFoundBlock(block, genTx); // assign the block to share. return true; } diff --git a/src/CoiniumServ/Statistics/PerPool.cs b/src/CoiniumServ/Statistics/PerPool.cs index 4cb15359a..b696a816f 100644 --- a/src/CoiniumServ/Statistics/PerPool.cs +++ b/src/CoiniumServ/Statistics/PerPool.cs @@ -129,6 +129,9 @@ private void RecacheWorkers() foreach (var miner in _minerManager.Miners) { + if (!miner.Authenticated) + continue; + Workers.Add(miner.Username, shares.ContainsKey(miner.Username) ? shares[miner.Username] : 0); } diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index 7f89ec287..ca927ae4f 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -41,7 +41,7 @@ public static class Assembly /// /// Main assemby version. /// - public const string Version = "0.1.1.*"; + public const string Version = "0.1.2.*"; } } } diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 14076fa0d..cd259f45b 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -98,13 +98,13 @@ @switch (block.Status) { case BlockStatus.Pending: - @block.Status + @block.Status break; case BlockStatus.Orphaned: - @block.Status + @block.Status break; case BlockStatus.Confirmed: - @block.Status + @block.Status break; }