From a2fbe0403f3fe95158858eaaaf54883b2707792b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 2 Jul 2014 12:39:29 +0300 Subject: [PATCH 001/230] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index bb08ffeb0..de5b57b2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ env: - secure: "jan4aHikK+XOsBfJrhbFnrFlhAJ7p31z2KiXxoviFmO+5gIsZuhaEIniA5Kx/27rakj0CphoXxGL77WAYiEuVGJKl5j2j55zCYxSrs3ux7OuDut7A3NmwFXD65XcU75Pj12O3YMN96FKSY1ESdf0SBnti+hvgGDgIM47MOFWxME=" - EnableNuGetPackageRestore=true matrix: + - MONO_VER="2.10.12" Package="dmg" - MONO_VER="3.2.7" Package="pkg" - MONO_VER="3.4.0" Package="pkg" before_install: From 1984888976a0c2d53eb2ccf06b7dc326dcac7b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 2 Jul 2014 12:51:34 +0300 Subject: [PATCH 002/230] removed coverity-scan from travis --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index de5b57b2d..d0461fbbf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: objective-c env: global: - - secure: "jan4aHikK+XOsBfJrhbFnrFlhAJ7p31z2KiXxoviFmO+5gIsZuhaEIniA5Kx/27rakj0CphoXxGL77WAYiEuVGJKl5j2j55zCYxSrs3ux7OuDut7A3NmwFXD65XcU75Pj12O3YMN96FKSY1ESdf0SBnti+hvgGDgIM47MOFWxME=" - EnableNuGetPackageRestore=true matrix: - MONO_VER="2.10.12" Package="dmg" @@ -18,11 +17,3 @@ script: notifications: irc: chat.freenode.net#coinium-dev email: false -addons: - coverity_scan: - project: - name: CoiniumServ/CoiniumServ - description: C# Mono/.Net based crypto currency mining pool software - build_command_prepend: - build_command: xbuild build/CoiniumServ.sln - branch_pattern: coverity_scan From 33bdfc8b4e15f2c895202ad85bb264661cf19e85 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 13:06:46 +0300 Subject: [PATCH 003/230] Another ubuntu installer fix. --- assets/installer/ubuntu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/installer/ubuntu.sh b/assets/installer/ubuntu.sh index 7e9e262dc..9d7837a04 100644 --- a/assets/installer/ubuntu.sh +++ b/assets/installer/ubuntu.sh @@ -1,6 +1,6 @@ #!/bin/bash echo "Making sure git and mono is installed.." -sudo apt-get install git-core mono-complete +sudo apt-get -y install git-core mono-complete echo "Cloning CoiniumServ.." git clone https://github.com/CoiniumServ/CoiniumServ.git cd CoiniumServ From 71797d131fc2bcb95cafad7adc0fde6c8ba11a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 2 Jul 2014 13:30:06 +0300 Subject: [PATCH 004/230] trying a fix for nuget on < ubuntu 14 --- build/.gitignore | 1 + build/.nuget/Microsoft.Build.dll | Bin 0 -> 449376 bytes 2 files changed, 1 insertion(+) create mode 100644 build/.nuget/Microsoft.Build.dll diff --git a/build/.gitignore b/build/.gitignore index 8f4c84746..4473b19c8 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,2 +1,3 @@ /*.sln.DotSettings *.userprefs +!.nuget/Microsoft.Build.dll \ No newline at end of file diff --git a/build/.nuget/Microsoft.Build.dll b/build/.nuget/Microsoft.Build.dll new file mode 100644 index 0000000000000000000000000000000000000000..0fdbcfa086f92bef0eea1b747caefbfb43d16207 GIT binary patch literal 449376 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�+a1+MR@lDJL?4CG$|=mB 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 XarYm2!Y4z!ALTi4(g|!Oxm^DTgMf(P literal 0 HcmV?d00001 From ccc630611b4a99e46097f304b08c451e6ea39848 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 13:51:00 +0300 Subject: [PATCH 005/230] Updated nuget packages to microsoft.bcl 1.1.8, serilog 1.3.30, stackexchange.redis. 1.0.312. --- src/CoiniumServ/App.config | 4 ++-- src/CoiniumServ/CoiniumServ.csproj | 18 +++++------------- src/CoiniumServ/packages.config | 6 +++--- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index 9bf7ed104..d085a4b71 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -7,11 +7,11 @@ - + - + diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 6f85ee37d..3383d2218 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -83,28 +83,20 @@ False - ..\..\build\packages\Serilog.1.3.30\lib\net40\Serilog.dll + ..\..\build\packages\Serilog.1.3.33\lib\net40\Serilog.dll False - ..\..\build\packages\Serilog.1.3.30\lib\net40\Serilog.FullNetFx.dll + ..\..\build\packages\Serilog.1.3.33\lib\net40\Serilog.FullNetFx.dll - - ..\..\build\packages\StackExchange.Redis.1.0.312\lib\net40\StackExchange.Redis.dll + + False + ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll - - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.IO.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Runtime.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Threading.Tasks.dll - diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index d917ec748..f5cf596f9 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,12 +4,12 @@ - + - - + + \ No newline at end of file From 6a201f1283599ba30f6d8f1c1ab30f1892f55291 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 13:56:55 +0300 Subject: [PATCH 006/230] Testing a possible async fix for mono. --- src/CoiniumServ/CoiniumServ.csproj | 12 ++++++++++++ src/CoiniumServ/packages.config | 1 + src/Tests/App.config | 4 ++-- src/Tests/Tests.csproj | 9 +++------ src/Tests/packages.config | 4 ++-- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 3383d2218..a50c1097f 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -46,6 +46,9 @@ ..\..\assets\Coinium.ico + + ..\..\build\packages\AsyncBridge.0.1.1\lib\net40-Client\AsyncBridge.dll + False ..\..\build\packages\AustinHarris.JsonRpc.1.0.4.18\lib\net40\AustinHarris.JsonRpc.dll @@ -95,8 +98,17 @@ + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll + diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index f5cf596f9..760c8b881 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -1,5 +1,6 @@  + diff --git a/src/Tests/App.config b/src/Tests/App.config index 16b7606d6..188c1a87b 100644 --- a/src/Tests/App.config +++ b/src/Tests/App.config @@ -8,11 +8,11 @@ - + - + diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index e9ac1f3b3..6a4e8348d 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -60,21 +60,18 @@ ..\..\build\packages\ShouldFluent.1.1.19\lib\Should.Fluent.dll - - ..\..\build\packages\StackExchange.Redis.1.0.312\lib\net40\StackExchange.Redis.dll - - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.IO.dll + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Runtime.dll + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll - ..\..\build\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Threading.Tasks.dll + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll ..\..\build\packages\xunit.1.9.2\lib\net20\xunit.dll diff --git a/src/Tests/packages.config b/src/Tests/packages.config index c0084c0e3..8b33ce25e 100644 --- a/src/Tests/packages.config +++ b/src/Tests/packages.config @@ -1,13 +1,13 @@  - + - + \ No newline at end of file From 4a7a34a98714490cb79233246c24905f332c4141 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 14:02:37 +0300 Subject: [PATCH 007/230] Removed AsyncBridge. --- src/CoiniumServ/CoiniumServ.csproj | 3 --- src/CoiniumServ/packages.config | 1 - 2 files changed, 4 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index a50c1097f..18c06ff9f 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -46,9 +46,6 @@ ..\..\assets\Coinium.ico - - ..\..\build\packages\AsyncBridge.0.1.1\lib\net40-Client\AsyncBridge.dll - False ..\..\build\packages\AustinHarris.JsonRpc.1.0.4.18\lib\net40\AustinHarris.JsonRpc.dll diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 760c8b881..f5cf596f9 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -1,6 +1,5 @@  - From 2e498206f5db11d518852a62ed5ae1431d82a22e Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 14:47:59 +0300 Subject: [PATCH 008/230] Removed 2.10.12 target from travis.yml. Removed Microsoft.Build.dll. --- .travis.yml | 1 - build/.gitignore | 3 +-- build/.nuget/Microsoft.Build.dll | Bin 449376 -> 0 bytes 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 build/.nuget/Microsoft.Build.dll diff --git a/.travis.yml b/.travis.yml index d0461fbbf..ccdb02b3a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ env: global: - EnableNuGetPackageRestore=true matrix: - - MONO_VER="2.10.12" Package="dmg" - MONO_VER="3.2.7" Package="pkg" - MONO_VER="3.4.0" Package="pkg" before_install: diff --git a/build/.gitignore b/build/.gitignore index 4473b19c8..b3ec5017c 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,3 +1,2 @@ /*.sln.DotSettings -*.userprefs -!.nuget/Microsoft.Build.dll \ No newline at end of file +*.userprefs \ No newline at end of file diff --git a/build/.nuget/Microsoft.Build.dll b/build/.nuget/Microsoft.Build.dll deleted file mode 100644 index 0fdbcfa086f92bef0eea1b747caefbfb43d16207..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 449376 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�+a1+MR@lDJL?4CG$|=mB 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 XarYm2!Y4z!ALTi4(g|!Oxm^DTgMf(P From 97463873f3c0f0fe82eb213883bb7eaaf94cd2ce Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 14:49:21 +0300 Subject: [PATCH 009/230] Another ubuntu.sh installer fix. --- assets/installer/ubuntu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/installer/ubuntu.sh b/assets/installer/ubuntu.sh index 9d7837a04..32b972de4 100644 --- a/assets/installer/ubuntu.sh +++ b/assets/installer/ubuntu.sh @@ -1,6 +1,6 @@ #!/bin/bash echo "Making sure git and mono is installed.." -sudo apt-get -y install git-core mono-complete +sudo apt-get -y --force-yes install git-core mono-complete echo "Cloning CoiniumServ.." git clone https://github.com/CoiniumServ/CoiniumServ.git cd CoiniumServ From b0cdb4118cc743def70382d7b9c2350f1c732d74 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 16:56:21 +0300 Subject: [PATCH 010/230] Accepted blocks are now also stored in redis now. --- src/CoiniumServ/Mining/Shares/ShareManager.cs | 6 +-- src/CoiniumServ/Persistance/Redis/Redis.cs | 42 +++++++++++++++---- src/Tests/Tests.csproj | 3 ++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 384b04923..4b49ae61f 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -82,10 +82,8 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, { Log.ForContext().Information("Share with block candidate [{0}] accepted at {1:0.00}/{2} by miner {3}.", share.Height, share.Difficulty, miner.Difficulty, miner.Username); - var success = SubmitBlock(share); // submit block to daemon - - if (success) - _storage.CommitBlock(share); + var success = SubmitBlock(share); // submit block to daemon. + _storage.CommitBlock(share); // commit the block. // TODO: notify back job manager using an event so he can create a new job. } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 245677f64..af16f7bf2 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -22,10 +22,12 @@ #endregion using System; +using System.Linq; using System.Net; using System.Net.Sockets; using Coinium.Mining.Shares; using Coinium.Utils.Configuration; +using Coinium.Utils.Extensions; using Coinium.Utils.Helpers.Time; using Serilog; using StackExchange.Redis; @@ -62,18 +64,25 @@ public void CommitShare(IShare share) var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); - // add the share to round. + // add the share to round + // key: coin:shares:round:current + // field: username, value: difficulty. var roundKey = string.Format("{0}:shares:round:current", coin); _database.HashIncrement(roundKey, share.Miner.Username, share.Difficulty ,CommandFlags.FireAndForget); - // increment the valid shares. + // increment shares stats. + // key: coin:stats + // fields: validShares, invalidShares. var statsKey = string.Format("{0}:stats", coin); _database.HashIncrement(statsKey, share.IsValid ? "validShares" : "invalidShares", 1 , CommandFlags.FireAndForget); - // add to hashrate. + // add to hashrate + // key: coin:shares:hashrate + // score: unix-time + // value: difficulty:username if (share.IsValid) { - var hashrateKey = string.Format("{0}:hashrate", coin); + var hashrateKey = string.Format("{0}:shares:hashrate", coin); var entry = string.Format("{0}:{1}", share.Difficulty, share.Miner.Username); _database.SortedSetAdd(hashrateKey, entry, TimeHelpers.NowInUnixTime(), CommandFlags.FireAndForget); } @@ -83,10 +92,27 @@ public void CommitBlock(IShare share) { var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); - // rename round:current to round:height. - var currentKey = string.Format("{0}:shares:round:current", coin); - var newKey = string.Format("{0}:shares:round:{1}", coin, share.Height); - _database.KeyRenameAsync(currentKey, newKey, When.Always, CommandFlags.HighPriority); + if (share.IsBlockAccepted) + { + // rename round [coin:round:current -> coin:round:heigh] + var currentKey = string.Format("{0}:shares:round:current", coin); + var newKey = string.Format("{0}:shares:round:{1}", coin, share.Height); + _database.KeyRenameAsync(currentKey, newKey, When.Always, CommandFlags.HighPriority); + + // add block to pending + // key: coin:blocks:pending + // score: block height: + // value: blockHash:generation-transaction-hash + var pendingKey = string.Format("{0}:blocks:pending", coin); + var entry = string.Format("{0}:{1}", share.BlockHash.ToHexString(), share.Block.Tx.First()); + _database.SortedSetAdd(pendingKey, entry, share.Block.Height, CommandFlags.FireAndForget); + } + + // increment block stats. + // key: coin:stats + // fields: validBlocks, invalidBlocks + var statsKey = string.Format("{0}:stats", coin); + _database.HashIncrement(statsKey, share.IsBlockAccepted ? "validBlocks" : "invalidBlocks", 1, CommandFlags.FireAndForget); } private void Initialize() diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 6a4e8348d..cf562c95d 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -60,6 +60,9 @@ ..\..\build\packages\ShouldFluent.1.1.19\lib\Should.Fluent.dll + + ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll + From 6dbd3144406ebf598c3b848101deec7287a38f56 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 17:08:08 +0300 Subject: [PATCH 011/230] Redis now executes commands in batch. --- src/CoiniumServ/Persistance/Redis/Redis.cs | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index af16f7bf2..c46f7a47b 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -22,9 +22,11 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading.Tasks; using Coinium.Mining.Shares; using Coinium.Utils.Configuration; using Coinium.Utils.Extensions; @@ -62,19 +64,20 @@ public void CommitShare(IShare share) if (!IsEnabled || !IsConnected) return; - var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); + var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); // the coin we are working on. + var batch = _database.CreateBatch(); // batch the commands. // add the share to round // key: coin:shares:round:current // field: username, value: difficulty. var roundKey = string.Format("{0}:shares:round:current", coin); - _database.HashIncrement(roundKey, share.Miner.Username, share.Difficulty ,CommandFlags.FireAndForget); + batch.HashIncrementAsync(roundKey, share.Miner.Username, share.Difficulty, CommandFlags.FireAndForget); // increment shares stats. // key: coin:stats // fields: validShares, invalidShares. var statsKey = string.Format("{0}:stats", coin); - _database.HashIncrement(statsKey, share.IsValid ? "validShares" : "invalidShares", 1 , CommandFlags.FireAndForget); + batch.HashIncrementAsync(statsKey, share.IsValid ? "validShares" : "invalidShares", 1, CommandFlags.FireAndForget); // add to hashrate // key: coin:shares:hashrate @@ -84,20 +87,23 @@ public void CommitShare(IShare share) { var hashrateKey = string.Format("{0}:shares:hashrate", coin); var entry = string.Format("{0}:{1}", share.Difficulty, share.Miner.Username); - _database.SortedSetAdd(hashrateKey, entry, TimeHelpers.NowInUnixTime(), CommandFlags.FireAndForget); + batch.SortedSetAddAsync(hashrateKey, entry, TimeHelpers.NowInUnixTime(), CommandFlags.FireAndForget); } + + batch.Execute(); // execute the batch commands. } public void CommitBlock(IShare share) { - var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); + var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); // the coin we are working on. + var batch = _database.CreateBatch(); // batch the commands. if (share.IsBlockAccepted) { // rename round [coin:round:current -> coin:round:heigh] var currentKey = string.Format("{0}:shares:round:current", coin); var newKey = string.Format("{0}:shares:round:{1}", coin, share.Height); - _database.KeyRenameAsync(currentKey, newKey, When.Always, CommandFlags.HighPriority); + batch.KeyRenameAsync(currentKey, newKey, When.Always, CommandFlags.HighPriority); // add block to pending // key: coin:blocks:pending @@ -105,14 +111,16 @@ public void CommitBlock(IShare share) // value: blockHash:generation-transaction-hash var pendingKey = string.Format("{0}:blocks:pending", coin); var entry = string.Format("{0}:{1}", share.BlockHash.ToHexString(), share.Block.Tx.First()); - _database.SortedSetAdd(pendingKey, entry, share.Block.Height, CommandFlags.FireAndForget); + batch.SortedSetAddAsync(pendingKey, entry, share.Block.Height, CommandFlags.FireAndForget); } // increment block stats. // key: coin:stats // fields: validBlocks, invalidBlocks var statsKey = string.Format("{0}:stats", coin); - _database.HashIncrement(statsKey, share.IsBlockAccepted ? "validBlocks" : "invalidBlocks", 1, CommandFlags.FireAndForget); + batch.HashIncrementAsync(statsKey, share.IsBlockAccepted ? "validBlocks" : "invalidBlocks", 1, CommandFlags.FireAndForget); + + batch.Execute(); // execute the batch commands. } private void Initialize() From 8fde2ddd876b48bfb058861e2ae4406cd2855a30 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 18:42:09 +0300 Subject: [PATCH 012/230] Implemented hashrate extensions : GetReadableHashrate(). Renamed IJobTracker:LastJob to IJobTracker.Current. JobManager will now create a new job on initialization. Added NetworkHashps field to MiningInfo. Pool.cs will now print a pool info on startup. --- src/CoiniumServ/Coin/Helpers/Hashrate.cs | 47 ++++++++++++++ src/CoiniumServ/CoiniumServ.csproj | 1 + src/CoiniumServ/Daemon/IDaemonClient.cs | 4 ++ src/CoiniumServ/Daemon/Responses/Info.cs | 6 +- .../Daemon/Responses/MiningInfo.cs | 1 + .../Mining/Jobs/Manager/JobManager.cs | 21 ++++--- .../Mining/Jobs/Tracker/IJobTracker.cs | 2 +- .../Mining/Jobs/Tracker/JobTracker.cs | 4 +- src/CoiniumServ/Mining/Pools/Pool.cs | 61 +++++++++++++++---- src/CoiniumServ/Net/Server/Http/HttpServer.cs | 5 +- .../Server/Stratum/StratumServer.cs | 6 +- 11 files changed, 124 insertions(+), 34 deletions(-) create mode 100644 src/CoiniumServ/Coin/Helpers/Hashrate.cs diff --git a/src/CoiniumServ/Coin/Helpers/Hashrate.cs b/src/CoiniumServ/Coin/Helpers/Hashrate.cs new file mode 100644 index 000000000..381530257 --- /dev/null +++ b/src/CoiniumServ/Coin/Helpers/Hashrate.cs @@ -0,0 +1,47 @@ +#region License +// +// CoiniumServ - Crypto Currency Mining Pool Server Software +// Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org +// 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.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Coinium.Coin.Helpers +{ + public static class Hashrate + { + public static string GetReadableHashrate(this int hashrate) + { + var index = -1; + double rate = hashrate; + var units = new[] { "KH/s", "MH/s", "GH/s", "TH/s", "PH/s" }; + + do + { + rate = rate/1024; + index++; + } while (rate > 1024); + + return string.Format("{0:0.00} {1}", rate, units[index]); + } + } +} diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 18c06ff9f..b63c19036 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -108,6 +108,7 @@ + diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 0b5e1766c..5c5e8914d 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -40,6 +40,10 @@ public interface IDaemonClient bool Getwork(string data); + Info GetInfo(); + + MiningInfo GetMiningInfo(); + ValidateAddress ValidateAddress(string walletAddress); void Initialize(IDaemonConfig daemonConfig); diff --git a/src/CoiniumServ/Daemon/Responses/Info.cs b/src/CoiniumServ/Daemon/Responses/Info.cs index d6348405e..a6adb4bd4 100644 --- a/src/CoiniumServ/Daemon/Responses/Info.cs +++ b/src/CoiniumServ/Daemon/Responses/Info.cs @@ -24,9 +24,9 @@ namespace Coinium.Daemon.Responses { public class Info { - public string Version { get; set; } - public string ProtocolVersion { get; set; } - public string WalletVersion { get; set; } + public int Version { get; set; } + public int ProtocolVersion { get; set; } + public int WalletVersion { get; set; } public decimal Balance { get; set; } public long Blocks { get; set; } public long TimeOffset { get; set; } diff --git a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs index 58c49590c..cc594462c 100644 --- a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs @@ -32,6 +32,7 @@ public class MiningInfo public bool Generate { get; set; } public int GenProcLimit { get; set; } public int HashesPerSec { get; set; } + public int NetworkHashps { get; set; } public int PooledTx { get; set; } public bool Testnet { get; set; } } diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 6336552ff..cad46b65d 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -79,7 +79,8 @@ public void Initialize(UInt32 instanceId) _shareManager.BlockFound += OnBlockFound; _minerManager.MinerAuthenticated += OnMinerAuthenticated; - _timer = new Timer(NewJobTimer, null, TimeSpan.Zero, _timeSpan); // setup a timer to broadcast jobs. + var job = GetNewJob(); // initially create a job. + _timer = new Timer(NewJobTimer, null, TimeSpan.Zero, _timeSpan); // setup a timer to broadcast jobs. } private void OnBlockFound(object sender, EventArgs e) @@ -89,14 +90,6 @@ private void OnBlockFound(object sender, EventArgs e) Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id, count); } - private void OnMinerAuthenticated(object sender, EventArgs e) - { - var miner = ((MinerEventArgs) e).Miner; - - //if (miner != null) - var result = SendJobToMiner(miner, _jobTracker.LastJob); - } - private void NewJobTimer(object state) { var job = GetNewJob(); // create a new job. @@ -104,6 +97,16 @@ private void NewJobTimer(object state) Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, TimerExpiration); } + private void OnMinerAuthenticated(object sender, EventArgs e) + { + var miner = ((MinerEventArgs) e).Miner; + + if (miner != null) + { + var result = SendJobToMiner(miner, _jobTracker.Current); + } + } + private IJob GetNewJob() { try diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs index 6cbfd29c6..156bd26fa 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs @@ -30,7 +30,7 @@ public interface IJobTracker { IJob Get(UInt64 id); - IJob LastJob { get; } + IJob Current { get; } void Add(IJob job); } diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs index 9efdaece2..e56dfa716 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs @@ -31,7 +31,7 @@ public class JobTracker:IJobTracker { private readonly Dictionary _jobs; - public IJob LastJob { get; private set; } + public IJob Current { get; private set; } public JobTracker() { @@ -46,7 +46,7 @@ public IJob Get(UInt64 id) public void Add(IJob job) { _jobs.Add(job.Id, job); - LastJob = job; + Current = job; } } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 317be6d3e..ea0aa2034 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -22,11 +22,11 @@ #endregion using System; using System.Collections.Generic; +using System.Linq; using System.Security.Cryptography; -using System.Threading; +using Coinium.Coin.Helpers; using Coinium.Crypto.Algorithms; using Coinium.Daemon; -using Coinium.Mining.Jobs; using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; @@ -37,6 +37,7 @@ using Coinium.Service; using Coinium.Utils.Configuration; using Coinium.Utils.Helpers.Validation; +using HashLib; using Serilog; namespace Coinium.Mining.Pools @@ -64,6 +65,7 @@ public class Pool : IPool private IJobManager _jobManager; private IShareManager _shareManager; private IStorage _storageManager; + private IHashAlgorithm _hashAlgorithm; private Dictionary _servers; @@ -131,6 +133,9 @@ public void Initialize(IPoolConfig config) { Config = config; + // init the algorithm + _hashAlgorithm = _hashAlgorithmFactory.Get(Config.Coin.Algorithm); + // init coin daemon. InitDaemon(); @@ -141,6 +146,14 @@ public void Initialize(IPoolConfig config) InitServers(); } + private void InitDaemon() + { + if (Config.Daemon == null || Config.Daemon.Valid == false) + Log.ForContext().Error("Coin daemon configuration is not valid!"); + + _daemonClient.Initialize(Config.Daemon); + } + private void InitManagers() { _storageManager = _storageManagerFactory.Get(Storages.Redis); @@ -151,18 +164,10 @@ private void InitManagers() _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storageManager); - _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithmFactory.Get(Config.Coin.Algorithm)); + _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); } - private void InitDaemon() - { - if (Config.Daemon == null || Config.Daemon.Valid == false) - Log.ForContext().Error("Coin daemon configuration is not valid!"); - - _daemonClient.Initialize(Config.Daemon); - } - private void InitServers() { _servers = new Dictionary(); @@ -201,6 +206,40 @@ public void Start() { server.Key.Start(); } + + GetPoolInfo(); + } + + private void GetPoolInfo() + { + var info = _daemonClient.GetInfo(); + var miningInfo = _daemonClient.GetMiningInfo(); + + Log.ForContext().Information("Pool started for {0:l}\n" + + "Coin symbol: {1:l} algorithm: {2:l}\n" + + "Coin version: {3} protocol: {4} wallet: {5}\n" + + "Daemon network: {6:l} peers: {7} blocks: {8} errors: {9:l}\n" + + "Network difficulty: {10:0.0000} block difficulty: {11:0.00}\n" + + "Network hashrate: {12:l}\n" + + "{13:l}\n", + Config.Coin.Name, + Config.Coin.Symbol, + Config.Coin.Algorithm, + info.Version, + info.ProtocolVersion, + info.WalletVersion, + info.Testnet ? "testnet" : "mainnet", + info.Connections, info.Blocks, + string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors, + _jobTracker.Current.Difficulty, + _jobTracker.Current.Difficulty*_hashAlgorithm.Multiplier, + miningInfo.NetworkHashps.GetReadableHashrate(), + "Services: " + _servers.Select(pair => pair.Key) + .Aggregate(string.Empty, + (current, server) => + current + + string.Format("{0} @ {1}:{2}, ", server.Config.Name.ToLower(), server.BindIP, server.Port)) + ); } public void Stop() diff --git a/src/CoiniumServ/Net/Server/Http/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/HttpServer.cs index 7e805e495..5cd9f7f61 100644 --- a/src/CoiniumServ/Net/Server/Http/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/HttpServer.cs @@ -76,7 +76,8 @@ public void Initialize(int port, int maxThreads = 5) public bool Start() { - _listener.Prefixes.Add(String.Format(@"http://localhost:{0}/", Port)); + BindIP = "localhost"; + _listener.Prefixes.Add(String.Format(@"http://{0}:{1}/", BindIP, Port)); _listener.Start(); _listenerThread.Start(); @@ -88,8 +89,6 @@ public bool Start() IsListening = true; - Log.ForContext().Information("Vanilla server listening on port {0}.", Port); - return true; } diff --git a/src/CoiniumServ/Server/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Stratum/StratumServer.cs index d2f2cd0d9..c44ba4077 100644 --- a/src/CoiniumServ/Server/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Stratum/StratumServer.cs @@ -83,11 +83,7 @@ public void Initialize(IServerConfig config) public override bool Start() { var success = Listen(BindIP, Port); - - if(success) - Log.ForContext().Information("Stratum server listening on {0}:{1}", BindIP, Port); - - return true; + return success; } ///

From 0719718693030a19bb0d6f27d048a0f9b5a955c8 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 2 Jul 2014 18:45:15 +0300 Subject: [PATCH 013/230] Updated license texts. --- src/CoiniumServ/Coin/Address/Base58.cs | 2 +- .../Coin/Address/Exceptions/AddressFormatException.cs | 3 +-- .../Coin/Address/Exceptions/InvalidWalletAddressException.cs | 3 +-- src/CoiniumServ/Coin/Coinbase/Serializers.cs | 2 +- src/CoiniumServ/Coin/Coinbase/Utils.cs | 2 +- src/CoiniumServ/Coin/Config/CoinConfig.cs | 2 +- src/CoiniumServ/Coin/Config/CoinConfigFactory.cs | 3 +-- src/CoiniumServ/Coin/Config/ICoinConfig.cs | 3 +-- src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs | 2 +- src/CoiniumServ/Coin/Helpers/Amount.cs | 2 +- src/CoiniumServ/Coin/Helpers/Hashrate.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/Algorithms.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs | 3 +-- src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/Scrypt.cs | 2 +- src/CoiniumServ/Crypto/Hash.cs | 2 +- src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs | 3 +-- src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs | 3 +-- src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs | 3 +-- src/CoiniumServ/Crypto/Merkle/MerkleTree.cs | 3 +-- src/CoiniumServ/Crypto/Utils.cs | 2 +- src/CoiniumServ/Daemon/Config/DaemonConfig.cs | 2 +- src/CoiniumServ/Daemon/Config/IDaemonConfig.cs | 3 +-- src/CoiniumServ/Daemon/DaemonBase.cs | 3 +-- src/CoiniumServ/Daemon/DaemonClient.cs | 3 +-- src/CoiniumServ/Daemon/DaemonError.cs | 3 +-- src/CoiniumServ/Daemon/DaemonRequest.cs | 3 +-- src/CoiniumServ/Daemon/DaemonResponse.cs | 3 +-- src/CoiniumServ/Daemon/Exceptions/DaemonException.cs | 3 +-- src/CoiniumServ/Daemon/IDaemonClient.cs | 3 +-- src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs | 3 +-- src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs | 3 +-- src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs | 3 +-- src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs | 3 +-- src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs | 3 +-- src/CoiniumServ/Daemon/Responses/Block.cs | 3 +-- src/CoiniumServ/Daemon/Responses/BlockTemplate.cs | 3 +-- src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs | 2 +- src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs | 3 +-- src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs | 3 +-- src/CoiniumServ/Daemon/Responses/Info.cs | 2 +- .../Daemon/Responses/ListReceivedByAccountTransaction.cs | 2 +- .../Daemon/Responses/ListReceivedByAddressTransaction.cs | 2 +- src/CoiniumServ/Daemon/Responses/ListTransaction.cs | 2 +- src/CoiniumServ/Daemon/Responses/MiningInfo.cs | 2 +- src/CoiniumServ/Daemon/Responses/MultisigAddress.cs | 2 +- src/CoiniumServ/Daemon/Responses/NodeAddress.cs | 2 +- src/CoiniumServ/Daemon/Responses/PeerInfo.cs | 2 +- src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs | 2 +- src/CoiniumServ/Daemon/Responses/Transaction.cs | 3 +-- src/CoiniumServ/Daemon/Responses/TransactionDetail.cs | 2 +- src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs | 2 +- src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs | 3 +-- src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs | 2 +- src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs | 2 +- src/CoiniumServ/Daemon/Responses/ValidateAddress.cs | 3 +-- src/CoiniumServ/Daemon/Responses/Work.cs | 2 +- src/CoiniumServ/Mining/Jobs/ExtraNonce.cs | 2 +- src/CoiniumServ/Mining/Jobs/IExtraNonce.cs | 2 +- src/CoiniumServ/Mining/Jobs/IJobCounter.cs | 2 +- src/CoiniumServ/Mining/Jobs/JobCounter.cs | 2 +- src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs | 2 +- src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs | 3 +-- src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs | 3 +-- src/CoiniumServ/Mining/Miners/IMiner.cs | 3 +-- src/CoiniumServ/Mining/Miners/IMinerManager.cs | 2 +- src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs | 3 +-- src/CoiniumServ/Mining/Miners/MinerEventArgs.cs | 3 +-- src/CoiniumServ/Mining/Miners/MinerManager.cs | 2 +- src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs | 3 +-- src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs | 3 +-- src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs | 2 +- src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs | 2 +- src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs | 3 +-- src/CoiniumServ/Mining/Pools/IPool.cs | 2 +- src/CoiniumServ/Mining/Pools/IPoolFactory.cs | 2 +- src/CoiniumServ/Mining/Pools/IPoolManager.cs | 2 +- src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- src/CoiniumServ/Mining/Pools/PoolFactory.cs | 3 +-- src/CoiniumServ/Mining/Pools/PoolManager.cs | 2 +- src/CoiniumServ/Mining/Shares/IShare.cs | 2 +- src/CoiniumServ/Mining/Shares/IShareManager.cs | 3 +-- src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs | 3 +-- src/CoiniumServ/Mining/Shares/Share.cs | 2 +- src/CoiniumServ/Mining/Shares/ShareError.cs | 2 +- src/CoiniumServ/Mining/Shares/ShareManager.cs | 2 +- src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs | 3 +-- src/CoiniumServ/Net/Server/Http/HttpServer.cs | 2 +- src/CoiniumServ/Net/Server/IServer.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/Connection.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/IClient.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/IConnection.cs | 2 +- src/CoiniumServ/Net/Server/Sockets/SocketServer.cs | 2 +- src/CoiniumServ/Persistance/IStorage.cs | 2 +- src/CoiniumServ/Persistance/IStorageFactory.cs | 2 +- src/CoiniumServ/Persistance/Redis/IRedis.cs | 3 +-- src/CoiniumServ/Persistance/Redis/IRedisConfig.cs | 3 +-- src/CoiniumServ/Persistance/Redis/Redis.cs | 3 +-- src/CoiniumServ/Persistance/Redis/RedisConfig.cs | 2 +- src/CoiniumServ/Persistance/StorageFactory.cs | 3 +-- src/CoiniumServ/Persistance/Storages.cs | 2 +- src/CoiniumServ/Program.cs | 2 +- src/CoiniumServ/Properties/AssemblyInfo.cs | 2 +- src/CoiniumServ/Repository/Bootstrapper.cs | 3 +-- src/CoiniumServ/Repository/Context/ApplicationContext.cs | 3 +-- src/CoiniumServ/Repository/Context/IApplicationContext.cs | 3 +-- src/CoiniumServ/Repository/Registries/ClassRegistry.cs | 3 +-- src/CoiniumServ/Repository/Registries/FactoryRegistry.cs | 3 +-- src/CoiniumServ/Repository/Registries/IRegistry.cs | 2 +- src/CoiniumServ/Repository/Registries/ManagerRegistry.cs | 3 +-- src/CoiniumServ/Repository/Registries/Registry.cs | 3 +-- src/CoiniumServ/Repository/Registries/ServerRegistry.cs | 3 +-- src/CoiniumServ/Repository/Registries/ServiceRegistry.cs | 3 +-- src/CoiniumServ/Server/Commands/Server.cs | 2 +- src/CoiniumServ/Server/Commands/Stats.cs | 2 +- src/CoiniumServ/Server/Commands/Uptime.cs | 2 +- src/CoiniumServ/Server/Commands/Version.cs | 2 +- src/CoiniumServ/Server/Config/IServerConfig.cs | 2 +- src/CoiniumServ/Server/IMiningServer.cs | 3 +-- src/CoiniumServ/Server/IServerFactory.cs | 3 +-- src/CoiniumServ/Server/ServerFactory.cs | 3 +-- src/CoiniumServ/Server/ServerManager.cs | 2 +- src/CoiniumServ/Server/Stratum/Config/IStratumServerConfig.cs | 2 +- src/CoiniumServ/Server/Stratum/Config/StratumServerConfig.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/AuthenticationError.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/DuplicateShareError.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/IStratumError.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/JobNotFoundError.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/LowDifficultyShare.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/NotSubscriberError.cs | 2 +- src/CoiniumServ/Server/Stratum/Errors/OtherError.cs | 2 +- src/CoiniumServ/Server/Stratum/IStratumMiner.cs | 2 +- src/CoiniumServ/Server/Stratum/Notifications/Difficulty.cs | 2 +- src/CoiniumServ/Server/Stratum/Notifications/IJob.cs | 2 +- src/CoiniumServ/Server/Stratum/Notifications/Job.cs | 2 +- src/CoiniumServ/Server/Stratum/Responses/SubscribeResponse.cs | 2 +- src/CoiniumServ/Server/Stratum/StratumMiner.cs | 2 +- src/CoiniumServ/Server/Stratum/StratumServer.cs | 3 +-- src/CoiniumServ/Server/Vanilla/Config/IVanillaServerConfig.cs | 2 +- src/CoiniumServ/Server/Vanilla/Config/VanillaServerConfig.cs | 2 +- src/CoiniumServ/Server/Vanilla/VanillaMiner.cs | 2 +- src/CoiniumServ/Server/Vanilla/VanillaServer.cs | 2 +- src/CoiniumServ/Server/Web/Modules/Stats.cs | 2 +- src/CoiniumServ/Server/Web/WebServer.cs | 2 +- src/CoiniumServ/Service/IRpcService.cs | 2 +- src/CoiniumServ/Service/IServiceFactory.cs | 3 +-- src/CoiniumServ/Service/ServiceFactory.cs | 3 +-- src/CoiniumServ/Service/Services.cs | 2 +- src/CoiniumServ/Service/Stratum/SocketServiceContext.cs | 3 +-- src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs | 3 +-- src/CoiniumServ/Service/Stratum/StratumService.cs | 3 +-- src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs | 3 +-- src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs | 3 +-- src/CoiniumServ/Service/Vanilla/VanillaService.cs | 3 +-- src/CoiniumServ/Transactions/GenerationTransaction.cs | 2 +- src/CoiniumServ/Transactions/IGenerationTransaction.cs | 2 +- src/CoiniumServ/Transactions/IOutputs.cs | 2 +- src/CoiniumServ/Transactions/OutPoint.cs | 2 +- src/CoiniumServ/Transactions/Outputs.cs | 2 +- src/CoiniumServ/Transactions/Script/ISignatureScript.cs | 2 +- src/CoiniumServ/Transactions/Script/SignatureScript.cs | 2 +- src/CoiniumServ/Transactions/TxIn.cs | 2 +- src/CoiniumServ/Transactions/TxOut.cs | 2 +- src/CoiniumServ/Transactions/Utils/TransactionUtils.cs | 2 +- src/CoiniumServ/Utils/Commands/CommandAttributes.cs | 3 +-- src/CoiniumServ/Utils/Commands/CommandGroup.cs | 3 +-- src/CoiniumServ/Utils/Commands/CommandManager.cs | 3 +-- src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs | 3 +-- src/CoiniumServ/Utils/Configuration/IConfig.cs | 2 +- src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs | 3 +-- src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs | 3 +-- src/CoiniumServ/Utils/Console/ConsoleWindow.cs | 3 +-- src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs | 3 +-- src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs | 3 +-- src/CoiniumServ/Utils/Extensions/JsonExtensions.cs | 3 +-- src/CoiniumServ/Utils/Extensions/StringExtensions.cs | 3 +-- src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs | 3 +-- src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs | 3 +-- src/CoiniumServ/Utils/Helpers/Misc/Range.cs | 3 +-- src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs | 3 +-- src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs | 3 +-- src/CoiniumServ/Utils/Logging/Logging.cs | 3 +-- src/CoiniumServ/Utils/Numerics/BigInteger.cs | 3 +-- src/CoiniumServ/Utils/Numerics/BigRational.cs | 3 +-- src/CoiniumServ/Utils/Platform/Framework.cs | 2 +- src/CoiniumServ/Utils/Platform/PlatformManager.cs | 3 +-- src/CoiniumServ/Utils/Versions/VersionInfo.cs | 2 +- src/CoiniumServGui/MainForm.cs | 2 +- src/CoiniumServGui/Program.cs | 2 +- src/CoiniumServGui/Properties/AssemblyInfo.cs | 2 +- src/Tests/Coin/AmountTests.cs | 2 +- src/Tests/Coin/Base58Test.cs | 2 +- src/Tests/Coin/Coinbase/SerializersTests.cs | 2 +- src/Tests/Coin/Coinbase/UtilsTests.cs | 2 +- src/Tests/Crypto/Merkle/MerkleRootTests.cs | 3 +-- src/Tests/Crypto/Merkle/MerkleTreeTests.cs | 3 +-- src/Tests/Daemon/BlockTemplateTests.cs | 3 +-- src/Tests/Mining/Pools/PoolTests.cs | 2 +- src/Tests/Mining/Shares/ShareTests.cs | 2 +- src/Tests/Properties/AssemblyInfo.cs | 2 +- src/Tests/Server/Stratum/Notifications/JobTests.cs | 2 +- src/Tests/Transactions/GenerationTransactionTests.cs | 2 +- src/Tests/Transactions/OutputsTests.cs | 2 +- src/Tests/Transactions/Script/SignatureScriptTests.cs | 3 +-- src/Tests/Transactions/Utils/TransactionUtilsTests.cs | 2 +- src/Tests/Utils/Extensions/ArrayExtensionsTests.cs | 3 +-- src/Tests/Utils/Extensions/StringExtensionsTests.cs | 3 +-- 215 files changed, 215 insertions(+), 312 deletions(-) diff --git a/src/CoiniumServ/Coin/Address/Base58.cs b/src/CoiniumServ/Coin/Address/Base58.cs index 30060c70c..3d10d591c 100644 --- a/src/CoiniumServ/Coin/Address/Base58.cs +++ b/src/CoiniumServ/Coin/Address/Base58.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs b/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs index 5a111684f..5a48cd658 100644 --- a/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs +++ b/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Coin.Address.Exceptions diff --git a/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs b/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs index 88ce71a99..bd6b6d170 100644 --- a/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs +++ b/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Coin.Address.Exceptions diff --git a/src/CoiniumServ/Coin/Coinbase/Serializers.cs b/src/CoiniumServ/Coin/Coinbase/Serializers.cs index fc39b17c8..e27eab986 100644 --- a/src/CoiniumServ/Coin/Coinbase/Serializers.cs +++ b/src/CoiniumServ/Coin/Coinbase/Serializers.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Coinbase/Utils.cs b/src/CoiniumServ/Coin/Coinbase/Utils.cs index df102d62d..bf30d16e8 100644 --- a/src/CoiniumServ/Coin/Coinbase/Utils.cs +++ b/src/CoiniumServ/Coin/Coinbase/Utils.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index fb4eb3e44..88218ab9c 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs b/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs index b8e5985bd..c0cfe6f4c 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Coinium.Utils.Configuration; diff --git a/src/CoiniumServ/Coin/Config/ICoinConfig.cs b/src/CoiniumServ/Coin/Config/ICoinConfig.cs index d9574fc09..3915e6320 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Utils.Configuration; namespace Coinium.Coin.Config diff --git a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs b/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs index f842c4f89..bd7ad24ec 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Helpers/Amount.cs b/src/CoiniumServ/Coin/Helpers/Amount.cs index 45f3002fc..4b2e4d2b7 100644 --- a/src/CoiniumServ/Coin/Helpers/Amount.cs +++ b/src/CoiniumServ/Coin/Helpers/Amount.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Coin/Helpers/Hashrate.cs b/src/CoiniumServ/Coin/Helpers/Hashrate.cs index 381530257..1d097fbaa 100644 --- a/src/CoiniumServ/Coin/Helpers/Hashrate.cs +++ b/src/CoiniumServ/Coin/Helpers/Hashrate.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs index c7c019f82..f35030112 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs index 5de821c03..6425d9feb 100644 --- a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Serilog; diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs index 7cd3a8abc..0826544cb 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs index 19f5de598..c66bf0f7e 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs index d16d4d48d..28e063a15 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Hash.cs b/src/CoiniumServ/Crypto/Hash.cs index 60aa5ee7e..8fd13e656 100644 --- a/src/CoiniumServ/Crypto/Hash.cs +++ b/src/CoiniumServ/Crypto/Hash.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs index efa2aa945..2fa75a1e9 100644 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs +++ b/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Crypto.Merkle diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs index 8d9dcde57..2beaf5f16 100644 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs +++ b/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Crypto.Merkle diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs index 7b3fe779e..ae9288710 100644 --- a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs +++ b/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using Coinium.Utils.Extensions; diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs index b1e7474b7..56df2955d 100644 --- a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs +++ b/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using System.Linq; using Coinium.Utils.Extensions; diff --git a/src/CoiniumServ/Crypto/Utils.cs b/src/CoiniumServ/Crypto/Utils.cs index 9e48f2b13..30e367007 100644 --- a/src/CoiniumServ/Crypto/Utils.cs +++ b/src/CoiniumServ/Crypto/Utils.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs index 222677847..c63cfa718 100644 --- a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs index 1b7b2362b..a356f24bd 100644 --- a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Utils.Configuration; diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 3d15d6d56..9bfbd16fd 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.IO; using System.Net; diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 46f098446..9ec3f89f0 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Daemon/DaemonError.cs b/src/CoiniumServ/Daemon/DaemonError.cs index 5bbd71a77..2424949a9 100644 --- a/src/CoiniumServ/Daemon/DaemonError.cs +++ b/src/CoiniumServ/Daemon/DaemonError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Newtonsoft.Json; namespace Coinium.Daemon diff --git a/src/CoiniumServ/Daemon/DaemonRequest.cs b/src/CoiniumServ/Daemon/DaemonRequest.cs index df1e5c417..345d5a7e8 100644 --- a/src/CoiniumServ/Daemon/DaemonRequest.cs +++ b/src/CoiniumServ/Daemon/DaemonRequest.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/CoiniumServ/Daemon/DaemonResponse.cs b/src/CoiniumServ/Daemon/DaemonResponse.cs index 5ef42e668..01154a4ea 100644 --- a/src/CoiniumServ/Daemon/DaemonResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonResponse.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Newtonsoft.Json; namespace Coinium.Daemon diff --git a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs b/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs index c699bbc94..bbd20db78 100644 --- a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs +++ b/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Daemon.Exceptions diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 5c5e8914d..a3c8a0290 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon.Config; using Coinium.Daemon.Responses; diff --git a/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs b/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs index b3de18605..48f24d1fd 100644 --- a/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Requests diff --git a/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs b/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs index 6108a7896..2ad10c1e3 100644 --- a/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs +++ b/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Newtonsoft.Json; namespace Coinium.Daemon.Requests diff --git a/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs b/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs index 3ae6bfb2c..96b1bb6a7 100644 --- a/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Requests diff --git a/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs b/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs index b249ed1e0..b77394844 100644 --- a/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs +++ b/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Newtonsoft.Json; namespace Coinium.Daemon.Requests diff --git a/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs b/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs index fff2ee421..dbe3e2e05 100644 --- a/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/Block.cs b/src/CoiniumServ/Daemon/Responses/Block.cs index cf4dfcc03..ea4519d36 100644 --- a/src/CoiniumServ/Daemon/Responses/Block.cs +++ b/src/CoiniumServ/Daemon/Responses/Block.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; diff --git a/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs b/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs index 556cf0490..66b618d22 100644 --- a/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs +++ b/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; diff --git a/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs b/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs index eadca4e5c..75927f5ba 100644 --- a/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs b/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs index 1515961e9..e40c96958 100644 --- a/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs b/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs index 33b8877c9..8f8cc39a0 100644 --- a/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs +++ b/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; diff --git a/src/CoiniumServ/Daemon/Responses/Info.cs b/src/CoiniumServ/Daemon/Responses/Info.cs index a6adb4bd4..8d2c355a4 100644 --- a/src/CoiniumServ/Daemon/Responses/Info.cs +++ b/src/CoiniumServ/Daemon/Responses/Info.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs index 28faaf47f..af698c8ec 100644 --- a/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs index 129cc08db..491783123 100644 --- a/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/ListTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListTransaction.cs index 17f484ea6..bf2d88b96 100644 --- a/src/CoiniumServ/Daemon/Responses/ListTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs index cc594462c..6be47e871 100644 --- a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs b/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs index ed044c106..dc39e9e34 100644 --- a/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/NodeAddress.cs b/src/CoiniumServ/Daemon/Responses/NodeAddress.cs index a5199afad..89d4aeaf4 100644 --- a/src/CoiniumServ/Daemon/Responses/NodeAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/NodeAddress.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/PeerInfo.cs b/src/CoiniumServ/Daemon/Responses/PeerInfo.cs index a5d8319f7..ce7621831 100644 --- a/src/CoiniumServ/Daemon/Responses/PeerInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/PeerInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs b/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs index d4bad7bb7..f3d02e542 100644 --- a/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index feced9ef6..c77b4c159 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs index 779abf232..f3f660c6f 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs b/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs index 5a0f53261..53edb8c77 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs b/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs index dc5fc8f85..d210ef8c5 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs b/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs index 6fff480ce..99876093f 100644 --- a/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs b/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs index ebc4fce9d..ebdfe4525 100644 --- a/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs b/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs index 507381767..06bae4219 100644 --- a/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/Work.cs b/src/CoiniumServ/Daemon/Responses/Work.cs index 87c8d31b7..ffd67c55a 100644 --- a/src/CoiniumServ/Daemon/Responses/Work.cs +++ b/src/CoiniumServ/Daemon/Responses/Work.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs index 4d1fc9724..51b5a2f84 100644 --- a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs index e32d943f9..0e4007024 100644 --- a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs b/src/CoiniumServ/Mining/Jobs/IJobCounter.cs index b967295b9..38c5fcb40 100644 --- a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs +++ b/src/CoiniumServ/Mining/Jobs/IJobCounter.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/JobCounter.cs b/src/CoiniumServ/Mining/Jobs/JobCounter.cs index d9998a39e..7f2bada54 100644 --- a/src/CoiniumServ/Mining/Jobs/JobCounter.cs +++ b/src/CoiniumServ/Mining/Jobs/JobCounter.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs index 6aa7238ca..75ee95019 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Mining.Jobs.Manager diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs index bf9080d32..809566019 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index cad46b65d..51ad27c4f 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Threading; diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs index 6b05c450a..859a2dbed 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs index 156bd26fa..bd12579be 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Server.Stratum.Notifications; diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs index 901e9c504..96047fa8c 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs index e56dfa716..c9b4cf08f 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using Coinium.Server.Stratum.Notifications; diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs index 4ad1ea786..23b348ff1 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; namespace Coinium.Mining.Jobs.Tracker diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Mining/Miners/IMiner.cs index ae0ba3d29..b4ae9fab0 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Mining/Miners/IMiner.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools; using Coinium.Server.Stratum.Notifications; diff --git a/src/CoiniumServ/Mining/Miners/IMinerManager.cs b/src/CoiniumServ/Mining/Miners/IMinerManager.cs index 94f0a99f7..d6ef3c24d 100644 --- a/src/CoiniumServ/Mining/Miners/IMinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/IMinerManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs index c2ee2da48..2cae2adeb 100644 --- a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs +++ b/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; namespace Coinium.Mining.Miners diff --git a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs b/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs index 66d87b678..7bb40fa3d 100644 --- a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs +++ b/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Mining.Miners diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index 790dff006..3e406af7d 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs index 18de5bef0..547367a2d 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Repository.Context; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index f62b9ec9b..c1f661ed2 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Coin.Config; using Coinium.Daemon.Config; using Coinium.Server.Stratum.Config; diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs index 546baa969..bee5d40ce 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index edc10663b..054e266e6 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs index 2acc4cecb..fbae33b19 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Coin.Config; using Coinium.Repository.Context; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index a6cd89b05..1406bf901 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolFactory.cs index 5b261d979..3cab87213 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index acb0eb538..cafa2fe82 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index ea0aa2034..09b6cfe56 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Pools/PoolFactory.cs b/src/CoiniumServ/Mining/Pools/PoolFactory.cs index 404f3b27e..9f3b07a57 100644 --- a/src/CoiniumServ/Mining/Pools/PoolFactory.cs +++ b/src/CoiniumServ/Mining/Pools/PoolFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools.Config; using Coinium.Repository.Context; using Serilog; diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 18e4500aa..3f86acdbb 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Shares/IShare.cs b/src/CoiniumServ/Mining/Shares/IShare.cs index ef979d2e9..ce720998b 100644 --- a/src/CoiniumServ/Mining/Shares/IShare.cs +++ b/src/CoiniumServ/Mining/Shares/IShare.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Shares/IShareManager.cs b/src/CoiniumServ/Mining/Shares/IShareManager.cs index 77d556528..71a0dcde3 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Server.Stratum; using Coinium.Server.Vanilla; diff --git a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs index a6d27e5f2..7b21a72e4 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; using Coinium.Persistance; diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index a50cf4ffc..622d511f2 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Shares/ShareError.cs b/src/CoiniumServ/Mining/Shares/ShareError.cs index 4745c7fb8..d10f31561 100644 --- a/src/CoiniumServ/Mining/Shares/ShareError.cs +++ b/src/CoiniumServ/Mining/Shares/ShareError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 4b49ae61f..bff60b0c5 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs index 029a1fcf8..965c93373 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Mining.Jobs; using Coinium.Mining.Jobs.Manager; diff --git a/src/CoiniumServ/Net/Server/Http/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/HttpServer.cs index 5cd9f7f61..ea9d50d17 100644 --- a/src/CoiniumServ/Net/Server/Http/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/HttpServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/IServer.cs b/src/CoiniumServ/Net/Server/IServer.cs index f2a5fb55c..b0c8fb10a 100644 --- a/src/CoiniumServ/Net/Server/IServer.cs +++ b/src/CoiniumServ/Net/Server/IServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/Connection.cs b/src/CoiniumServ/Net/Server/Sockets/Connection.cs index 7f2eee318..b44632966 100644 --- a/src/CoiniumServ/Net/Server/Sockets/Connection.cs +++ b/src/CoiniumServ/Net/Server/Sockets/Connection.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs b/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs index 595d91259..54fa6e9b5 100644 --- a/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs +++ b/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs b/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs index 0d2c65d14..bdaf232c1 100644 --- a/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs +++ b/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/IClient.cs b/src/CoiniumServ/Net/Server/Sockets/IClient.cs index dc01d4adb..7735a6cf6 100644 --- a/src/CoiniumServ/Net/Server/Sockets/IClient.cs +++ b/src/CoiniumServ/Net/Server/Sockets/IClient.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/IConnection.cs b/src/CoiniumServ/Net/Server/Sockets/IConnection.cs index a3c7a06ce..cfb71b694 100644 --- a/src/CoiniumServ/Net/Server/Sockets/IConnection.cs +++ b/src/CoiniumServ/Net/Server/Sockets/IConnection.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs index 3b0013991..c55727d21 100644 --- a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index c6f7a1a30..7850a69f3 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Persistance/IStorageFactory.cs b/src/CoiniumServ/Persistance/IStorageFactory.cs index eabf0d83e..0ac204528 100644 --- a/src/CoiniumServ/Persistance/IStorageFactory.cs +++ b/src/CoiniumServ/Persistance/IStorageFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Persistance/Redis/IRedis.cs b/src/CoiniumServ/Persistance/Redis/IRedis.cs index 844afc170..21b673872 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedis.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedis.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Persistance.Redis diff --git a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs index ef50b51e6..fc96e10f5 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Persistance.Redis diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index c46f7a47b..206987722 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs index aa04698f3..a9d54b77a 100644 --- a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs index 41e04daa3..6d05055b6 100644 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ b/src/CoiniumServ/Persistance/StorageFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Nancy.TinyIoc; using Serilog; diff --git a/src/CoiniumServ/Persistance/Storages.cs b/src/CoiniumServ/Persistance/Storages.cs index 5e8dc1650..7e7ed64c1 100644 --- a/src/CoiniumServ/Persistance/Storages.cs +++ b/src/CoiniumServ/Persistance/Storages.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 95fb2637f..ab1f457c2 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Properties/AssemblyInfo.cs b/src/CoiniumServ/Properties/AssemblyInfo.cs index 60b68ad27..12a30bdfe 100644 --- a/src/CoiniumServ/Properties/AssemblyInfo.cs +++ b/src/CoiniumServ/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Repository/Bootstrapper.cs b/src/CoiniumServ/Repository/Bootstrapper.cs index c2ea0fb0b..3d646b55b 100644 --- a/src/CoiniumServ/Repository/Bootstrapper.cs +++ b/src/CoiniumServ/Repository/Bootstrapper.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Coinium.Repository.Registries; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Repository/Context/ApplicationContext.cs b/src/CoiniumServ/Repository/Context/ApplicationContext.cs index 09e42e15f..e1df2198e 100644 --- a/src/CoiniumServ/Repository/Context/ApplicationContext.cs +++ b/src/CoiniumServ/Repository/Context/ApplicationContext.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Nancy.TinyIoc; namespace Coinium.Repository.Context diff --git a/src/CoiniumServ/Repository/Context/IApplicationContext.cs b/src/CoiniumServ/Repository/Context/IApplicationContext.cs index 99c8472f4..4d2d87f01 100644 --- a/src/CoiniumServ/Repository/Context/IApplicationContext.cs +++ b/src/CoiniumServ/Repository/Context/IApplicationContext.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Nancy.TinyIoc; namespace Coinium.Repository.Context diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 29bd1f824..7f2ddc7cd 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 065d57f21..e76ed64a5 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Coin.Config; using Coinium.Crypto.Algorithms; using Coinium.Mining.Jobs; diff --git a/src/CoiniumServ/Repository/Registries/IRegistry.cs b/src/CoiniumServ/Repository/Registries/IRegistry.cs index cc9614846..3c2d068b5 100644 --- a/src/CoiniumServ/Repository/Registries/IRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/IRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index d7a9287e7..b155b0987 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs; using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index fc55d6e70..b4b424bc9 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using Coinium.Repository.Context; diff --git a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs index 92116cd58..7aabacfac 100644 --- a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Coinium.Server; using Coinium.Server.Stratum; diff --git a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs index e7909598d..a17bac675 100644 --- a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Coinium.Service; using Coinium.Service.Stratum; diff --git a/src/CoiniumServ/Server/Commands/Server.cs b/src/CoiniumServ/Server/Commands/Server.cs index 5345873e5..74054ae07 100644 --- a/src/CoiniumServ/Server/Commands/Server.cs +++ b/src/CoiniumServ/Server/Commands/Server.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Commands/Stats.cs b/src/CoiniumServ/Server/Commands/Stats.cs index 158f609cc..cf2d7d87a 100644 --- a/src/CoiniumServ/Server/Commands/Stats.cs +++ b/src/CoiniumServ/Server/Commands/Stats.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Commands/Uptime.cs b/src/CoiniumServ/Server/Commands/Uptime.cs index de677c78e..2759595fe 100644 --- a/src/CoiniumServ/Server/Commands/Uptime.cs +++ b/src/CoiniumServ/Server/Commands/Uptime.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Commands/Version.cs b/src/CoiniumServ/Server/Commands/Version.cs index e6ba905b1..f9f34b2b2 100644 --- a/src/CoiniumServ/Server/Commands/Version.cs +++ b/src/CoiniumServ/Server/Commands/Version.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Config/IServerConfig.cs b/src/CoiniumServ/Server/Config/IServerConfig.cs index 6403574c0..948182b0c 100644 --- a/src/CoiniumServ/Server/Config/IServerConfig.cs +++ b/src/CoiniumServ/Server/Config/IServerConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/IMiningServer.cs b/src/CoiniumServ/Server/IMiningServer.cs index 6f4326606..cfd300292 100644 --- a/src/CoiniumServ/Server/IMiningServer.cs +++ b/src/CoiniumServ/Server/IMiningServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Net.Server; using Coinium.Server.Config; diff --git a/src/CoiniumServ/Server/IServerFactory.cs b/src/CoiniumServ/Server/IServerFactory.cs index 60a760bd4..6bde536cf 100644 --- a/src/CoiniumServ/Server/IServerFactory.cs +++ b/src/CoiniumServ/Server/IServerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; using Coinium.Mining.Pools; diff --git a/src/CoiniumServ/Server/ServerFactory.cs b/src/CoiniumServ/Server/ServerFactory.cs index e0c366183..49d6ac2fd 100644 --- a/src/CoiniumServ/Server/ServerFactory.cs +++ b/src/CoiniumServ/Server/ServerFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; using Coinium.Mining.Pools; diff --git a/src/CoiniumServ/Server/ServerManager.cs b/src/CoiniumServ/Server/ServerManager.cs index 4ddcc47cd..6fd627453 100644 --- a/src/CoiniumServ/Server/ServerManager.cs +++ b/src/CoiniumServ/Server/ServerManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Stratum/Config/IStratumServerConfig.cs index 23fc5f7fc..62431c752 100644 --- a/src/CoiniumServ/Server/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Stratum/Config/IStratumServerConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Stratum/Config/StratumServerConfig.cs index 3ac4d3df8..ed3fd2680 100644 --- a/src/CoiniumServ/Server/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Stratum/Config/StratumServerConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/AuthenticationError.cs b/src/CoiniumServ/Server/Stratum/Errors/AuthenticationError.cs index b88dcbe9b..bdf298c93 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/AuthenticationError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/AuthenticationError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/DuplicateShareError.cs b/src/CoiniumServ/Server/Stratum/Errors/DuplicateShareError.cs index ee2386cea..057b4ae27 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/DuplicateShareError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/DuplicateShareError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/IStratumError.cs b/src/CoiniumServ/Server/Stratum/Errors/IStratumError.cs index 0d54b9168..64d36da5c 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/IStratumError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/IStratumError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/JobNotFoundError.cs b/src/CoiniumServ/Server/Stratum/Errors/JobNotFoundError.cs index af4a3d807..070fa65d3 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/JobNotFoundError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/JobNotFoundError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/LowDifficultyShare.cs b/src/CoiniumServ/Server/Stratum/Errors/LowDifficultyShare.cs index faaa28e43..9bdce5351 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/LowDifficultyShare.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/LowDifficultyShare.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/NotSubscriberError.cs b/src/CoiniumServ/Server/Stratum/Errors/NotSubscriberError.cs index f9e7229ed..c624488d2 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/NotSubscriberError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/NotSubscriberError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Errors/OtherError.cs b/src/CoiniumServ/Server/Stratum/Errors/OtherError.cs index 88b4e89ef..bc8317824 100644 --- a/src/CoiniumServ/Server/Stratum/Errors/OtherError.cs +++ b/src/CoiniumServ/Server/Stratum/Errors/OtherError.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Stratum/IStratumMiner.cs index cfbb05902..495ff33ef 100644 --- a/src/CoiniumServ/Server/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Stratum/IStratumMiner.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Notifications/Difficulty.cs b/src/CoiniumServ/Server/Stratum/Notifications/Difficulty.cs index 68600c9f4..4c4ed304c 100644 --- a/src/CoiniumServ/Server/Stratum/Notifications/Difficulty.cs +++ b/src/CoiniumServ/Server/Stratum/Notifications/Difficulty.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Notifications/IJob.cs b/src/CoiniumServ/Server/Stratum/Notifications/IJob.cs index 4660cf0f5..08c9dd72a 100644 --- a/src/CoiniumServ/Server/Stratum/Notifications/IJob.cs +++ b/src/CoiniumServ/Server/Stratum/Notifications/IJob.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Stratum/Notifications/Job.cs index 2003a84be..b8cf994c5 100644 --- a/src/CoiniumServ/Server/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Stratum/Notifications/Job.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/Responses/SubscribeResponse.cs b/src/CoiniumServ/Server/Stratum/Responses/SubscribeResponse.cs index 5732fd274..0eeb148c6 100644 --- a/src/CoiniumServ/Server/Stratum/Responses/SubscribeResponse.cs +++ b/src/CoiniumServ/Server/Stratum/Responses/SubscribeResponse.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Stratum/StratumMiner.cs index a992d41d2..349260544 100644 --- a/src/CoiniumServ/Server/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Stratum/StratumMiner.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Stratum/StratumServer.cs index c44ba4077..38d12a543 100644 --- a/src/CoiniumServ/Server/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Stratum/StratumServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; using Coinium.Mining.Pools; diff --git a/src/CoiniumServ/Server/Vanilla/Config/IVanillaServerConfig.cs b/src/CoiniumServ/Server/Vanilla/Config/IVanillaServerConfig.cs index bfafe95cf..264c3e1ad 100644 --- a/src/CoiniumServ/Server/Vanilla/Config/IVanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Vanilla/Config/IVanillaServerConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Vanilla/Config/VanillaServerConfig.cs index 893ba8a99..90e236ef6 100644 --- a/src/CoiniumServ/Server/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Vanilla/Config/VanillaServerConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Vanilla/VanillaMiner.cs index b70caf2b5..29d63b38f 100644 --- a/src/CoiniumServ/Server/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Vanilla/VanillaMiner.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Vanilla/VanillaServer.cs index 64abe130a..822068c5b 100644 --- a/src/CoiniumServ/Server/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Vanilla/VanillaServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Web/Modules/Stats.cs b/src/CoiniumServ/Server/Web/Modules/Stats.cs index df755e0b2..31a2960dd 100644 --- a/src/CoiniumServ/Server/Web/Modules/Stats.cs +++ b/src/CoiniumServ/Server/Web/Modules/Stats.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index d015cff6b..208ea29fb 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Service/IRpcService.cs b/src/CoiniumServ/Service/IRpcService.cs index 1e00431c8..1f5d64c32 100644 --- a/src/CoiniumServ/Service/IRpcService.cs +++ b/src/CoiniumServ/Service/IRpcService.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Service/IServiceFactory.cs b/src/CoiniumServ/Service/IServiceFactory.cs index a68cf8c43..0e99f948f 100644 --- a/src/CoiniumServ/Service/IServiceFactory.cs +++ b/src/CoiniumServ/Service/IServiceFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Mining.Shares; diff --git a/src/CoiniumServ/Service/ServiceFactory.cs b/src/CoiniumServ/Service/ServiceFactory.cs index 0b2ae4f2f..f6ee17002 100644 --- a/src/CoiniumServ/Service/ServiceFactory.cs +++ b/src/CoiniumServ/Service/ServiceFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Mining.Shares; using Coinium.Repository.Context; diff --git a/src/CoiniumServ/Service/Services.cs b/src/CoiniumServ/Service/Services.cs index 105a4d276..06c5d20e4 100644 --- a/src/CoiniumServ/Service/Services.cs +++ b/src/CoiniumServ/Service/Services.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs b/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs index 14d4de966..4e40acd5c 100644 --- a/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs +++ b/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Miners; namespace Coinium.Service.Stratum diff --git a/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs b/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs index 7f7389fdd..f1105661c 100644 --- a/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs +++ b/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Newtonsoft.Json; namespace Coinium.Service.Stratum diff --git a/src/CoiniumServ/Service/Stratum/StratumService.cs b/src/CoiniumServ/Service/Stratum/StratumService.cs index 9d109759a..cb7e539e0 100644 --- a/src/CoiniumServ/Service/Stratum/StratumService.cs +++ b/src/CoiniumServ/Service/Stratum/StratumService.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; using Coinium.Mining.Jobs; using Coinium.Mining.Shares; diff --git a/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs b/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs index f3eb2fab4..7dc9f5e40 100644 --- a/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs +++ b/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Miners; namespace Coinium.Service.Vanilla diff --git a/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs b/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs index 5f46013a3..bf4ab05ba 100644 --- a/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs +++ b/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Net; using Newtonsoft.Json; diff --git a/src/CoiniumServ/Service/Vanilla/VanillaService.cs b/src/CoiniumServ/Service/Vanilla/VanillaService.cs index 5834bf291..d8c8a550c 100644 --- a/src/CoiniumServ/Service/Vanilla/VanillaService.cs +++ b/src/CoiniumServ/Service/Vanilla/VanillaService.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; using Coinium.Daemon; using Coinium.Daemon.Responses; diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 0df00e74f..c570e588c 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/IGenerationTransaction.cs b/src/CoiniumServ/Transactions/IGenerationTransaction.cs index ce3131952..bdebff3ff 100644 --- a/src/CoiniumServ/Transactions/IGenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/IGenerationTransaction.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/IOutputs.cs b/src/CoiniumServ/Transactions/IOutputs.cs index 2f03574f5..8eaa7b4ae 100644 --- a/src/CoiniumServ/Transactions/IOutputs.cs +++ b/src/CoiniumServ/Transactions/IOutputs.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/OutPoint.cs b/src/CoiniumServ/Transactions/OutPoint.cs index 3bc0e2977..9d06cf75c 100644 --- a/src/CoiniumServ/Transactions/OutPoint.cs +++ b/src/CoiniumServ/Transactions/OutPoint.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/Outputs.cs b/src/CoiniumServ/Transactions/Outputs.cs index 31fad8a87..458d75642 100644 --- a/src/CoiniumServ/Transactions/Outputs.cs +++ b/src/CoiniumServ/Transactions/Outputs.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/Script/ISignatureScript.cs b/src/CoiniumServ/Transactions/Script/ISignatureScript.cs index fa18ff6a4..45b7b08b5 100644 --- a/src/CoiniumServ/Transactions/Script/ISignatureScript.cs +++ b/src/CoiniumServ/Transactions/Script/ISignatureScript.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/Script/SignatureScript.cs b/src/CoiniumServ/Transactions/Script/SignatureScript.cs index bbbee0ec8..970fe932f 100644 --- a/src/CoiniumServ/Transactions/Script/SignatureScript.cs +++ b/src/CoiniumServ/Transactions/Script/SignatureScript.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/TxIn.cs b/src/CoiniumServ/Transactions/TxIn.cs index 3b699ca6f..d7c9eabbe 100644 --- a/src/CoiniumServ/Transactions/TxIn.cs +++ b/src/CoiniumServ/Transactions/TxIn.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/TxOut.cs b/src/CoiniumServ/Transactions/TxOut.cs index 11f69728f..fdb283ac2 100644 --- a/src/CoiniumServ/Transactions/TxOut.cs +++ b/src/CoiniumServ/Transactions/TxOut.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs b/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs index 99e28d6ec..21f5ec69b 100644 --- a/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs +++ b/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Utils/Commands/CommandAttributes.cs b/src/CoiniumServ/Utils/Commands/CommandAttributes.cs index 3befee16c..022c775dd 100644 --- a/src/CoiniumServ/Utils/Commands/CommandAttributes.cs +++ b/src/CoiniumServ/Utils/Commands/CommandAttributes.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Commands diff --git a/src/CoiniumServ/Utils/Commands/CommandGroup.cs b/src/CoiniumServ/Utils/Commands/CommandGroup.cs index 644830c1b..0ee199cdd 100644 --- a/src/CoiniumServ/Utils/Commands/CommandGroup.cs +++ b/src/CoiniumServ/Utils/Commands/CommandGroup.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using System.Linq; using System.Reflection; diff --git a/src/CoiniumServ/Utils/Commands/CommandManager.cs b/src/CoiniumServ/Utils/Commands/CommandManager.cs index c1254e8e6..5bb9bd663 100644 --- a/src/CoiniumServ/Utils/Commands/CommandManager.cs +++ b/src/CoiniumServ/Utils/Commands/CommandManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs index f30a6184f..7fd4d701c 100644 --- a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Persistance.Redis; using Coinium.Repository.Context; diff --git a/src/CoiniumServ/Utils/Configuration/IConfig.cs b/src/CoiniumServ/Utils/Configuration/IConfig.cs index 4a57dd84e..7dfb9605b 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfig.cs +++ b/src/CoiniumServ/Utils/Configuration/IConfig.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs index 45c12d6d1..a951919a4 100644 --- a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Persistance.Redis; namespace Coinium.Utils.Configuration diff --git a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs b/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs index f35f69686..688cfe1bc 100644 --- a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs +++ b/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using JsonConfig; using Serilog; diff --git a/src/CoiniumServ/Utils/Console/ConsoleWindow.cs b/src/CoiniumServ/Utils/Console/ConsoleWindow.cs index 34fe8a763..6ddd5b24b 100644 --- a/src/CoiniumServ/Utils/Console/ConsoleWindow.cs +++ b/src/CoiniumServ/Utils/Console/ConsoleWindow.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Console diff --git a/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs b/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs index eed6c2f0a..8d3a089a9 100644 --- a/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.IO; diff --git a/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs b/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs index 243728d4a..c4d8bac93 100644 --- a/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs b/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs index b907fd096..bc537e65c 100644 --- a/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Text; namespace Coinium.Utils.Extensions diff --git a/src/CoiniumServ/Utils/Extensions/StringExtensions.cs b/src/CoiniumServ/Utils/Extensions/StringExtensions.cs index 057921080..46c1dfcc5 100644 --- a/src/CoiniumServ/Utils/Extensions/StringExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/StringExtensions.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Extensions diff --git a/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs b/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs index 5207df94f..59cd46fed 100644 --- a/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Helpers.Arrays diff --git a/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs b/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs index 229bca83b..be375a9d7 100644 --- a/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.IO; diff --git a/src/CoiniumServ/Utils/Helpers/Misc/Range.cs b/src/CoiniumServ/Utils/Helpers/Misc/Range.cs index 24769e70f..eedf52c50 100644 --- a/src/CoiniumServ/Utils/Helpers/Misc/Range.cs +++ b/src/CoiniumServ/Utils/Helpers/Misc/Range.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections; using System.Collections.Generic; diff --git a/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs b/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs index 54eec3f58..425076f49 100644 --- a/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Helpers.Time diff --git a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs index 2f430019f..03735a38b 100644 --- a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs +++ b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq.Expressions; diff --git a/src/CoiniumServ/Utils/Logging/Logging.cs b/src/CoiniumServ/Utils/Logging/Logging.cs index 0d068e579..f060d2096 100644 --- a/src/CoiniumServ/Utils/Logging/Logging.cs +++ b/src/CoiniumServ/Utils/Logging/Logging.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.IO; using System.Linq; diff --git a/src/CoiniumServ/Utils/Numerics/BigInteger.cs b/src/CoiniumServ/Utils/Numerics/BigInteger.cs index 099cf07a3..4a2e7805c 100644 --- a/src/CoiniumServ/Utils/Numerics/BigInteger.cs +++ b/src/CoiniumServ/Utils/Numerics/BigInteger.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Globalization; diff --git a/src/CoiniumServ/Utils/Numerics/BigRational.cs b/src/CoiniumServ/Utils/Numerics/BigRational.cs index 7fcc5a625..73c4e8fa7 100644 --- a/src/CoiniumServ/Utils/Numerics/BigRational.cs +++ b/src/CoiniumServ/Utils/Numerics/BigRational.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Globalization; using System.Runtime.InteropServices; diff --git a/src/CoiniumServ/Utils/Platform/Framework.cs b/src/CoiniumServ/Utils/Platform/Framework.cs index 334144cda..fcd1430b4 100644 --- a/src/CoiniumServ/Utils/Platform/Framework.cs +++ b/src/CoiniumServ/Utils/Platform/Framework.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServ/Utils/Platform/PlatformManager.cs b/src/CoiniumServ/Utils/Platform/PlatformManager.cs index 4fb6ef986..3248a7850 100644 --- a/src/CoiniumServ/Utils/Platform/PlatformManager.cs +++ b/src/CoiniumServ/Utils/Platform/PlatformManager.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Utils.Platform diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index c8027c680..f011fa720 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServGui/MainForm.cs b/src/CoiniumServGui/MainForm.cs index a713bfb8e..cd1497deb 100644 --- a/src/CoiniumServGui/MainForm.cs +++ b/src/CoiniumServGui/MainForm.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServGui/Program.cs b/src/CoiniumServGui/Program.cs index 4ec537ef1..cee6eda49 100644 --- a/src/CoiniumServGui/Program.cs +++ b/src/CoiniumServGui/Program.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/CoiniumServGui/Properties/AssemblyInfo.cs b/src/CoiniumServGui/Properties/AssemblyInfo.cs index 371b44427..8a46d6307 100644 --- a/src/CoiniumServGui/Properties/AssemblyInfo.cs +++ b/src/CoiniumServGui/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Coin/AmountTests.cs b/src/Tests/Coin/AmountTests.cs index e194c8bfb..b97794ef3 100644 --- a/src/Tests/Coin/AmountTests.cs +++ b/src/Tests/Coin/AmountTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Coin/Base58Test.cs b/src/Tests/Coin/Base58Test.cs index 41a09d0be..1c771a3ad 100644 --- a/src/Tests/Coin/Base58Test.cs +++ b/src/Tests/Coin/Base58Test.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index 74542722d..4b6d22837 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Coin/Coinbase/UtilsTests.cs b/src/Tests/Coin/Coinbase/UtilsTests.cs index a6a7e1a09..a31f8810a 100644 --- a/src/Tests/Coin/Coinbase/UtilsTests.cs +++ b/src/Tests/Coin/Coinbase/UtilsTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Crypto/Merkle/MerkleRootTests.cs b/src/Tests/Crypto/Merkle/MerkleRootTests.cs index 940c764de..878d67bb9 100644 --- a/src/Tests/Crypto/Merkle/MerkleRootTests.cs +++ b/src/Tests/Crypto/Merkle/MerkleRootTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using Coinium.Crypto.Merkle; using Coinium.Utils.Extensions; diff --git a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs b/src/Tests/Crypto/Merkle/MerkleTreeTests.cs index 98fc947c7..c882027f5 100644 --- a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs +++ b/src/Tests/Crypto/Merkle/MerkleTreeTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Linq; using Coinium.Crypto.Merkle; using Coinium.Daemon; diff --git a/src/Tests/Daemon/BlockTemplateTests.cs b/src/Tests/Daemon/BlockTemplateTests.cs index a3adddc0c..81d4ec0a1 100644 --- a/src/Tests/Daemon/BlockTemplateTests.cs +++ b/src/Tests/Daemon/BlockTemplateTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using Coinium.Daemon; using Coinium.Daemon.Responses; diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 338e19688..3a3172dbc 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index 617772c17..472794951 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Properties/AssemblyInfo.cs b/src/Tests/Properties/AssemblyInfo.cs index 17c611d10..5bd928249 100644 --- a/src/Tests/Properties/AssemblyInfo.cs +++ b/src/Tests/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index 2531a68cd..198e0bf4c 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index 93b37bd9a..4e4df87b3 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Transactions/OutputsTests.cs b/src/Tests/Transactions/OutputsTests.cs index 85a10785a..f29b2fd39 100644 --- a/src/Tests/Transactions/OutputsTests.cs +++ b/src/Tests/Transactions/OutputsTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Transactions/Script/SignatureScriptTests.cs b/src/Tests/Transactions/Script/SignatureScriptTests.cs index f15f4e895..1408985d2 100644 --- a/src/Tests/Transactions/Script/SignatureScriptTests.cs +++ b/src/Tests/Transactions/Script/SignatureScriptTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Jobs; diff --git a/src/Tests/Transactions/Utils/TransactionUtilsTests.cs b/src/Tests/Transactions/Utils/TransactionUtilsTests.cs index 7353d8fae..74f94528e 100644 --- a/src/Tests/Transactions/Utils/TransactionUtilsTests.cs +++ b/src/Tests/Transactions/Utils/TransactionUtilsTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 diff --git a/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs b/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs index 3653290e5..34bf18736 100644 --- a/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs +++ b/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Linq; using Coinium.Utils.Extensions; using Should.Fluent; diff --git a/src/Tests/Utils/Extensions/StringExtensionsTests.cs b/src/Tests/Utils/Extensions/StringExtensionsTests.cs index 5d60dc7e5..7a4213d10 100644 --- a/src/Tests/Utils/Extensions/StringExtensionsTests.cs +++ b/src/Tests/Utils/Extensions/StringExtensionsTests.cs @@ -2,7 +2,7 @@ // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org -// https://github.com/CoiniumServ/CoiniumServ +// 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 @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Utils.Extensions; using Should.Fluent; using Xunit; From 139281abb0eb264106eb23543a35078decdd9697 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 3 Jul 2014 13:42:46 +0300 Subject: [PATCH 014/230] Started implementing payment processor. Renamed config.json database to storage. Improved job-manager. --- assets/config/config-sample.json | 4 +- src/CoiniumServ/CoiniumServ.csproj | 6 ++ .../Mining/Jobs/Manager/JobManager.cs | 23 +++--- .../Mining/Pools/Config/IPoolConfig.cs | 3 + .../Mining/Pools/Config/PoolConfig.cs | 10 +++ src/CoiniumServ/Mining/Pools/Pool.cs | 52 ++++++------ src/CoiniumServ/Payments/IPaymentConfig.cs | 36 +++++++++ src/CoiniumServ/Payments/IPaymentProcessor.cs | 32 ++++++++ .../Payments/IPaymentProcessorFactory.cs | 33 ++++++++ src/CoiniumServ/Payments/PaymentConfig.cs | 52 ++++++++++++ src/CoiniumServ/Payments/PaymentProcessor.cs | 68 ++++++++++++++++ .../Payments/PaymentProcessorFactory.cs | 58 ++++++++++++++ src/CoiniumServ/Persistance/StorageFactory.cs | 2 - .../Repository/Registries/ClassRegistry.cs | 2 + .../Repository/Registries/FactoryRegistry.cs | 2 + .../Configuration/GlobalConfigFactory.cs | 2 +- src/Tests/Mining/Pools/PoolTests.cs | 80 ++++++++++++------- 17 files changed, 396 insertions(+), 69 deletions(-) create mode 100644 src/CoiniumServ/Payments/IPaymentConfig.cs create mode 100644 src/CoiniumServ/Payments/IPaymentProcessor.cs create mode 100644 src/CoiniumServ/Payments/IPaymentProcessorFactory.cs create mode 100644 src/CoiniumServ/Payments/PaymentConfig.cs create mode 100644 src/CoiniumServ/Payments/PaymentProcessor.cs create mode 100644 src/CoiniumServ/Payments/PaymentProcessorFactory.cs diff --git a/assets/config/config-sample.json b/assets/config/config-sample.json index a441afd9d..0d033b4c3 100644 --- a/assets/config/config-sample.json +++ b/assets/config/config-sample.json @@ -32,8 +32,8 @@ "port": 80 }, - # database configuration. - "database": { + # storage configuration. + "storage": { "redis": { "enabled": true, "host": "127.0.0.1", diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index b63c19036..c92e06cd2 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -117,6 +117,12 @@ + + + + + + diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 51ad27c4f..0214fb48f 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -21,7 +21,6 @@ // #endregion using System; -using System.Collections.Generic; using System.Threading; using Coinium.Crypto.Algorithms; using Coinium.Daemon; @@ -79,21 +78,29 @@ public void Initialize(UInt32 instanceId) _minerManager.MinerAuthenticated += OnMinerAuthenticated; var job = GetNewJob(); // initially create a job. - _timer = new Timer(NewJobTimer, null, TimeSpan.Zero, _timeSpan); // setup a timer to broadcast jobs. + _timer = new Timer(IdleJobTimer, null, TimeSpan.Zero, _timeSpan); // setup a timer to broadcast jobs. } private void OnBlockFound(object sender, EventArgs e) { - var job = GetNewJob(); // create a new job. - var count = Broadcast(job); // broadcast to miners. - Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id, count); + BroadcastNewJob(false); } - private void NewJobTimer(object state) + private void IdleJobTimer(object state) + { + BroadcastNewJob(true); + } + + private void BroadcastNewJob(bool initiatedByTimer) { var job = GetNewJob(); // create a new job. var count = Broadcast(job); // broadcast to miners. - Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, TimerExpiration); + _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. + + if (initiatedByTimer) + Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.",job.Id, count, TimerExpiration); + else + Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id,count); } private void OnMinerAuthenticated(object sender, EventArgs e) @@ -157,8 +164,6 @@ private Int32 Broadcast(IJob job) count++; } - _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. - return count; } catch (Exception e) diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index c1f661ed2..b44ac6c63 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -22,6 +22,7 @@ #endregion using Coinium.Coin.Config; using Coinium.Daemon.Config; +using Coinium.Payments; using Coinium.Server.Stratum.Config; using Coinium.Server.Vanilla.Config; using Coinium.Utils.Configuration; @@ -42,5 +43,7 @@ public interface IPoolConfig:IConfig IVanillaServerConfig Vanilla { get; } IDaemonConfig Daemon { get; } + + IPaymentConfig Payments { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 054e266e6..f04855952 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -23,6 +23,7 @@ using System.IO; using Coinium.Coin.Config; using Coinium.Daemon.Config; +using Coinium.Payments; using Coinium.Server.Stratum.Config; using Coinium.Server.Vanilla.Config; @@ -51,6 +52,8 @@ public class PoolConfig : IPoolConfig /// public IDaemonConfig Daemon { get; private set; } + public IPaymentConfig Payments { get; private set; } + /// /// Initializes a new instance of the class. /// @@ -92,6 +95,13 @@ public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) return; } + Payments = new PaymentConfig(config.payments); + if (Payments == null) + { + Valid = false; + return; + } + Valid = true; } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 09b6cfe56..8c22c6d1e 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -32,12 +32,12 @@ using Coinium.Mining.Miners; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; +using Coinium.Payments; using Coinium.Persistance; using Coinium.Server; using Coinium.Service; using Coinium.Utils.Configuration; using Coinium.Utils.Helpers.Validation; -using HashLib; using Serilog; namespace Coinium.Mining.Pools @@ -57,15 +57,16 @@ public class Pool : IPool private readonly IShareManagerFactory _shareManagerFactory; private readonly IMinerManagerFactory _minerManagerFactory; private readonly IHashAlgorithmFactory _hashAlgorithmFactory; - private readonly IStorageFactory _storageManagerFactory; - private readonly IGlobalConfigFactory _globalConfigFactory; + private readonly IStorageFactory _storageFactory; + private readonly IPaymentProcessorFactory _paymentProcessorFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; private IJobManager _jobManager; private IShareManager _shareManager; - private IStorage _storageManager; + private IStorage _storage; private IHashAlgorithm _hashAlgorithm; + private IPaymentProcessor _paymentProcessor; private Dictionary _servers; @@ -85,8 +86,8 @@ public class Pool : IPool /// /// The job manager factory. /// The share manager factory. - /// - /// + /// + /// public Pool( IHashAlgorithmFactory hashAlgorithmFactory, IServerFactory serverFactory, @@ -96,8 +97,8 @@ public Pool( IJobTrackerFactory jobTrackerFactory, IJobManagerFactory jobManagerFactory, IShareManagerFactory shareManagerFactory, - IStorageFactory storageManagerFactory, - IGlobalConfigFactory globalConfigFactory) + IStorageFactory storageFactory, + IPaymentProcessorFactory paymentProcessorFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); @@ -107,8 +108,8 @@ public Pool( Enforce.ArgumentNotNull(jobTrackerFactory, "IJobTrackerFactory"); Enforce.ArgumentNotNull(jobManagerFactory, "IJobManagerFactory"); Enforce.ArgumentNotNull(shareManagerFactory, "IShareManagerFactory"); - Enforce.ArgumentNotNull(storageManagerFactory, "IStorageFactory"); - Enforce.ArgumentNotNull(globalConfigFactory, "IGlobalConfigFactory"); + Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); + Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); _daemonClient = client; _minerManagerFactory = minerManagerFactory; @@ -118,8 +119,8 @@ public Pool( _serverFactory = serverFactory; _serviceFactory = serviceFactory; _hashAlgorithmFactory = hashAlgorithmFactory; - _storageManagerFactory = storageManagerFactory; - _globalConfigFactory = globalConfigFactory; + _storageFactory = storageFactory; + _paymentProcessorFactory = paymentProcessorFactory; GenerateInstanceId(); } @@ -133,9 +134,6 @@ public void Initialize(IPoolConfig config) { Config = config; - // init the algorithm - _hashAlgorithm = _hashAlgorithmFactory.Get(Config.Coin.Algorithm); - // init coin daemon. InitDaemon(); @@ -156,13 +154,19 @@ private void InitDaemon() private void InitManagers() { - _storageManager = _storageManagerFactory.Get(Storages.Redis); + // init the algorithm + _hashAlgorithm = _hashAlgorithmFactory.Get(Config.Coin.Algorithm); + + _storage = _storageFactory.Get(Storages.Redis); + + _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage); + _paymentProcessor.Initialize(Config.Payments); _minerManager = _minerManagerFactory.Get(_daemonClient); _jobTracker = _jobTrackerFactory.Get(); - _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storageManager); + _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage); _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); @@ -215,13 +219,13 @@ private void GetPoolInfo() var info = _daemonClient.GetInfo(); var miningInfo = _daemonClient.GetMiningInfo(); - Log.ForContext().Information("Pool started for {0:l}\n" + - "Coin symbol: {1:l} algorithm: {2:l}\n" + - "Coin version: {3} protocol: {4} wallet: {5}\n" + - "Daemon network: {6:l} peers: {7} blocks: {8} errors: {9:l}\n" + - "Network difficulty: {10:0.0000} block difficulty: {11:0.00}\n" + - "Network hashrate: {12:l}\n" + - "{13:l}\n", + Log.ForContext().Information("Pool started for {0:l}\r\n" + + "Coin symbol: {1:l} algorithm: {2:l}\r\n" + + "Coin version: {3} protocol: {4} wallet: {5}\r\n" + + "Daemon network: {6:l} peers: {7} blocks: {8} errors: {9:l}\r\n" + + "Network difficulty: {10:0.0000} block difficulty: {11:0.00}\r\n" + + "Network hashrate: {12:l}\r\n" + + "{13:l}\r\n", Config.Coin.Name, Config.Coin.Symbol, Config.Coin.Algorithm, diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs new file mode 100644 index 000000000..83463d625 --- /dev/null +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -0,0 +1,36 @@ +#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 Coinium.Utils.Configuration; + +namespace Coinium.Payments +{ + public interface IPaymentConfig:IConfig + { + bool Enabled { get; } + + Int32 Interval { get; } + + Int32 Minimum { get; } + } +} diff --git a/src/CoiniumServ/Payments/IPaymentProcessor.cs b/src/CoiniumServ/Payments/IPaymentProcessor.cs new file mode 100644 index 000000000..98f5a1d52 --- /dev/null +++ b/src/CoiniumServ/Payments/IPaymentProcessor.cs @@ -0,0 +1,32 @@ +#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 Coinium.Payments +{ + public interface IPaymentProcessor + { + void Initialize(IPaymentConfig config); + + bool IsEnabled { get; } + } +} diff --git a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs new file mode 100644 index 000000000..ac13cf181 --- /dev/null +++ b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs @@ -0,0 +1,33 @@ +#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 Coinium.Daemon; +using Coinium.Persistance; + +namespace Coinium.Payments +{ + public interface IPaymentProcessorFactory + { + IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage); + } +} diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs new file mode 100644 index 000000000..98f09de15 --- /dev/null +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -0,0 +1,52 @@ +#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.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Coinium.Payments +{ + public class PaymentConfig:IPaymentConfig + { + public bool Valid { get; private set; } + public bool Enabled { get; private set; } + public int Interval { get; private set; } + public int Minimum { get; private set; } + + public PaymentConfig(dynamic config) + { + if (config == null) + { + Valid = false; + return; + } + + Enabled = config.enabled; + Interval = config.interval; + Minimum = config.minimum; + + Valid = true; + } + } +} diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs new file mode 100644 index 000000000..dac076cef --- /dev/null +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -0,0 +1,68 @@ +#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.Threading; +using Coinium.Daemon; +using Coinium.Persistance; +using Serilog; + +namespace Coinium.Payments +{ + public class PaymentProcessor : IPaymentProcessor + { + public bool IsEnabled { get; private set; } + + private readonly IDaemonClient _daemonClient; + private readonly IStorage _storage; + private IPaymentConfig _config; + private Timer _timer; + private TimeSpan _timeSpan; + + public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) + { + _daemonClient = daemonClient; + _storage = storage; + } + + public void Initialize(IPaymentConfig config) + { + _config = config; + + IsEnabled = _config.Enabled; + + if (IsEnabled) + { + _timeSpan = new TimeSpan(0, 0, 0, config.Interval); + _timer = new Timer(RunPayments, null, TimeSpan.Zero, _timeSpan); // setup the timer to run payments. + } + } + + private void RunPayments(object state) + { + _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. + + Log.ForContext().Information("Payment processor ran."); + } + } +} diff --git a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs new file mode 100644 index 000000000..b745a8d81 --- /dev/null +++ b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs @@ -0,0 +1,58 @@ +#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 Coinium.Daemon; +using Coinium.Persistance; +using Coinium.Repository.Context; +using Nancy.TinyIoc; + +namespace Coinium.Payments +{ + public class PaymentProcessorFactory : IPaymentProcessorFactory + { + /// + /// The _kernel + /// + private readonly IApplicationContext _applicationContext; + + /// + /// Initializes a new instance of the class. + /// + /// The application context. + public PaymentProcessorFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"daemonClient", daemonClient}, + {"storage", storage} + }; + + return _applicationContext.Container.Resolve(@params); + } + } +} diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs index 6d05055b6..5f5bb4174 100644 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ b/src/CoiniumServ/Persistance/StorageFactory.cs @@ -21,8 +21,6 @@ // #endregion using Coinium.Repository.Context; -using Nancy.TinyIoc; -using Serilog; namespace Coinium.Persistance { diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 7f2ddc7cd..6f234e866 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -25,6 +25,7 @@ using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Pools; using Coinium.Mining.Pools.Config; +using Coinium.Payments; using Coinium.Persistance; using Coinium.Persistance.Redis; using Coinium.Repository.Context; @@ -48,6 +49,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register(Storages.Redis).AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index e76ed64a5..a65f7df99 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -29,6 +29,7 @@ using Coinium.Mining.Pools; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; +using Coinium.Payments; using Coinium.Persistance; using Coinium.Repository.Context; using Coinium.Server; @@ -60,6 +61,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs index 7fd4d701c..07ad6d34f 100644 --- a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs @@ -51,7 +51,7 @@ public dynamic Get() public RedisConfig GetRedisConfig() { // return the redis config, if we haven't read it yet, do so. - return _redisConfig ?? (_redisConfig = new RedisConfig(Get().database.redis)); + return _redisConfig ?? (_redisConfig = new RedisConfig(Get().storage.redis)); } } } diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 3a3172dbc..243085a93 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -28,6 +28,7 @@ using Coinium.Mining.Miners; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; +using Coinium.Payments; using Coinium.Persistance; using Coinium.Server; using Coinium.Service; @@ -48,8 +49,8 @@ public class PoolTests private readonly IShareManagerFactory _shareManagerFactory; private readonly IHashAlgorithmFactory _hashAlgorithmFactory; private readonly IMinerManagerFactory _minerManagerFactory; - private readonly IStorageFactory _storageManagerFactory; - private readonly IGlobalConfigFactory _globalConfigFactory; + private readonly IStorageFactory _storageFactory; + private readonly IPaymentProcessorFactory _paymentProcessorFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -60,6 +61,7 @@ public class PoolTests private readonly IStorage _storage; private readonly IMiningServer _miningServer; private readonly IRpcService _rpcService; + private readonly IPaymentProcessor _paymentProcessor; /// /// Initialize mock objects. @@ -73,8 +75,8 @@ public PoolTests() _minerManagerFactory = Substitute.For(); _serverFactory = Substitute.For(); _serviceFactory = Substitute.For(); - _storageManagerFactory = Substitute.For(); - _globalConfigFactory = Substitute.For(); + _storageFactory = Substitute.For(); + _paymentProcessorFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -84,6 +86,7 @@ public PoolTests() _miningServer = Substitute.For(); _rpcService = Substitute.For(); _storage = Substitute.For(); + _paymentProcessor = Substitute.For(); } /// @@ -101,8 +104,9 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -125,8 +129,9 @@ public void ConstructorTest_NullHashAlgorithmFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IHashAlgorithmFactory"); @@ -149,8 +154,9 @@ public void ConstructorTest_NullServerFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IServerFactory"); @@ -173,8 +179,9 @@ public void ConstructorTest_NullServiceFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IServiceFactory"); @@ -197,8 +204,9 @@ public void ConstructorTest_NullDaemonClient_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IDaemonClient"); @@ -221,8 +229,9 @@ public void ConstructorTest_NullMinerManagerFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IMinerManagerFactory"); @@ -245,8 +254,9 @@ public void ConstructorTest_NullJobTrackerFactory_ShouldThrow() null, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IJobTrackerFactory"); @@ -269,8 +279,9 @@ public void ConstructorTest_NullJobManagerFactory_ShouldThrow() _jobTrackerFactory, null, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IJobManagerFactory"); @@ -293,8 +304,9 @@ public void ConstructorTest_NullShareManagerFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, null, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IShareManagerFactory"); @@ -318,17 +330,18 @@ public void ConstructorTest_NullStorageFactory_ShouldThrow() _jobManagerFactory, _shareManagerFactory, null, - _globalConfigFactory); + _paymentProcessorFactory + ); }); ex.Message.Should().Contain("IStorageFactory"); } /// - /// Tests pool constructor with null GlobalConfigFactory, should trow exception. + /// Tests pool constructor with null StorageFactory, should trow exception. /// [Fact] - public void ConstructorTest_NullStorageManagerFactory_ShouldThrow() + public void ConstructorTest_NullPaymentProcessorFactory_ShouldThrow() { Exception ex = Assert.Throws(() => { @@ -341,11 +354,12 @@ public void ConstructorTest_NullStorageManagerFactory_ShouldThrow() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - null); + _storageFactory, + null + ); }); - ex.Message.Should().Contain("IGlobalConfigFactory"); + ex.Message.Should().Contain("IPaymentProcessorFactory"); } /// @@ -363,8 +377,9 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _jobTrackerFactory, _jobManagerFactory, _shareManagerFactory, - _storageManagerFactory, - _globalConfigFactory); + _storageFactory, + _paymentProcessorFactory + ); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -380,8 +395,11 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // initialize the miner manager. _minerManagerFactory.Get(_daemonClient); + // payment processor + _paymentProcessorFactory.Get(_daemonClient, _storage); + // initialize storage manager - _storageManagerFactory.Get(Storages.Redis); + _storageFactory.Get(Storages.Redis); // initialize the job tracker _jobTrackerFactory.Get(); From b9bd83e08e237446e0c7bd005b261c1b1dfb06ad Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 3 Jul 2014 15:47:37 +0300 Subject: [PATCH 015/230] IPool will no long export pool-config. Redis and Storage will now handled pool config. --- README.md | 3 +- src/CoiniumServ/Mining/Pools/IPool.cs | 2 -- src/CoiniumServ/Mining/Pools/Pool.cs | 31 ++++++++-------- src/CoiniumServ/Payments/PaymentProcessor.cs | 7 ++++ src/CoiniumServ/Persistance/IStorage.cs | 2 ++ .../Persistance/IStorageFactory.cs | 5 ++- src/CoiniumServ/Persistance/Redis/IRedis.cs | 2 -- src/CoiniumServ/Persistance/Redis/Redis.cs | 36 ++++++++++++------- src/CoiniumServ/Persistance/StorageFactory.cs | 12 +++++-- .../Repository/Registries/ClassRegistry.cs | 2 +- src/CoiniumServ/Server/ServerFactory.cs | 1 + src/Tests/Mining/Pools/PoolTests.cs | 14 ++++---- 12 files changed, 73 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index f9d1704cd..536816ac2 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,8 @@ You can send tips and furher support the project or get tips for contributing by ### License -Copyright (C) 2013 - 2014, Coinium & CoiniumServ Project - http://www.coinium.org +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 diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index 1406bf901..e76504e34 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -26,8 +26,6 @@ namespace Coinium.Mining.Pools { public interface IPool { - IPoolConfig Config { get; } - /// /// Initializes the specified bind ip. /// diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 8c22c6d1e..6ade41dc5 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -47,8 +47,6 @@ namespace Coinium.Mining.Pools /// public class Pool : IPool { - public IPoolConfig Config { get; private set; } - private readonly IDaemonClient _daemonClient; private readonly IServerFactory _serverFactory; private readonly IServiceFactory _serviceFactory; @@ -67,6 +65,7 @@ public class Pool : IPool private IStorage _storage; private IHashAlgorithm _hashAlgorithm; private IPaymentProcessor _paymentProcessor; + private IPoolConfig _config; private Dictionary _servers; @@ -132,7 +131,7 @@ public Pool( /// config;config.Daemon can not be null! public void Initialize(IPoolConfig config) { - Config = config; + _config = config; // init coin daemon. InitDaemon(); @@ -146,21 +145,21 @@ public void Initialize(IPoolConfig config) private void InitDaemon() { - if (Config.Daemon == null || Config.Daemon.Valid == false) + if (_config.Daemon == null || _config.Daemon.Valid == false) Log.ForContext().Error("Coin daemon configuration is not valid!"); - _daemonClient.Initialize(Config.Daemon); + _daemonClient.Initialize(_config.Daemon); } private void InitManagers() { // init the algorithm - _hashAlgorithm = _hashAlgorithmFactory.Get(Config.Coin.Algorithm); + _hashAlgorithm = _hashAlgorithmFactory.Get(_config.Coin.Algorithm); - _storage = _storageFactory.Get(Storages.Redis); + _storage = _storageFactory.Get(Storages.Redis, _config); _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage); - _paymentProcessor.Initialize(Config.Payments); + _paymentProcessor.Initialize(_config.Payments); _minerManager = _minerManagerFactory.Get(_daemonClient); @@ -178,21 +177,21 @@ private void InitServers() // we don't need here a server config list as a pool can host only one instance of stratum and one vanilla server. // we must be dictative here, using a server list may cause situations we don't want (multiple stratum configs etc..) - if (Config.Stratum != null) + if (_config.Stratum != null) { var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager); var stratumService = _serviceFactory.Get("Stratum", _shareManager, _daemonClient); - stratumServer.Initialize(Config.Stratum); + stratumServer.Initialize(_config.Stratum); _servers.Add(stratumServer, stratumService); } - if (Config.Vanilla != null) + if (_config.Vanilla != null) { var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager); var vanillaService = _serviceFactory.Get("Vanilla", _shareManager, _daemonClient); - vanillaServer.Initialize(Config.Vanilla); + vanillaServer.Initialize(_config.Vanilla); _servers.Add(vanillaServer, vanillaService); } @@ -200,7 +199,7 @@ private void InitServers() public void Start() { - if (!Config.Valid) + if (!_config.Valid) { Log.ForContext().Error("Can't start pool as configuration is not valid."); return; @@ -226,9 +225,9 @@ private void GetPoolInfo() "Network difficulty: {10:0.0000} block difficulty: {11:0.00}\r\n" + "Network hashrate: {12:l}\r\n" + "{13:l}\r\n", - Config.Coin.Name, - Config.Coin.Symbol, - Config.Coin.Algorithm, + _config.Coin.Name, + _config.Coin.Symbol, + _config.Coin.Algorithm, info.Version, info.ProtocolVersion, info.WalletVersion, diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index dac076cef..d01fabc02 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -62,7 +62,14 @@ private void RunPayments(object state) { _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. + GetPendingPayments(); + Log.ForContext().Information("Payment processor ran."); } + + private void GetPendingPayments() + { + var test = _storage.GetPendingBlocks(); + } } } diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 7850a69f3..078a6c97f 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -31,5 +31,7 @@ public interface IStorage void CommitShare(IShare share); void CommitBlock(IShare share); + + string[] GetPendingBlocks(); } } diff --git a/src/CoiniumServ/Persistance/IStorageFactory.cs b/src/CoiniumServ/Persistance/IStorageFactory.cs index 0ac204528..baa084f54 100644 --- a/src/CoiniumServ/Persistance/IStorageFactory.cs +++ b/src/CoiniumServ/Persistance/IStorageFactory.cs @@ -20,6 +20,9 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using Coinium.Mining.Pools.Config; + namespace Coinium.Persistance { public interface IStorageFactory @@ -28,6 +31,6 @@ public interface IStorageFactory /// Gets the specified daemon client. /// /// - IStorage Get(string storageName); + IStorage Get(string storageName, IPoolConfig poolConfig); } } diff --git a/src/CoiniumServ/Persistance/Redis/IRedis.cs b/src/CoiniumServ/Persistance/Redis/IRedis.cs index 21b673872..11a73039a 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedis.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedis.cs @@ -27,7 +27,5 @@ namespace Coinium.Persistance.Redis public interface IRedis { bool IsConnected { get; } - - IRedisConfig Config { get; } } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 206987722..9ea129bb1 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -21,11 +21,10 @@ // #endregion using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; -using System.Threading.Tasks; +using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Utils.Configuration; using Coinium.Utils.Extensions; @@ -39,20 +38,23 @@ public class Redis:IStorage, IRedis { public bool IsEnabled { get; private set; } public bool IsConnected { get { return _connectionMultiplexer.IsConnected; } } - public IRedisConfig Config { get; private set; } private readonly Version _requiredMinimumVersion = new Version(2, 6); private readonly IGlobalConfigFactory _globalConfigFactory; + private readonly IRedisConfig _config; + private readonly IPoolConfig _poolConfig; + private ConnectionMultiplexer _connectionMultiplexer; private IDatabase _database; private IServer _server; - public Redis(IGlobalConfigFactory globalConfigFactory) + public Redis(IGlobalConfigFactory globalConfigFactory, IPoolConfig poolConfig) { _globalConfigFactory = globalConfigFactory; - Config = _globalConfigFactory.GetRedisConfig(); // read the config. - IsEnabled = Config.IsEnabled; + _poolConfig = poolConfig; + _config = _globalConfigFactory.GetRedisConfig(); // read the config. + IsEnabled = _config.IsEnabled; if (IsEnabled) Initialize(); @@ -63,7 +65,7 @@ public void CommitShare(IShare share) if (!IsEnabled || !IsConnected) return; - var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); // the coin we are working on. + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var batch = _database.CreateBatch(); // batch the commands. // add the share to round @@ -94,7 +96,7 @@ public void CommitShare(IShare share) public void CommitBlock(IShare share) { - var coin = share.Miner.Pool.Config.Coin.Name.ToLower(); // the coin we are working on. + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var batch = _database.CreateBatch(); // batch the commands. if (share.IsBlockAccepted) @@ -122,14 +124,24 @@ public void CommitBlock(IShare share) batch.Execute(); // execute the batch commands. } + public string[] GetPendingBlocks() + { + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + + //var test1=_database.SortedSetRangeByRank() + //var test2=_database.SortedSetRangeByRankWithScores() + + return null; + } + private void Initialize() { var options = new ConfigurationOptions(); - var endpoint = new DnsEndPoint(Config.Host, Config.Port, AddressFamily.InterNetwork); + var endpoint = new DnsEndPoint(_config.Host, _config.Port, AddressFamily.InterNetwork); options.EndPoints.Add(endpoint); options.AllowAdmin = true; - if (!string.IsNullOrEmpty(Config.Password)) - options.Password = Config.Password; + if (!string.IsNullOrEmpty(_config.Password)) + options.Password = _config.Password; try { @@ -137,7 +149,7 @@ private void Initialize() _connectionMultiplexer = ConnectionMultiplexer.ConnectAsync(options).Result; // access to database. - _database = _connectionMultiplexer.GetDatabase(Config.DatabaseId); + _database = _connectionMultiplexer.GetDatabase(_config.DatabaseId); // get the configured server. _server = _connectionMultiplexer.GetServer(endpoint); diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs index 5f5bb4174..8abcde0a4 100644 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ b/src/CoiniumServ/Persistance/StorageFactory.cs @@ -20,7 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using Coinium.Mining.Pools.Config; using Coinium.Repository.Context; +using Nancy.TinyIoc; namespace Coinium.Persistance { @@ -41,13 +44,18 @@ public StorageFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; } - public IStorage Get(string storageName) + public IStorage Get(string storageName, IPoolConfig poolConfig) { // Default to redis if (string.IsNullOrWhiteSpace(storageName)) storageName = Storages.Redis; - return _applicationContext.Container.Resolve(storageName); + var @params = new NamedParameterOverloads + { + {"poolConfig", poolConfig} + }; + + return _applicationContext.Container.Resolve(storageName, @params); } } } diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 6f234e866..e7f3570e0 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -47,7 +47,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register(Storages.Redis).AsSingleton(); + _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); } diff --git a/src/CoiniumServ/Server/ServerFactory.cs b/src/CoiniumServ/Server/ServerFactory.cs index 49d6ac2fd..b7179f2af 100644 --- a/src/CoiniumServ/Server/ServerFactory.cs +++ b/src/CoiniumServ/Server/ServerFactory.cs @@ -53,6 +53,7 @@ public IMiningServer Get(string serverName, IPool pool, IMinerManager minerManag {"minerManager", minerManager}, {"jobManager", jobManager} }; + return _applicationContext.Container.Resolve(serverName, @params); } } diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 243085a93..27216cf8f 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -385,12 +385,12 @@ public void InitializationTest_NonNullParams_ShouldSuccess() pool.InstanceId.Should().Be.GreaterThan((UInt32)0); // pool-config mockup. - var config = Substitute.For(); - config.Daemon.Valid.Returns(true); + var poolConfig = Substitute.For(); + poolConfig.Daemon.Valid.Returns(true); // initialize hash algorithm var hashAlgorithm = Substitute.For(); - _hashAlgorithmFactory.Get(config.Coin.Algorithm).Returns(hashAlgorithm); + _hashAlgorithmFactory.Get(poolConfig.Coin.Algorithm).Returns(hashAlgorithm); // initialize the miner manager. _minerManagerFactory.Get(_daemonClient); @@ -399,7 +399,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _paymentProcessorFactory.Get(_daemonClient, _storage); // initialize storage manager - _storageFactory.Get(Storages.Redis); + _storageFactory.Get(Storages.Redis, poolConfig); // initialize the job tracker _jobTrackerFactory.Get(); @@ -412,7 +412,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _jobManager.Initialize(pool.InstanceId); // init daemon client - _daemonClient.Initialize(config.Daemon); + _daemonClient.Initialize(poolConfig.Daemon); // init server _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager).Returns(_miningServer); @@ -421,10 +421,10 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _serviceFactory.Get(Services.Stratum, _shareManager, _daemonClient).Returns(_rpcService); // initalize the server. - _miningServer.Initialize(config.Stratum); + _miningServer.Initialize(poolConfig.Stratum); // initialize the pool. - pool.Initialize(config); + pool.Initialize(poolConfig); } } } From 8ba702fe7fe147e419b4ca3c6b70564fc78fcd54 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 3 Jul 2014 15:48:23 +0300 Subject: [PATCH 016/230] Small fix within Redis.cs --- src/CoiniumServ/Persistance/Redis/Redis.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 9ea129bb1..ce1d94bb8 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -40,8 +40,7 @@ public class Redis:IStorage, IRedis public bool IsConnected { get { return _connectionMultiplexer.IsConnected; } } private readonly Version _requiredMinimumVersion = new Version(2, 6); - private readonly IGlobalConfigFactory _globalConfigFactory; - private readonly IRedisConfig _config; + private readonly IRedisConfig _redisConfig; private readonly IPoolConfig _poolConfig; private ConnectionMultiplexer _connectionMultiplexer; @@ -50,11 +49,9 @@ public class Redis:IStorage, IRedis public Redis(IGlobalConfigFactory globalConfigFactory, IPoolConfig poolConfig) { - _globalConfigFactory = globalConfigFactory; - - _poolConfig = poolConfig; - _config = _globalConfigFactory.GetRedisConfig(); // read the config. - IsEnabled = _config.IsEnabled; + _poolConfig = poolConfig; // the pool config. + _redisConfig = globalConfigFactory.GetRedisConfig(); // read the redis config. + IsEnabled = _redisConfig.IsEnabled; if (IsEnabled) Initialize(); @@ -137,11 +134,11 @@ public string[] GetPendingBlocks() private void Initialize() { var options = new ConfigurationOptions(); - var endpoint = new DnsEndPoint(_config.Host, _config.Port, AddressFamily.InterNetwork); + var endpoint = new DnsEndPoint(_redisConfig.Host, _redisConfig.Port, AddressFamily.InterNetwork); options.EndPoints.Add(endpoint); options.AllowAdmin = true; - if (!string.IsNullOrEmpty(_config.Password)) - options.Password = _config.Password; + if (!string.IsNullOrEmpty(_redisConfig.Password)) + options.Password = _redisConfig.Password; try { @@ -149,7 +146,7 @@ private void Initialize() _connectionMultiplexer = ConnectionMultiplexer.ConnectAsync(options).Result; // access to database. - _database = _connectionMultiplexer.GetDatabase(_config.DatabaseId); + _database = _connectionMultiplexer.GetDatabase(_redisConfig.DatabaseId); // get the configured server. _server = _connectionMultiplexer.GetServer(endpoint); From daa5120a6eb1fb049e22a6a1b3681cd38ea410eb Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 3 Jul 2014 17:02:38 +0300 Subject: [PATCH 017/230] Implemented Redis:GetPendingBlocks(). Created PersistedBlock structure. Started implementing PaymentProcessor:QueryPendingBlocks(). Fixed timers for JobManager and PaymentProcessor. Improved Daemon/Reponses/Transaction.cs. Further more improved DaemonException handling - it also contains the actual error code and message from the daemon now. --- src/CoiniumServ/CoiniumServ.csproj | 4 +- src/CoiniumServ/Daemon/DaemonBase.cs | 2 +- ...{DaemonError.cs => DaemonErrorResponse.cs} | 11 ++--- .../Daemon/Exceptions/DaemonException.cs | 8 +++- src/CoiniumServ/Daemon/IDaemonClient.cs | 2 + .../Daemon/Responses/Transaction.cs | 23 ++++++++-- .../Daemon/Responses/TransactionDetail.cs | 1 + .../Mining/Jobs/Manager/JobManager.cs | 11 +++-- src/CoiniumServ/Payments/PaymentProcessor.cs | 36 +++++++++++---- .../Persistance/IPersistedBlock.cs | 45 +++++++++++++++++++ src/CoiniumServ/Persistance/IStorage.cs | 5 ++- src/CoiniumServ/Persistance/PersistedBlock.cs | 41 +++++++++++++++++ src/CoiniumServ/Persistance/Redis/Redis.cs | 20 +++++++-- 13 files changed, 173 insertions(+), 36 deletions(-) rename src/CoiniumServ/Daemon/{DaemonError.cs => DaemonErrorResponse.cs} (93%) create mode 100644 src/CoiniumServ/Persistance/IPersistedBlock.cs create mode 100644 src/CoiniumServ/Persistance/PersistedBlock.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index c92e06cd2..c9ea45fb4 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -109,7 +109,7 @@ - + @@ -123,6 +123,8 @@ + + diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 9bfbd16fd..ce98b6af1 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -184,7 +184,7 @@ private string GetJsonResponse(HttpWebRequest httpWebRequest) { string error = reader.ReadToEnd(); - var daemonError = JsonConvert.DeserializeObject(error); + var daemonError = JsonConvert.DeserializeObject(error); throw new DaemonException(daemonError); } } diff --git a/src/CoiniumServ/Daemon/DaemonError.cs b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs similarity index 93% rename from src/CoiniumServ/Daemon/DaemonError.cs rename to src/CoiniumServ/Daemon/DaemonErrorResponse.cs index 2424949a9..0e1076c90 100644 --- a/src/CoiniumServ/Daemon/DaemonError.cs +++ b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs @@ -24,7 +24,7 @@ namespace Coinium.Daemon { - public class DaemonError + public class DaemonErrorResponse { /// /// The result object. @@ -36,21 +36,16 @@ public class DaemonError /// The error returned by the wallet, if any. /// [JsonProperty(PropertyName = "error", Order = 1)] - public ErrorObject Error { get; set; } + public DaemonError Error { get; set; } /// /// The id of the corresponding request. /// [JsonProperty(PropertyName = "id", Order = 2)] public int Id { get; set; } - - public DaemonError() - { - - } } - public class ErrorObject + public class DaemonError { [JsonProperty(PropertyName = "code", Order = 1)] public int Code { get; set; } diff --git a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs b/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs index bbd20db78..3fe3cec23 100644 --- a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs +++ b/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs @@ -26,12 +26,16 @@ namespace Coinium.Daemon.Exceptions { public class DaemonException : Exception { + public DaemonError Error { get; private set; } + public DaemonException(Exception e): base(e.Message) { } - public DaemonException(DaemonError response): + public DaemonException(DaemonErrorResponse response) : base(response.Error.Message) - { } + { + Error = response.Error; + } } } diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index a3c8a0290..b597d274a 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -45,6 +45,8 @@ public interface IDaemonClient ValidateAddress ValidateAddress(string walletAddress); + Transaction GetTransaction(string txId); + void Initialize(IDaemonConfig daemonConfig); } } diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index c77b4c159..e7eebd59c 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; using System.Collections.Generic; namespace Coinium.Daemon.Responses @@ -27,13 +29,28 @@ namespace Coinium.Daemon.Responses public class Transaction { public double Amount { get; set; } - public double Fee { get; set; } public int Confirmations { get; set; } + + public bool Generated { get; set; } + + public string BlockHash { get; set; } + + public int BlockIndex { get; set; } + + public int BlockTime { get; set; } + public string TxId { get; set; } + + public string NormTxId { get; set; } + public int Time { get; set; } public int TimeReceived { get; set; } - public string Comment { get; set; } - public string To { get; set; } + public List Details { get; set; } + + // not sure if fields below even exists / used + public double Fee { get; set; } + public string Comment { get; set; } + public string To { get; set; } } } diff --git a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs index f3f660c6f..4cf96e590 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs @@ -30,6 +30,7 @@ public class TransactionDetail public string Address { get; set; } public string Category { get; set; } public double Amount { get; set; } + // not sure if fields below even exists / used public double Fee { get; set; } } } diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 0214fb48f..539789eef 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -57,9 +57,7 @@ public class JobManager : IJobManager /// private Timer _timer; - private const int TimerExpiration = 60; - - private readonly TimeSpan _timeSpan = new TimeSpan(0, 0, 0, TimerExpiration); + private const int TimerExpiration = 10; public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm) { @@ -77,8 +75,8 @@ public void Initialize(UInt32 instanceId) _shareManager.BlockFound += OnBlockFound; _minerManager.MinerAuthenticated += OnMinerAuthenticated; - var job = GetNewJob(); // initially create a job. - _timer = new Timer(IdleJobTimer, null, TimeSpan.Zero, _timeSpan); // setup a timer to broadcast jobs. + _timer = new Timer(IdleJobTimer, null,Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + BroadcastNewJob(true); // broadcast a new job initially - which will also setup the timer. } private void OnBlockFound(object sender, EventArgs e) @@ -95,12 +93,13 @@ private void BroadcastNewJob(bool initiatedByTimer) { var job = GetNewJob(); // create a new job. var count = Broadcast(job); // broadcast to miners. - _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. if (initiatedByTimer) Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.",job.Id, count, TimerExpiration); else Log.ForContext().Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id,count); + + _timer.Change(TimerExpiration * 1000, Timeout.Infinite); // reset the idle-block timer. } private void OnMinerAuthenticated(object sender, EventArgs e) diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index d01fabc02..2045db8fe 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -22,8 +22,10 @@ #endregion using System; +using System.Collections.Generic; using System.Threading; using Coinium.Daemon; +using Coinium.Daemon.Exceptions; using Coinium.Persistance; using Serilog; @@ -37,7 +39,6 @@ public class PaymentProcessor : IPaymentProcessor private readonly IStorage _storage; private IPaymentConfig _config; private Timer _timer; - private TimeSpan _timeSpan; public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) { @@ -53,23 +54,40 @@ public void Initialize(IPaymentConfig config) if (IsEnabled) { - _timeSpan = new TimeSpan(0, 0, 0, config.Interval); - _timer = new Timer(RunPayments, null, TimeSpan.Zero, _timeSpan); // setup the timer to run payments. + _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); // setup the timer to run payments. } } private void RunPayments(object state) - { - _timer.Change(_timeSpan, TimeSpan.Zero); // reset the idle-block timer. - - GetPendingPayments(); + { + var pendingBlocks = _storage.GetPendingBlocks(); + QueryPendingBlocks(pendingBlocks); Log.ForContext().Information("Payment processor ran."); + + _timer.Change(_config.Interval * 1000, Timeout.Infinite); // reset the payments timer. } - private void GetPendingPayments() + private void QueryPendingBlocks(IEnumerable blocks) { - var test = _storage.GetPendingBlocks(); + + foreach (var block in blocks) + { + try + { + var test = _daemonClient.GetTransaction(block.TransactionHash + "a"); + } + catch (DaemonException exception) + { + if (exception.Error.Code == -5) + Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.", block.Height, block.TransactionHash); + else + Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].", block.Height, block.TransactionHash, exception.Error.Message, exception.Error.Code); + + block.Status=PersistedBlockStatus.Kicked; // kic the block. + } + } + } } } diff --git a/src/CoiniumServ/Persistance/IPersistedBlock.cs b/src/CoiniumServ/Persistance/IPersistedBlock.cs new file mode 100644 index 000000000..8ddadd191 --- /dev/null +++ b/src/CoiniumServ/Persistance/IPersistedBlock.cs @@ -0,0 +1,45 @@ +#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; + +namespace Coinium.Persistance +{ + public interface IPersistedBlock + { + UInt32 Height { get; } + + string BlockHash { get; } + string TransactionHash { get; } + + PersistedBlockStatus Status { get; set; } + } + + public enum PersistedBlockStatus + { + Pending, + Kicked, + Orphan, + Confirmed + } +} diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 078a6c97f..5023f40bd 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System.Collections.Generic; using Coinium.Mining.Shares; namespace Coinium.Persistance @@ -31,7 +33,6 @@ public interface IStorage void CommitShare(IShare share); void CommitBlock(IShare share); - - string[] GetPendingBlocks(); + IList GetPendingBlocks(); } } diff --git a/src/CoiniumServ/Persistance/PersistedBlock.cs b/src/CoiniumServ/Persistance/PersistedBlock.cs new file mode 100644 index 000000000..5e77baede --- /dev/null +++ b/src/CoiniumServ/Persistance/PersistedBlock.cs @@ -0,0 +1,41 @@ +#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 Coinium.Persistance +{ + public class PersistedBlock : IPersistedBlock + { + public uint Height { get; private set; } + public string BlockHash { get; private set; } + public string TransactionHash { get; private set; } + public PersistedBlockStatus Status { get; set; } + + public PersistedBlock( PersistedBlockStatus status, uint height, string blockHash, string transactionHash) + { + Status = status; + Height = height; + BlockHash = blockHash; + TransactionHash = transactionHash; + } + } +} diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index ce1d94bb8..604a30035 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; @@ -121,14 +122,25 @@ public void CommitBlock(IShare share) batch.Execute(); // execute the batch commands. } - public string[] GetPendingBlocks() + public IList GetPendingBlocks() { var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + var key=string.Format("{0}:blocks:pending", coin); - //var test1=_database.SortedSetRangeByRank() - //var test2=_database.SortedSetRangeByRankWithScores() + var task = _database.SortedSetRangeByRankWithScoresAsync(key, 0, -1, Order.Ascending, CommandFlags.HighPriority); + var results = task.Result; - return null; + var list = new List(); + foreach (var result in results) + { + var data = result.Element.ToString().Split(':'); + var blockHash = data[0]; + var transactionHash = data[1]; + var persistedBlock = new PersistedBlock(PersistedBlockStatus.Pending, (UInt32)result.Score, blockHash, transactionHash); + list.Add(persistedBlock); + } + + return list; } private void Initialize() From 9fb56a59377c4855f2499693f99fcefb0617c57d Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 3 Jul 2014 18:38:15 +0300 Subject: [PATCH 018/230] More PaymentProcessor.cs work. --- src/CoiniumServ/Daemon/DaemonClient.cs | 7 +- src/CoiniumServ/Daemon/IDaemonClient.cs | 2 + .../Daemon/Responses/Transaction.cs | 6 +- .../Daemon/Responses/TransactionDetail.cs | 2 +- src/CoiniumServ/Mining/Pools/PoolManager.cs | 18 ++-- src/CoiniumServ/Payments/PaymentProcessor.cs | 89 ++++++++++++++++--- 6 files changed, 102 insertions(+), 22 deletions(-) diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 9ec3f89f0..2143df8bb 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -46,6 +46,8 @@ namespace Coinium.Daemon /// public class DaemonClient : DaemonBase, IDaemonClient { + private static readonly object[] EmptyParams = {}; // used as empty parameter. + /// /// Version 0.8: Attempts add or remove node from the addnode list or try a connection to node once. /// @@ -185,7 +187,10 @@ public List GetAddressesByAccount(string account) /// The balance of the account or the total wallet. public decimal GetBalance(string account = "") { - return MakeRequest("getbalance", account); + if (string.IsNullOrEmpty(account)) + return MakeRequest("getbalance", EmptyParams); + else + return MakeRequest("getbalance", account); } /// diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index b597d274a..549f8f9e7 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -47,6 +47,8 @@ public interface IDaemonClient Transaction GetTransaction(string txId); + decimal GetBalance(string account = ""); + void Initialize(IDaemonConfig daemonConfig); } } diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index e7eebd59c..bc9832a5f 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -49,8 +49,8 @@ public class Transaction public List Details { get; set; } // not sure if fields below even exists / used - public double Fee { get; set; } - public string Comment { get; set; } - public string To { get; set; } + //public double Fee { get; set; } + //public string Comment { get; set; } + //public string To { get; set; } } } diff --git a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs index 4cf96e590..f155654e9 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs @@ -31,6 +31,6 @@ public class TransactionDetail public string Category { get; set; } public double Amount { get; set; } // not sure if fields below even exists / used - public double Fee { get; set; } + //public double Fee { get; set; } } } diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 3f86acdbb..9290367c4 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -50,9 +50,11 @@ public void Run() public void LoadConfigs() { const string configRoot = "config/pools"; - - var enabledPools = new List(); + var files = FileHelpers.GetFilesByExtensionRecursive(configRoot, ".json"); + + var pools = new List(); + var names = new List(); foreach (var file in files) { @@ -61,12 +63,16 @@ public void LoadConfigs() if (!poolConfig.Enabled) // skip pools that are not enabled. continue; - enabledPools.Add(poolConfig.Coin.Name); - - AddPool(poolConfig); + pools.Add(poolConfig); + names.Add(poolConfig.Coin.Name); } - Log.ForContext().Information("Discovered a total of {0} enabled pool configurations: {1}.", _pools.Count, enabledPools); + Log.ForContext().Information("Discovered a total of {0} enabled pool configurations: {1}.", pools.Count, names); + + foreach (var config in pools) + { + AddPool(config); + } } public IPool AddPool(IPoolConfig poolConfig) diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 2045db8fe..a733464f1 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -23,9 +23,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Threading; +using Coinium.Coin.Address.Exceptions; using Coinium.Daemon; using Coinium.Daemon.Exceptions; +using Coinium.Daemon.Responses; +using Coinium.Mining.Pools; using Coinium.Persistance; using Serilog; @@ -40,6 +45,11 @@ public class PaymentProcessor : IPaymentProcessor private IPaymentConfig _config; private Timer _timer; + private readonly object _paymentsLock = new object(); + private readonly Stopwatch _stopWatch = new Stopwatch(); + + private const string PoolWallet = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; + public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) { _daemonClient = daemonClient; @@ -52,30 +62,88 @@ public void Initialize(IPaymentConfig config) IsEnabled = _config.Enabled; - if (IsEnabled) + if (!IsEnabled) + return; + + // validate the pool wallet. + var validationResult = _daemonClient.ValidateAddress(PoolWallet); + + if (!validationResult.IsValid || !validationResult.IsMine) // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. { - _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); // setup the timer to run payments. + Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.",PoolWallet); + return; } + + // determine the satoshis in the coin. + var balanceResult = _daemonClient.GetBalance(); + + + // setup the timer to run payments. + _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); } private void RunPayments(object state) { - var pendingBlocks = _storage.GetPendingBlocks(); - QueryPendingBlocks(pendingBlocks); + lock (_paymentsLock) + { + _stopWatch.Start(); - Log.ForContext().Information("Payment processor ran."); + var pendingBlocks = _storage.GetPendingBlocks(); + QueryPendingBlocks(pendingBlocks); - _timer.Change(_config.Interval * 1000, Timeout.Infinite); // reset the payments timer. + Log.ForContext().Information("Payments processed - took {0:0.00} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); + _stopWatch.Reset(); + + _timer.Change(_config.Interval*1000, Timeout.Infinite); // reset the payments timer. + } } private void QueryPendingBlocks(IEnumerable blocks) { - foreach (var block in blocks) { try { - var test = _daemonClient.GetTransaction(block.TransactionHash + "a"); + var transaction = _daemonClient.GetTransaction(block.TransactionHash); + + // get the output transaction that targets pools central wallet. + var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolWallet); + + // make sure output for the pool central wallet exists + if (poolOutput == null) + { + Log.ForContext().Error("Kicking block {0} as transaction doesn't contain output for the pool's central wallet.", block.Height); + block.Status = PersistedBlockStatus.Kicked; // kick the block. + } + else + { + // possible categories: + // src/rpcwallet.cpp:961: entry.push_back(Pair("category", "send")); + // src/rpcwallet.cpp:986: entry.push_back(Pair("category", "orphan")); + // src/rpcwallet.cpp:988: entry.push_back(Pair("category", "immature")); + // src/rpcwallet.cpp:990: entry.push_back(Pair("category", "generate")); + // src/rpcwallet.cpp:993: entry.push_back(Pair("category", "receive")); + // src/rpcwallet.cpp:1011: entry.push_back(Pair("category", "move")); + + switch (poolOutput.Category) + { + case "immature": + block.Status = PersistedBlockStatus.Pending; + break; + case "orphan": + block.Status = PersistedBlockStatus.Orphan; + break; + case "generate": + block.Status = PersistedBlockStatus.Confirmed; + break; + default: // send, recieve, move - TODO: we shouldn't be seing these categories! Implement an error message and kick it may be? + block.Status = PersistedBlockStatus.Pending; + break; + } + + // get the amount. + var amount = poolOutput.Amount; + } } catch (DaemonException exception) { @@ -83,11 +151,10 @@ private void QueryPendingBlocks(IEnumerable blocks) Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.", block.Height, block.TransactionHash); else Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].", block.Height, block.TransactionHash, exception.Error.Message, exception.Error.Code); - - block.Status=PersistedBlockStatus.Kicked; // kic the block. + + block.Status = PersistedBlockStatus.Kicked; // kick the block. } } - } } } From 20f6490a6ac5e2c23e4f4897b501d16dc2956ab6 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 4 Jul 2014 18:18:31 +0300 Subject: [PATCH 019/230] Implemented Redis:GetSharesForRounds() Implemented IPaymentRounds - share & reward calculation for rounds. Implemented coin precision determination. --- src/CoiniumServ/CoiniumServ.csproj | 2 + src/CoiniumServ/Daemon/DaemonBase.cs | 36 ++++-- src/CoiniumServ/Daemon/DaemonClient.cs | 3 +- src/CoiniumServ/Daemon/IDaemonClient.cs | 2 + src/CoiniumServ/Payments/IPaymentRound.cs | 42 +++++++ src/CoiniumServ/Payments/PaymentProcessor.cs | 126 ++++++++++++++----- src/CoiniumServ/Payments/PaymentRound.cs | 65 ++++++++++ src/CoiniumServ/Persistance/IStorage.cs | 4 + src/CoiniumServ/Persistance/Redis/Redis.cs | 23 +++- 9 files changed, 256 insertions(+), 47 deletions(-) create mode 100644 src/CoiniumServ/Payments/IPaymentRound.cs create mode 100644 src/CoiniumServ/Payments/PaymentRound.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index c9ea45fb4..8210e1706 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -117,9 +117,11 @@ + + diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index ce98b6af1..148d49513 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -64,17 +64,6 @@ public T MakeRequest(string method, params object[] parameters) return rpcResponse.Result; } - /// - /// Make a raw JSON RPC request with the given request object. Returns raw JSON. - /// - /// The request object. - /// The raw JSON string. - public string MakeRawRpcRequest(DaemonRequest walletRequest) - { - HttpWebRequest httpWebRequest = MakeHttpRequest(walletRequest); - return GetJsonResponse(httpWebRequest); - } - /// /// Make an JSON RPC request, and return a JSON RPC response object with the result /// deserialized as the given type. @@ -84,10 +73,33 @@ public string MakeRawRpcRequest(DaemonRequest walletRequest) /// A JSON RPC response with the result deserialized as the given type. private DaemonResponse MakeRpcRequest(DaemonRequest walletRequest) { - HttpWebRequest httpWebRequest = MakeHttpRequest(walletRequest); + var httpWebRequest = MakeHttpRequest(walletRequest); return GetRpcResponse(httpWebRequest); } + /// + /// Make a raw JSON RPC request with the given request object. Returns raw JSON. + /// + /// + /// + /// + public string MakeRawRequest(string method, params object[] parameters) + { + var response = MakeRawRpcRequest(new DaemonRequest(RequestCounter++, method, parameters)); + return response; + } + + /// + /// Make a raw JSON RPC request with the given request object. Returns raw JSON. + /// + /// The request object. + /// The raw JSON string. + private string MakeRawRpcRequest(DaemonRequest walletRequest) + { + var httpWebRequest = MakeHttpRequest(walletRequest); + return GetJsonResponse(httpWebRequest); + } + /// /// Make the actual HTTP request to the Bitcoin RPC interface. /// diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 2143df8bb..4671c16e9 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -23,7 +23,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Coinium.Daemon.Config; using Coinium.Daemon.Requests; using Coinium.Daemon.Responses; @@ -46,7 +45,7 @@ namespace Coinium.Daemon /// public class DaemonClient : DaemonBase, IDaemonClient { - private static readonly object[] EmptyParams = {}; // used as empty parameter. + public static readonly object[] EmptyParams = {}; // used as empty parameter. /// /// Version 0.8: Attempts add or remove node from the addnode list or try a connection to node once. diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 549f8f9e7..080203b1b 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -49,6 +49,8 @@ public interface IDaemonClient decimal GetBalance(string account = ""); + string MakeRawRequest(string method, params object[] parameters); + void Initialize(IDaemonConfig daemonConfig); } } diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs new file mode 100644 index 000000000..31478d28c --- /dev/null +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -0,0 +1,42 @@ +#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.Collections.Generic; +using Coinium.Persistance; + +namespace Coinium.Payments +{ + public interface IPaymentRound + { + IPersistedBlock Block {get;} + + decimal TotalRewardInSatoshis { get; } + + Dictionary Shares { get; } + + Dictionary Payouts { get; } + + void AddShares(IDictionary shares); + } +} diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index a733464f1..1602dad2f 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -26,11 +26,8 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using Coinium.Coin.Address.Exceptions; using Coinium.Daemon; using Coinium.Daemon.Exceptions; -using Coinium.Daemon.Responses; -using Coinium.Mining.Pools; using Coinium.Persistance; using Serilog; @@ -45,6 +42,9 @@ public class PaymentProcessor : IPaymentProcessor private IPaymentConfig _config; private Timer _timer; + private Int32 _precision; // coin's precision. + private UInt32 _magnitude; // coin's magnitude + private readonly object _paymentsLock = new object(); private readonly Stopwatch _stopWatch = new Stopwatch(); @@ -66,19 +66,14 @@ public void Initialize(IPaymentConfig config) return; // validate the pool wallet. - var validationResult = _daemonClient.ValidateAddress(PoolWallet); - - if (!validationResult.IsValid || !validationResult.IsMine) // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. - { - Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.",PoolWallet); + if (!ValidatePoolAddress()) return; - } // determine the satoshis in the coin. - var balanceResult = _daemonClient.GetBalance(); - + if (!DeterminePrecision()) + return; - // setup the timer to run payments. + // if we reached here, then we can just setup the timer to run payments. _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); } @@ -88,43 +83,55 @@ private void RunPayments(object state) { _stopWatch.Start(); - var pendingBlocks = _storage.GetPendingBlocks(); - QueryPendingBlocks(pendingBlocks); + var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. + var rounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. + ProcessRounds(rounds); - Log.ForContext().Information("Payments processed - took {0:0.00} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); + Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); _stopWatch.Reset(); _timer.Change(_config.Interval*1000, Timeout.Infinite); // reset the payments timer. } } - private void QueryPendingBlocks(IEnumerable blocks) + private void ProcessRounds(IList rounds) + { + // get shares for the rounds. + var roundShares = _storage.GetSharesForRounds(rounds); + + // assign shares to the rounds. + foreach (var round in rounds) + { + if (roundShares.ContainsKey(round.Block.Height)) + { + round.AddShares(roundShares[round.Block.Height]); + break; + } + } + } + + private IList GetPaymentRounds(IEnumerable blocks) { + var rounds = new List(); + foreach (var block in blocks) { try { + // get the transaction. var transaction = _daemonClient.GetTransaction(block.TransactionHash); - + // get the output transaction that targets pools central wallet. var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolWallet); // make sure output for the pool central wallet exists if (poolOutput == null) { - Log.ForContext().Error("Kicking block {0} as transaction doesn't contain output for the pool's central wallet.", block.Height); + Log.ForContext().Error("Kicking block {0} as transaction doesn't contain output for the pool's central wallet.",block.Height); block.Status = PersistedBlockStatus.Kicked; // kick the block. } else { - // possible categories: - // src/rpcwallet.cpp:961: entry.push_back(Pair("category", "send")); - // src/rpcwallet.cpp:986: entry.push_back(Pair("category", "orphan")); - // src/rpcwallet.cpp:988: entry.push_back(Pair("category", "immature")); - // src/rpcwallet.cpp:990: entry.push_back(Pair("category", "generate")); - // src/rpcwallet.cpp:993: entry.push_back(Pair("category", "receive")); - // src/rpcwallet.cpp:1011: entry.push_back(Pair("category", "move")); - switch (poolOutput.Category) { case "immature": @@ -136,25 +143,80 @@ private void QueryPendingBlocks(IEnumerable blocks) case "generate": block.Status = PersistedBlockStatus.Confirmed; break; - default: // send, recieve, move - TODO: we shouldn't be seing these categories! Implement an error message and kick it may be? + default: + // send, recieve, move - TODO: we shouldn't be seing these categories! Implement an error message and kick it may be? block.Status = PersistedBlockStatus.Pending; break; } - // get the amount. - var amount = poolOutput.Amount; - } + + if (block.Status == PersistedBlockStatus.Confirmed) + { + // get the reward amount. + var rewardInSatoshis = (decimal)poolOutput.Amount * _magnitude; + rounds.Add(new PaymentRound(block, rewardInSatoshis)); + } + } } catch (DaemonException exception) { if (exception.Error.Code == -5) - Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.", block.Height, block.TransactionHash); + Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.",block.Height, block.TransactionHash); else - Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].", block.Height, block.TransactionHash, exception.Error.Message, exception.Error.Code); + Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].",block.Height, block.TransactionHash, exception.Error.Message, exception.Error.Code); block.Status = PersistedBlockStatus.Kicked; // kick the block. + + return rounds; } } + + return rounds; + } + + private bool ValidatePoolAddress() + { + var result = _daemonClient.ValidateAddress(PoolWallet); + + // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. + if (result.IsValid && result.IsMine) + return true; + + Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", PoolWallet); + return false; + } + + private bool DeterminePrecision() + { + var json = string.Empty; + + try + { + json = _daemonClient.MakeRawRequest("getbalance", DaemonClient.EmptyParams); + + // we want a raw request + var satoshis = json.Split(new[] { "result\":" }, StringSplitOptions.None)[1].Split(',')[0].Split('.')[1]; + + _precision = satoshis.Length; + _magnitude = 1; + + for (int i = 1; i <= _precision; i++) + { + _magnitude *= 10; + } + + return true; + } + catch (DaemonException e) + { + Log.ForContext().Error("Halted as getbalance call failed: {0}.", e.Error.Message); + return false; + } + catch (Exception e) + { + Log.ForContext().Error("Halted as we can not determine satoshis in a coin - failed parsing: {0}", json); + return false; + } } } } diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs new file mode 100644 index 000000000..32f646191 --- /dev/null +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -0,0 +1,65 @@ +#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; +using Coinium.Persistance; + +namespace Coinium.Payments +{ + public class PaymentRound:IPaymentRound + { + public IPersistedBlock Block { get; private set; } + public decimal TotalRewardInSatoshis { get; private set; } + public Dictionary Shares { get; private set; } + public Dictionary Payouts { get; private set; } + + + public PaymentRound(IPersistedBlock block, decimal totalRewardInSatoshis) + { + Block = block; + TotalRewardInSatoshis = totalRewardInSatoshis; + Payouts = new Dictionary(); + } + + public void AddShares(IDictionary shares) + { + Shares = shares.ToDictionary(pair => pair.Key, pair => pair.Value); + CalculatePayouts(); + } + + private void CalculatePayouts() + { + var totalShares = Shares.Sum(pair => pair.Value); // total shares. + + // calculate per worker amounts. + foreach (var pair in Shares) + { + var percent = pair.Value/totalShares; + var rewardInSatoshis = (decimal) percent*TotalRewardInSatoshis; + + Payouts.Add(pair.Key, rewardInSatoshis); + } + } + } +} diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 5023f40bd..cc30615c7 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -21,8 +21,10 @@ // #endregion +using System; using System.Collections.Generic; using Coinium.Mining.Shares; +using Coinium.Payments; namespace Coinium.Persistance { @@ -34,5 +36,7 @@ public interface IStorage void CommitBlock(IShare share); IList GetPendingBlocks(); + + Dictionary> GetSharesForRounds(IList rounds); } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 604a30035..cc4765c7a 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -25,8 +25,10 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using Coinium.Crypto; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; +using Coinium.Payments; using Coinium.Utils.Configuration; using Coinium.Utils.Extensions; using Coinium.Utils.Helpers.Time; @@ -125,12 +127,13 @@ public void CommitBlock(IShare share) public IList GetPendingBlocks() { var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - var key=string.Format("{0}:blocks:pending", coin); + var key = string.Format("{0}:blocks:pending", coin); var task = _database.SortedSetRangeByRankWithScoresAsync(key, 0, -1, Order.Ascending, CommandFlags.HighPriority); var results = task.Result; var list = new List(); + foreach (var result in results) { var data = result.Element.ToString().Split(':'); @@ -143,6 +146,24 @@ public IList GetPendingBlocks() return list; } + public Dictionary> GetSharesForRounds(IList rounds) + { + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + + var sharesForRounds = new Dictionary>(); // dictionary of block-height <-> shares. + + foreach (var round in rounds) + { + var key = string.Format("{0}:shares:round:{1}", coin, round.Block.Height); + var hashes = _database.HashGetAllAsync(key, CommandFlags.HighPriority).Result; + + var shares = hashes.ToDictionary(pair => pair.Name, pair => (double)pair.Value); + sharesForRounds.Add(round.Block.Height, shares); + } + + return sharesForRounds; + } + private void Initialize() { var options = new ConfigurationOptions(); From 90e7d76c5c7abbc7543c200de62d61307fe8b3a7 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 5 Jul 2014 13:25:42 +0300 Subject: [PATCH 020/230] Implemented PaymentProcessor:CalculatePayments() and PaymentProcessor:ExecutePayments(). --- src/CoiniumServ/CoiniumServ.csproj | 2 + src/CoiniumServ/Payments/IWorkerPayout.cs | 36 ++++++++++++++++ src/CoiniumServ/Payments/PaymentProcessor.cs | 41 +++++++++++++++++- src/CoiniumServ/Payments/WorkerPayout.cs | 44 ++++++++++++++++++++ src/CoiniumServGui/CoiniumServGui.csproj | 12 ------ src/CoiniumServGui/app.config | 5 +-- src/CoiniumServGui/packages.config | 1 - 7 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 src/CoiniumServ/Payments/IWorkerPayout.cs create mode 100644 src/CoiniumServ/Payments/WorkerPayout.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 8210e1706..05f3cbdba 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -121,10 +121,12 @@ + + diff --git a/src/CoiniumServ/Payments/IWorkerPayout.cs b/src/CoiniumServ/Payments/IWorkerPayout.cs new file mode 100644 index 000000000..4d28d07f1 --- /dev/null +++ b/src/CoiniumServ/Payments/IWorkerPayout.cs @@ -0,0 +1,36 @@ +#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 Coinium.Payments +{ + public interface IWorkerPayout + { + string Worker { get; } + + decimal Balance { get; } + + bool Paid { get; set; } + + void AddPayment(decimal amount); + } +} diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 1602dad2f..9e14fe772 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -44,6 +44,7 @@ public class PaymentProcessor : IPaymentProcessor private Int32 _precision; // coin's precision. private UInt32 _magnitude; // coin's magnitude + private decimal _minPaymentInSatoshis; // minimum amount of satoshis to issue a payment. private readonly object _paymentsLock = new object(); private readonly Stopwatch _stopWatch = new Stopwatch(); @@ -73,27 +74,65 @@ public void Initialize(IPaymentConfig config) if (!DeterminePrecision()) return; + // calculate the minimum amount of payments in satoshis. + _minPaymentInSatoshis = _magnitude*config.Minimum; + // if we reached here, then we can just setup the timer to run payments. _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); } private void RunPayments(object state) { + if (!IsEnabled) + return; + lock (_paymentsLock) { _stopWatch.Start(); var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. var rounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. - ProcessRounds(rounds); + ProcessRounds(rounds); // process the rounds, calculate shares and payouts per rounds. + var payments = CalculatePayments(rounds); // calculate the payments. + ExecutePayments(payments); // execute the payments. Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); + _stopWatch.Reset(); _timer.Change(_config.Interval*1000, Timeout.Infinite); // reset the payments timer. } } + private IDictionary CalculatePayments(IEnumerable rounds) + { + var payments = new Dictionary(); + + foreach (var round in rounds) // loop through all rounds + { + foreach (var roundPayment in round.Payouts) // loop through all payouts for the rounds + { + if (!payments.ContainsKey(roundPayment.Key)) // make sure a payout for worker already exists + payments.Add(roundPayment.Key, new WorkerPayout(roundPayment.Key)); + + payments[roundPayment.Key].AddPayment(roundPayment.Value); + } + } + + return payments.ToDictionary(k => k.Key, v => v.Value); + } + + private void ExecutePayments(IEnumerable> payments) + { + foreach (var pair in payments) + { + var worker = pair.Value; + + if (worker.Balance < _minPaymentInSatoshis) + worker.Paid = false; + } + } + private void ProcessRounds(IList rounds) { // get shares for the rounds. diff --git a/src/CoiniumServ/Payments/WorkerPayout.cs b/src/CoiniumServ/Payments/WorkerPayout.cs new file mode 100644 index 000000000..ad888a725 --- /dev/null +++ b/src/CoiniumServ/Payments/WorkerPayout.cs @@ -0,0 +1,44 @@ +#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 Coinium.Payments +{ + public class WorkerPayout:IWorkerPayout + { + public string Worker { get; private set; } + public decimal Balance { get; private set; } + public bool Paid { get; set; } + + public WorkerPayout(string worker) + { + Worker = worker; + Balance = 0; + Paid = false; + } + + public void AddPayment(decimal amount) + { + Balance += amount; + } + } +} diff --git a/src/CoiniumServGui/CoiniumServGui.csproj b/src/CoiniumServGui/CoiniumServGui.csproj index 83ccbf406..e703ff256 100644 --- a/src/CoiniumServGui/CoiniumServGui.csproj +++ b/src/CoiniumServGui/CoiniumServGui.csproj @@ -55,18 +55,6 @@ - - ..\..\build\packages\XDMessaging.4.0.9\lib\net40-Client\XDMessaging.dll - - - ..\..\build\packages\XDMessaging.4.0.9\lib\net40-Client\XDMessaging.Transport.Amazon.dll - - - ..\..\build\packages\XDMessaging.4.0.9\lib\net40-Client\XDMessaging.Transport.IOStream.dll - - - ..\..\build\packages\XDMessaging.4.0.9\lib\net40-Client\XDMessaging.Transport.WindowsMessaging.dll - diff --git a/src/CoiniumServGui/app.config b/src/CoiniumServGui/app.config index 2fb01017b..c5c407bdb 100644 --- a/src/CoiniumServGui/app.config +++ b/src/CoiniumServGui/app.config @@ -1,7 +1,4 @@  - - - - + \ No newline at end of file diff --git a/src/CoiniumServGui/packages.config b/src/CoiniumServGui/packages.config index 46642571a..10a00719b 100644 --- a/src/CoiniumServGui/packages.config +++ b/src/CoiniumServGui/packages.config @@ -1,5 +1,4 @@  - \ No newline at end of file From 5b208202fd881aec460cfa95eb9c6e92d4ee1ff0 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 5 Jul 2014 13:38:43 +0300 Subject: [PATCH 021/230] Testing dot.net 4.5 --- src/CoiniumServ/App.config | 12 +++--- src/CoiniumServ/CoiniumServ.csproj | 17 ++++---- src/CoiniumServ/Payments/PaymentProcessor.cs | 2 +- src/CoiniumServ/packages.config | 10 +++-- src/CoiniumServGui/CoiniumServGui.csproj | 6 ++- .../Properties/Resources.Designer.cs | 42 ++++++++----------- .../Properties/Settings.Designer.cs | 22 ++++------ src/CoiniumServGui/app.config | 4 +- src/Tests/App.config | 14 +++---- src/Tests/Tests.csproj | 13 ++---- src/Tests/packages.config | 8 ++-- 11 files changed, 67 insertions(+), 83 deletions(-) diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index d085a4b71..cbdad42db 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -1,17 +1,17 @@ - + - + - - + + - - + + diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 05f3cbdba..a0ddfce52 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -9,7 +9,7 @@ Properties Coinium CoiniumServ - v4.0 + v4.5 512 @@ -60,6 +60,9 @@ ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll + + ..\..\build\packages\Microsoft.Experimental.Collections.1.0.1-alpha\lib\portable-net45+win8+wp8\Microsoft.Experimental.Collections.dll + ..\..\build\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll @@ -94,18 +97,12 @@ ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll + + ..\..\build\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll - diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 9e14fe772..c82cd2806 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -104,7 +104,7 @@ private void RunPayments(object state) } } - private IDictionary CalculatePayments(IEnumerable rounds) + private IEnumerable> CalculatePayments(IEnumerable rounds) { var payments = new Dictionary(); diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index f5cf596f9..0502cd5d7 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,12 +4,14 @@ - + + + - - - + + + \ No newline at end of file diff --git a/src/CoiniumServGui/CoiniumServGui.csproj b/src/CoiniumServGui/CoiniumServGui.csproj index e703ff256..6673e78e1 100644 --- a/src/CoiniumServGui/CoiniumServGui.csproj +++ b/src/CoiniumServGui/CoiniumServGui.csproj @@ -9,10 +9,11 @@ Properties CoiniumServGui CoiniumServGui - v4.0 + v4.5 512 ..\..\build\ true + AnyCPU @@ -23,6 +24,7 @@ DEBUG;TRACE prompt 4 + false AnyCPU @@ -32,6 +34,7 @@ TRACE prompt 4 + false Coinium.ico @@ -76,6 +79,7 @@ True Resources.resx + True diff --git a/src/CoiniumServGui/Properties/Resources.Designer.cs b/src/CoiniumServGui/Properties/Resources.Designer.cs index 85e927b7e..e4fdd4ce8 100644 --- a/src/CoiniumServGui/Properties/Resources.Designer.cs +++ b/src/CoiniumServGui/Properties/Resources.Designer.cs @@ -8,10 +8,10 @@ // //------------------------------------------------------------------------------ -namespace CoiniumServGui.Properties -{ - - +namespace CoiniumServGui.Properties { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -22,48 +22,40 @@ namespace CoiniumServGui.Properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CoiniumServGui.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } diff --git a/src/CoiniumServGui/Properties/Settings.Designer.cs b/src/CoiniumServGui/Properties/Settings.Designer.cs index 6d79175fe..620124e0c 100644 --- a/src/CoiniumServGui/Properties/Settings.Designer.cs +++ b/src/CoiniumServGui/Properties/Settings.Designer.cs @@ -8,21 +8,17 @@ // //------------------------------------------------------------------------------ -namespace CoiniumServGui.Properties -{ - - +namespace CoiniumServGui.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } diff --git a/src/CoiniumServGui/app.config b/src/CoiniumServGui/app.config index c5c407bdb..e5eb4927e 100644 --- a/src/CoiniumServGui/app.config +++ b/src/CoiniumServGui/app.config @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/src/Tests/App.config b/src/Tests/App.config index 188c1a87b..0e26d0c5a 100644 --- a/src/Tests/App.config +++ b/src/Tests/App.config @@ -1,18 +1,18 @@ - + - + - + - - + + - - + + diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index cf562c95d..3b7cf170b 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -9,7 +9,7 @@ Properties Tests CoiniumServ.Tests - v4.0 + v4.5 512 ..\..\build\ true @@ -23,6 +23,7 @@ DEBUG;TRACE prompt 4 + false pdbonly @@ -31,6 +32,7 @@ TRACE prompt 4 + false @@ -66,16 +68,7 @@ - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll - - - ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll - ..\..\build\packages\xunit.1.9.2\lib\net20\xunit.dll diff --git a/src/Tests/packages.config b/src/Tests/packages.config index 8b33ce25e..6cdea1dfd 100644 --- a/src/Tests/packages.config +++ b/src/Tests/packages.config @@ -1,13 +1,13 @@  - + - - + + - + \ No newline at end of file From 9b65cbeb6dd89498b3722c5e74f6bd2b059b5532 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 5 Jul 2014 13:50:20 +0300 Subject: [PATCH 022/230] Updated release mode output path. --- deps/jsonconfig | 2 +- src/CoiniumServ/CoiniumServ.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/jsonconfig b/deps/jsonconfig index ec1a5567a..7e2133611 160000 --- a/deps/jsonconfig +++ b/deps/jsonconfig @@ -1 +1 @@ -Subproject commit ec1a5567a669663cf0df07a897188ac9e1f57972 +Subproject commit 7e21336116cb2404cd49fa2d9cab8a53d76b80a8 diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index a0ddfce52..3e8b7161a 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -33,7 +33,7 @@ AnyCPU pdbonly true - bin\Release\ + ..\..\bin\Release\ TRACE prompt 4 From 85138601a94a6f05d35018d0180565f0a5d6dee3 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 5 Jul 2014 14:29:03 +0300 Subject: [PATCH 023/230] Downgraded back to .net 4.0. --- src/CoiniumServ/App.config | 14 +++++++------- src/CoiniumServ/CoiniumServ.csproj | 19 +++++++++++-------- src/CoiniumServ/Persistance/Redis/Redis.cs | 1 - src/CoiniumServ/packages.config | 10 ++++------ src/CoiniumServGui/CoiniumServGui.csproj | 6 +----- src/CoiniumServGui/app.config | 2 +- src/Tests/App.config | 16 ++++++++-------- src/Tests/Tests.csproj | 13 ++++++++++--- src/Tests/packages.config | 8 ++++---- 9 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index cbdad42db..4a8baaf9f 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -1,18 +1,18 @@ - + - + - - + + - - + + - + \ No newline at end of file diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 3e8b7161a..05f3cbdba 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -9,7 +9,7 @@ Properties Coinium CoiniumServ - v4.5 + v4.0 512 @@ -33,7 +33,7 @@ AnyCPU pdbonly true - ..\..\bin\Release\ + bin\Release\ TRACE prompt 4 @@ -60,9 +60,6 @@ ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll - - ..\..\build\packages\Microsoft.Experimental.Collections.1.0.1-alpha\lib\portable-net45+win8+wp8\Microsoft.Experimental.Collections.dll - ..\..\build\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll @@ -97,12 +94,18 @@ ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll - - ..\..\build\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll + diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index cc4765c7a..49c858aa1 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -25,7 +25,6 @@ using System.Linq; using System.Net; using System.Net.Sockets; -using Coinium.Crypto; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Payments; diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 0502cd5d7..f5cf596f9 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,14 +4,12 @@ - + - - - - - + + + \ No newline at end of file diff --git a/src/CoiniumServGui/CoiniumServGui.csproj b/src/CoiniumServGui/CoiniumServGui.csproj index 6673e78e1..e703ff256 100644 --- a/src/CoiniumServGui/CoiniumServGui.csproj +++ b/src/CoiniumServGui/CoiniumServGui.csproj @@ -9,11 +9,10 @@ Properties CoiniumServGui CoiniumServGui - v4.5 + v4.0 512 ..\..\build\ true - AnyCPU @@ -24,7 +23,6 @@ DEBUG;TRACE prompt 4 - false AnyCPU @@ -34,7 +32,6 @@ TRACE prompt 4 - false Coinium.ico @@ -79,7 +76,6 @@ True Resources.resx - True diff --git a/src/CoiniumServGui/app.config b/src/CoiniumServGui/app.config index e5eb4927e..f42ae73a8 100644 --- a/src/CoiniumServGui/app.config +++ b/src/CoiniumServGui/app.config @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/src/Tests/App.config b/src/Tests/App.config index 0e26d0c5a..828389723 100644 --- a/src/Tests/App.config +++ b/src/Tests/App.config @@ -1,19 +1,19 @@ - + - + - + - - + + - - + + - + \ No newline at end of file diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 3b7cf170b..cf562c95d 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -9,7 +9,7 @@ Properties Tests CoiniumServ.Tests - v4.5 + v4.0 512 ..\..\build\ true @@ -23,7 +23,6 @@ DEBUG;TRACE prompt 4 - false pdbonly @@ -32,7 +31,6 @@ TRACE prompt 4 - false @@ -68,7 +66,16 @@ + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll + + + ..\..\build\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll + ..\..\build\packages\xunit.1.9.2\lib\net20\xunit.dll diff --git a/src/Tests/packages.config b/src/Tests/packages.config index 6cdea1dfd..8b33ce25e 100644 --- a/src/Tests/packages.config +++ b/src/Tests/packages.config @@ -1,13 +1,13 @@  - + - - + + - + \ No newline at end of file From 0519d559089f7ca7a3bc18127ff8aa4e06461436 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 5 Jul 2014 16:33:50 +0300 Subject: [PATCH 024/230] More ExecutePayments() work. Added enabled/connected checks to redis methods. --- src/CoiniumServ/CoiniumServ.csproj | 1 + src/CoiniumServ/Daemon/DaemonBase.cs | 2 +- src/CoiniumServ/Daemon/DaemonClient.cs | 9 ++-- src/CoiniumServ/Daemon/IDaemonBase.cs | 43 ++++++++++++++++++++ src/CoiniumServ/Daemon/IDaemonClient.cs | 6 ++- src/CoiniumServ/Payments/IWorkerPayout.cs | 2 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 23 +++++++---- src/CoiniumServ/Payments/WorkerPayout.cs | 6 +-- src/CoiniumServ/Persistance/Redis/Redis.cs | 25 +++++++++--- 9 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 src/CoiniumServ/Daemon/IDaemonBase.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 05f3cbdba..c23720734 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -111,6 +111,7 @@ + diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 148d49513..ba5098762 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -32,7 +32,7 @@ namespace Coinium.Daemon { - public class DaemonBase + public class DaemonBase : IDaemonBase { public string RpcUrl { get; private set; } public string RpcUser { get; private set; } diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 4671c16e9..901950344 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -45,7 +45,7 @@ namespace Coinium.Daemon /// public class DaemonClient : DaemonBase, IDaemonClient { - public static readonly object[] EmptyParams = {}; // used as empty parameter. + public static readonly object[] EmptyString = {}; // used as empty parameter. /// /// Version 0.8: Attempts add or remove node from the addnode list or try a connection to node once. @@ -186,10 +186,9 @@ public List GetAddressesByAccount(string account) /// The balance of the account or the total wallet. public decimal GetBalance(string account = "") { - if (string.IsNullOrEmpty(account)) - return MakeRequest("getbalance", EmptyParams); - else - return MakeRequest("getbalance", account); + return string.IsNullOrEmpty(account) + ? MakeRequest("getbalance", EmptyString) + : MakeRequest("getbalance", account); } /// diff --git a/src/CoiniumServ/Daemon/IDaemonBase.cs b/src/CoiniumServ/Daemon/IDaemonBase.cs new file mode 100644 index 000000000..7e36c66e0 --- /dev/null +++ b/src/CoiniumServ/Daemon/IDaemonBase.cs @@ -0,0 +1,43 @@ +#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 Coinium.Daemon.Config; + +namespace Coinium.Daemon +{ + public interface IDaemonBase + { + string RpcUrl { get; } + + string RpcUser { get;} + string RpcPassword { get;} + Int32 RequestCounter { get; } + + T MakeRequest(string method, params object[] parameters); + + string MakeRawRequest(string method, params object[] parameters); + + void Initialize(IDaemonConfig daemonConfig); + } +} diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 080203b1b..9cacc61db 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System.Collections.Generic; using Coinium.Daemon.Config; using Coinium.Daemon.Responses; @@ -51,6 +53,8 @@ public interface IDaemonClient string MakeRawRequest(string method, params object[] parameters); - void Initialize(IDaemonConfig daemonConfig); + string SendMany(string fromAccount, Dictionary toBitcoinAddress, int minConf = 1, string comment = ""); + + void Initialize(IDaemonConfig daemonConfig); } } diff --git a/src/CoiniumServ/Payments/IWorkerPayout.cs b/src/CoiniumServ/Payments/IWorkerPayout.cs index 4d28d07f1..4e6898162 100644 --- a/src/CoiniumServ/Payments/IWorkerPayout.cs +++ b/src/CoiniumServ/Payments/IWorkerPayout.cs @@ -27,7 +27,7 @@ public interface IWorkerPayout { string Worker { get; } - decimal Balance { get; } + decimal Amount { get; } bool Paid { get; set; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index c82cd2806..6e9268dce 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -26,6 +26,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using Coinium.Coin.Helpers; using Coinium.Daemon; using Coinium.Daemon.Exceptions; using Coinium.Persistance; @@ -124,13 +125,21 @@ private IEnumerable> CalculatePayments(IEnum private void ExecutePayments(IEnumerable> payments) { - foreach (var pair in payments) - { - var worker = pair.Value; + var a = _daemonClient.GetBalance(); + var b = _daemonClient.GetBalance(""); + var c = _daemonClient.GetBalance(string.Empty); - if (worker.Balance < _minPaymentInSatoshis) - worker.Paid = false; - } + var payouts = + payments.Select(pair => pair.Value) + .Where(workerPayment => workerPayment.Amount >= _minPaymentInSatoshis) + .ToDictionary(workerPayment => workerPayment.Worker, workerPayment => SatoshiToCoins(workerPayment.Amount)); + + var result = _daemonClient.SendMany("", payouts); // fix account. + } + + public decimal SatoshiToCoins(decimal satoshis) + { + return satoshis/_magnitude; } private void ProcessRounds(IList rounds) @@ -231,7 +240,7 @@ private bool DeterminePrecision() try { - json = _daemonClient.MakeRawRequest("getbalance", DaemonClient.EmptyParams); + json = _daemonClient.MakeRawRequest("getbalance", DaemonClient.EmptyString); // we want a raw request var satoshis = json.Split(new[] { "result\":" }, StringSplitOptions.None)[1].Split(',')[0].Split('.')[1]; diff --git a/src/CoiniumServ/Payments/WorkerPayout.cs b/src/CoiniumServ/Payments/WorkerPayout.cs index ad888a725..7ecc5b9de 100644 --- a/src/CoiniumServ/Payments/WorkerPayout.cs +++ b/src/CoiniumServ/Payments/WorkerPayout.cs @@ -26,19 +26,19 @@ namespace Coinium.Payments public class WorkerPayout:IWorkerPayout { public string Worker { get; private set; } - public decimal Balance { get; private set; } + public decimal Amount { get; private set; } public bool Paid { get; set; } public WorkerPayout(string worker) { Worker = worker; - Balance = 0; + Amount = 0; Paid = false; } public void AddPayment(decimal amount) { - Balance += amount; + Amount += amount; } } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 49c858aa1..c506346e4 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -95,6 +95,9 @@ public void CommitShare(IShare share) public void CommitBlock(IShare share) { + if (!IsEnabled || !IsConnected) + return; + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var batch = _database.CreateBatch(); // batch the commands. @@ -125,14 +128,17 @@ public void CommitBlock(IShare share) public IList GetPendingBlocks() { + var list = new List(); + + if (!IsEnabled || !IsConnected) + return list; + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var key = string.Format("{0}:blocks:pending", coin); var task = _database.SortedSetRangeByRankWithScoresAsync(key, 0, -1, Order.Ascending, CommandFlags.HighPriority); var results = task.Result; - var list = new List(); - foreach (var result in results) { var data = result.Element.ToString().Split(':'); @@ -147,10 +153,13 @@ public IList GetPendingBlocks() public Dictionary> GetSharesForRounds(IList rounds) { - var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - var sharesForRounds = new Dictionary>(); // dictionary of block-height <-> shares. + if (!IsEnabled || !IsConnected) + return sharesForRounds; + + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + foreach (var round in rounds) { var key = string.Format("{0}:shares:round:{1}", coin, round.Block.Height); @@ -165,10 +174,14 @@ public Dictionary> GetSharesForRounds(IList Date: Mon, 7 Jul 2014 13:34:30 +0300 Subject: [PATCH 025/230] Renamed WorkerPayout.cs to WorkerBalance.cs. Added GetPoolAccount() so it can be used during payments. --- src/CoiniumServ/CoiniumServ.csproj | 4 +- src/CoiniumServ/Daemon/IDaemonClient.cs | 4 + .../{IWorkerPayout.cs => IWorkerBalance.cs} | 4 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 78 +++++++++++++------ .../{WorkerPayout.cs => WorkerBalance.cs} | 12 +-- 5 files changed, 69 insertions(+), 33 deletions(-) rename src/CoiniumServ/Payments/{IWorkerPayout.cs => IWorkerBalance.cs} (93%) rename src/CoiniumServ/Payments/{WorkerPayout.cs => WorkerBalance.cs} (81%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index c23720734..a9c5ba040 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -122,12 +122,12 @@ - + - + diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 9cacc61db..e08f2889a 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -53,6 +53,10 @@ public interface IDaemonClient string MakeRawRequest(string method, params object[] parameters); + Dictionary ListAccounts(); + + string GetAccount(string bitcoinAddress); + string SendMany(string fromAccount, Dictionary toBitcoinAddress, int minConf = 1, string comment = ""); void Initialize(IDaemonConfig daemonConfig); diff --git a/src/CoiniumServ/Payments/IWorkerPayout.cs b/src/CoiniumServ/Payments/IWorkerBalance.cs similarity index 93% rename from src/CoiniumServ/Payments/IWorkerPayout.cs rename to src/CoiniumServ/Payments/IWorkerBalance.cs index 4e6898162..e40b3de4b 100644 --- a/src/CoiniumServ/Payments/IWorkerPayout.cs +++ b/src/CoiniumServ/Payments/IWorkerBalance.cs @@ -23,11 +23,11 @@ namespace Coinium.Payments { - public interface IWorkerPayout + public interface IWorkerBalance { string Worker { get; } - decimal Amount { get; } + decimal AmountInSatoshis { get; } bool Paid { get; set; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 6e9268dce..5411ea59b 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -29,6 +29,7 @@ using Coinium.Coin.Helpers; using Coinium.Daemon; using Coinium.Daemon.Exceptions; +using Coinium.Mining.Pools; using Coinium.Persistance; using Serilog; @@ -45,12 +46,13 @@ public class PaymentProcessor : IPaymentProcessor private Int32 _precision; // coin's precision. private UInt32 _magnitude; // coin's magnitude - private decimal _minPaymentInSatoshis; // minimum amount of satoshis to issue a payment. + private decimal _paymentThresholdInSatoshis; // minimum amount of satoshis to issue a payment. private readonly object _paymentsLock = new object(); private readonly Stopwatch _stopWatch = new Stopwatch(); - private const string PoolWallet = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; + private const string PoolAddress = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; + private string PoolAccount = string.Empty; public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) { @@ -71,12 +73,15 @@ public void Initialize(IPaymentConfig config) if (!ValidatePoolAddress()) return; + // get the pool's account name if any. + GetPoolAccount(); + // determine the satoshis in the coin. if (!DeterminePrecision()) return; // calculate the minimum amount of payments in satoshis. - _minPaymentInSatoshis = _magnitude*config.Minimum; + _paymentThresholdInSatoshis = _magnitude*config.Minimum; // if we reached here, then we can just setup the timer to run payments. _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); @@ -95,7 +100,7 @@ private void RunPayments(object state) var rounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. ProcessRounds(rounds); // process the rounds, calculate shares and payouts per rounds. var payments = CalculatePayments(rounds); // calculate the payments. - ExecutePayments(payments); // execute the payments. + var success = ExecutePayments(payments); // execute the payments. Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); @@ -105,39 +110,60 @@ private void RunPayments(object state) } } - private IEnumerable> CalculatePayments(IEnumerable rounds) + private IList CalculatePayments(IEnumerable rounds) { - var payments = new Dictionary(); + var workerBalances = new Dictionary(); foreach (var round in rounds) // loop through all rounds { foreach (var roundPayment in round.Payouts) // loop through all payouts for the rounds { - if (!payments.ContainsKey(roundPayment.Key)) // make sure a payout for worker already exists - payments.Add(roundPayment.Key, new WorkerPayout(roundPayment.Key)); + if (!workerBalances.ContainsKey(roundPayment.Key)) // make sure a payout for worker already exists + workerBalances.Add(roundPayment.Key, new WorkerBalance(roundPayment.Key)); - payments[roundPayment.Key].AddPayment(roundPayment.Value); + workerBalances[roundPayment.Key].AddPayment(roundPayment.Value); } } - return payments.ToDictionary(k => k.Key, v => v.Value); + return workerBalances.Values.ToList(); } - private void ExecutePayments(IEnumerable> payments) + private bool ExecutePayments(IList workerBalances) { - var a = _daemonClient.GetBalance(); - var b = _daemonClient.GetBalance(""); - var c = _daemonClient.GetBalance(string.Empty); + var payments = new Dictionary(); - var payouts = - payments.Select(pair => pair.Value) - .Where(workerPayment => workerPayment.Amount >= _minPaymentInSatoshis) - .ToDictionary(workerPayment => workerPayment.Worker, workerPayment => SatoshiToCoins(workerPayment.Amount)); + try + { + decimal totalAmountToPay = 0; + foreach (var balance in workerBalances) + { + if (balance.AmountInSatoshis >= _paymentThresholdInSatoshis) // if worker's balance exceed's threshold, add him to payment list. + { + totalAmountToPay += balance.AmountInSatoshis; + payments.Add(balance.Worker, SatoshisToCoins(balance.AmountInSatoshis)); + } + } + + var result = _daemonClient.SendMany(PoolAccount, payments); // send the payments + + foreach (var balance in workerBalances) + { + // we have paid workers with balance that exceeds the threshold. + balance.Paid = balance.AmountInSatoshis >= _paymentThresholdInSatoshis; + } - var result = _daemonClient.SendMany("", payouts); // fix account. + Log.ForContext().Information("Paid a total of {0} coins to {1} workers.", SatoshisToCoins(totalAmountToPay), workerBalances.Count); + + return true; + } + catch (DaemonException e) + { + Log.ForContext().Error("Payment failed: {0} [{1}] - payouts: {2}.", e.Error.Message, e.Error.Code, payments); + return false; + } } - public decimal SatoshiToCoins(decimal satoshis) + public decimal SatoshisToCoins(decimal satoshis) { return satoshis/_magnitude; } @@ -170,7 +196,7 @@ private IList GetPaymentRounds(IEnumerable block var transaction = _daemonClient.GetTransaction(block.TransactionHash); // get the output transaction that targets pools central wallet. - var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolWallet); + var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); // make sure output for the pool central wallet exists if (poolOutput == null) @@ -222,15 +248,21 @@ private IList GetPaymentRounds(IEnumerable block return rounds; } + private void GetPoolAccount() + { + var result = _daemonClient.GetAccount(PoolAddress); + PoolAccount = result; + } + private bool ValidatePoolAddress() { - var result = _daemonClient.ValidateAddress(PoolWallet); + var result = _daemonClient.ValidateAddress(PoolAddress); // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. if (result.IsValid && result.IsMine) return true; - Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", PoolWallet); + Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", PoolAddress); return false; } diff --git a/src/CoiniumServ/Payments/WorkerPayout.cs b/src/CoiniumServ/Payments/WorkerBalance.cs similarity index 81% rename from src/CoiniumServ/Payments/WorkerPayout.cs rename to src/CoiniumServ/Payments/WorkerBalance.cs index 7ecc5b9de..5e37e49ba 100644 --- a/src/CoiniumServ/Payments/WorkerPayout.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -23,22 +23,22 @@ namespace Coinium.Payments { - public class WorkerPayout:IWorkerPayout + public class WorkerBalance:IWorkerBalance { public string Worker { get; private set; } - public decimal Amount { get; private set; } - public bool Paid { get; set; } + public decimal AmountInSatoshis { get; private set; } + public bool Paid { get; set; } - public WorkerPayout(string worker) + public WorkerBalance(string worker) { Worker = worker; - Amount = 0; + AmountInSatoshis = 0; Paid = false; } public void AddPayment(decimal amount) { - Amount += amount; + AmountInSatoshis += amount; } } } From 2b1997814edcf513450e091018c4b5241b21e608 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 7 Jul 2014 18:34:19 +0300 Subject: [PATCH 026/230] Improved daemon connection's exception & error handling. Implemented CommitRemainingBalances(), DeleteShares(), MoveSharesToCurrentRound() and MovePendingBlock() for Redis. PaymentProcessor now pays the miners - though it still doesn't consider existing balances. Improved readibility of a few log messages. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- src/CoiniumServ/Daemon/DaemonBase.cs | 12 +- src/CoiniumServ/Daemon/DaemonErrorResponse.cs | 4 +- .../{DaemonException.cs => RpcException.cs} | 16 +-- .../Daemon/Responses/TransactionDetail.cs | 3 +- .../Mining/Jobs/Manager/JobManager.cs | 4 +- src/CoiniumServ/Mining/Shares/ShareManager.cs | 26 ++-- src/CoiniumServ/Payments/IPaymentRound.cs | 3 +- src/CoiniumServ/Payments/IWorkerBalance.cs | 3 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 112 +++++++++++------ src/CoiniumServ/Payments/PaymentRound.cs | 20 ++- src/CoiniumServ/Payments/WorkerBalance.cs | 22 +++- .../Persistance/IPersistedBlock.cs | 2 - src/CoiniumServ/Persistance/IStorage.cs | 9 ++ src/CoiniumServ/Persistance/PersistedBlock.cs | 5 + src/CoiniumServ/Persistance/Redis/Redis.cs | 118 ++++++++++++++---- src/CoiniumServ/Program.cs | 4 +- 17 files changed, 253 insertions(+), 112 deletions(-) rename src/CoiniumServ/Daemon/Exceptions/{DaemonException.cs => RpcException.cs} (76%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index a9c5ba040..4fb34e08e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,7 +110,7 @@ - + diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index ba5098762..c0fd05f99 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -130,7 +130,7 @@ private HttpWebRequest MakeHttpRequest(DaemonRequest walletRequest) } catch (WebException exception) { - throw new DaemonException(exception); + throw new RpcException("An unknown web exception occured while trying to send the JSON request.", exception); } return webRequest; @@ -181,14 +181,14 @@ private string GetJsonResponse(HttpWebRequest httpWebRequest) } catch (ProtocolViolationException protocolException) { - throw new Exception("Unable to connect to the daemon.", protocolException); + throw new RpcException("Unable to connect to the daemon.", protocolException); } catch (WebException webException) { var response = webException.Response as HttpWebResponse; if(response == null) - throw new Exception("An unknown web exception occured while trying to read the JSON response.", webException); + throw new RpcException(string.Format("Error while reading the json response: {0}.", webException.Message), webException); using (var stream = response.GetResponseStream()) { @@ -196,14 +196,14 @@ private string GetJsonResponse(HttpWebRequest httpWebRequest) { string error = reader.ReadToEnd(); - var daemonError = JsonConvert.DeserializeObject(error); - throw new DaemonException(daemonError); + var errorResponse = JsonConvert.DeserializeObject(error); + throw new RpcException(errorResponse); } } } catch (Exception exception) { - throw new Exception("An unknown exception occured while trying to read the JSON response.", exception); + throw new RpcException("An unknown exception occured while trying to read the JSON response.", exception); } } } diff --git a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs index 0e1076c90..f3bf4926c 100644 --- a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; using Newtonsoft.Json; namespace Coinium.Daemon @@ -48,7 +50,7 @@ public class DaemonErrorResponse public class DaemonError { [JsonProperty(PropertyName = "code", Order = 1)] - public int Code { get; set; } + public Int32 Code { get; set; } [JsonProperty(PropertyName = "message", Order = 1)] public string Message { get; set; } diff --git a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs similarity index 76% rename from src/CoiniumServ/Daemon/Exceptions/DaemonException.cs rename to src/CoiniumServ/Daemon/Exceptions/RpcException.cs index 3fe3cec23..66b53b17f 100644 --- a/src/CoiniumServ/Daemon/Exceptions/DaemonException.cs +++ b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs @@ -24,18 +24,20 @@ namespace Coinium.Daemon.Exceptions { - public class DaemonException : Exception + public class RpcException : Exception { - public DaemonError Error { get; private set; } + public Int32 Code { get; private set; } - public DaemonException(Exception e): - base(e.Message) - { } + public RpcException(string message, Exception innerException) : + base(message, innerException) + { + Code = Int32.MinValue; + } - public DaemonException(DaemonErrorResponse response) : + public RpcException(DaemonErrorResponse response) : base(response.Error.Message) { - Error = response.Error; + Code = response.Error.Code; } } } diff --git a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs index f155654e9..f3f660c6f 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs @@ -30,7 +30,6 @@ public class TransactionDetail public string Address { get; set; } public string Category { get; set; } public double Amount { get; set; } - // not sure if fields below even exists / used - //public double Fee { get; set; } + public double Fee { get; set; } } } diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 539789eef..16bf1e790 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -131,9 +131,9 @@ private IJob GetNewJob() return job; } - catch (DaemonException daemonException) + catch (RpcException rpcException) { - Log.ForContext().Error(daemonException, "Can not read blocktemplate from daemon:"); + Log.ForContext().Error(rpcException, "New job creation failed:"); return null; } catch (Exception e) diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index bff60b0c5..e20257540 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -76,19 +76,22 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, if (share.IsValid) { - _storage.CommitShare(share); + _storage.CommitShare(share); // commit the share. - if (share.IsBlockCandidate) + if (share.IsBlockCandidate) // if share contains a block candicate { - Log.ForContext().Information("Share with block candidate [{0}] accepted at {1:0.00}/{2} by miner {3}.", share.Height, share.Difficulty, miner.Difficulty, miner.Username); - - var success = SubmitBlock(share); // submit block to daemon. - _storage.CommitBlock(share); // commit the block. - - // TODO: notify back job manager using an event so he can create a new job. + Log.ForContext().Debug("Share with block candidate [{0}] accepted at {1:0.00}/{2} by miner {3:l}.", share.Height, share.Difficulty, miner.Difficulty, miner.Username); + + var accepted = SubmitBlock(share); // submit block to daemon. + + if (accepted) + { + OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. + _storage.CommitBlock(share); // commit the block. + } } else - Log.ForContext().Information("Share accepted at {0:0.00}/{1} by miner {2}.", share.Difficulty, miner.Difficulty, miner.Username); + Log.ForContext().Debug("Share accepted at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); } else { @@ -117,7 +120,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, break; } - Log.ForContext().Information("Share rejected at {0:0.00}/{1} by miner {2}.", share.Difficulty, miner.Difficulty, miner.Username); + Log.ForContext().Debug("Share rejected at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); } @@ -143,9 +146,6 @@ private bool SubmitBlock(Share share) : "Submitted block [{0}] but got denied: {1}.", share.Height, share.BlockHash.ToHexString()); - if(isAccepted) - OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. - return isAccepted; } catch (Exception e) diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index 31478d28c..6da41c76d 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -21,7 +21,6 @@ // #endregion -using System; using System.Collections.Generic; using Coinium.Persistance; @@ -31,7 +30,7 @@ public interface IPaymentRound { IPersistedBlock Block {get;} - decimal TotalRewardInSatoshis { get; } + decimal TotalAmount { get; } Dictionary Shares { get; } diff --git a/src/CoiniumServ/Payments/IWorkerBalance.cs b/src/CoiniumServ/Payments/IWorkerBalance.cs index e40b3de4b..a227e79f9 100644 --- a/src/CoiniumServ/Payments/IWorkerBalance.cs +++ b/src/CoiniumServ/Payments/IWorkerBalance.cs @@ -27,7 +27,8 @@ public interface IWorkerBalance { string Worker { get; } - decimal AmountInSatoshis { get; } + decimal Balance { get; } + decimal BalanceInSatoshis { get; } bool Paid { get; set; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 5411ea59b..599500bd3 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -26,7 +26,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using Coinium.Coin.Helpers; using Coinium.Daemon; using Coinium.Daemon.Exceptions; using Coinium.Mining.Pools; @@ -52,7 +51,7 @@ public class PaymentProcessor : IPaymentProcessor private readonly Stopwatch _stopWatch = new Stopwatch(); private const string PoolAddress = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; - private string PoolAccount = string.Empty; + private string _poolAccount = string.Empty; public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) { @@ -97,10 +96,15 @@ private void RunPayments(object state) _stopWatch.Start(); var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. - var rounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. - ProcessRounds(rounds); // process the rounds, calculate shares and payouts per rounds. - var payments = CalculatePayments(rounds); // calculate the payments. - var success = ExecutePayments(payments); // execute the payments. + var paymentRounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. + AssignSharesToRounds(paymentRounds); // process the rounds, calculate shares and payouts per rounds. + var workerBalances = CalculatePayments(paymentRounds); // calculate the payments. + var success = ExecutePayments(workerBalances); // execute the payments. + + if (success) // if the payment executed succesfully, + ProcessRemainingBalances(workerBalances); // process the remaining balances. + + ProcessRounds(paymentRounds, success); // process the rounds. Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); @@ -116,10 +120,13 @@ private IList CalculatePayments(IEnumerable round foreach (var round in rounds) // loop through all rounds { + if (round.Block.Status != PersistedBlockStatus.Confirmed) // only pay to confirmed rounds. + continue; + foreach (var roundPayment in round.Payouts) // loop through all payouts for the rounds { if (!workerBalances.ContainsKey(roundPayment.Key)) // make sure a payout for worker already exists - workerBalances.Add(roundPayment.Key, new WorkerBalance(roundPayment.Key)); + workerBalances.Add(roundPayment.Key, new WorkerBalance(roundPayment.Key, _magnitude)); workerBalances[roundPayment.Key].AddPayment(roundPayment.Value); } @@ -135,52 +142,84 @@ private bool ExecutePayments(IList workerBalances) try { decimal totalAmountToPay = 0; + foreach (var balance in workerBalances) { - if (balance.AmountInSatoshis >= _paymentThresholdInSatoshis) // if worker's balance exceed's threshold, add him to payment list. + if (balance.BalanceInSatoshis >= _paymentThresholdInSatoshis) // if worker's balance exceed's threshold, add him to payment list. { - totalAmountToPay += balance.AmountInSatoshis; - payments.Add(balance.Worker, SatoshisToCoins(balance.AmountInSatoshis)); + totalAmountToPay += balance.Balance; + payments.Add(balance.Worker, balance.Balance); } } - var result = _daemonClient.SendMany(PoolAccount, payments); // send the payments + if (totalAmountToPay <= 0) + { + Log.ForContext().Information("No pending payments found."); + return false; + } - foreach (var balance in workerBalances) + var result = _daemonClient.SendMany(_poolAccount, payments); // send the payments + + // mark the paid ones. + foreach (var balance in workerBalances.Where(balance => balance.BalanceInSatoshis >= _paymentThresholdInSatoshis)) { - // we have paid workers with balance that exceeds the threshold. - balance.Paid = balance.AmountInSatoshis >= _paymentThresholdInSatoshis; + balance.Paid = true; } - Log.ForContext().Information("Paid a total of {0} coins to {1} workers.", SatoshisToCoins(totalAmountToPay), workerBalances.Count); + Log.ForContext().Information("Paid a total of {0} coins to {1} workers.", totalAmountToPay, workerBalances.Count); return true; } - catch (DaemonException e) + catch (RpcException e) { - Log.ForContext().Error("Payment failed: {0} [{1}] - payouts: {2}.", e.Error.Message, e.Error.Code, payments); + Log.ForContext().Error("Payment failed: {0} [{1}] - payouts: {2}.", e.Message, e.Code, payments); return false; } } - public decimal SatoshisToCoins(decimal satoshis) + private void ProcessRemainingBalances(IEnumerable workerBalances) { - return satoshis/_magnitude; + // commit remaining balances to storage. + var remainingBalances = workerBalances.Where(balance => !balance.Paid).ToList(); // find workers with remaining balances. + _storage.CommitRemainingBalances(remainingBalances); } + + private void ProcessRounds(IEnumerable rounds, bool paymentSucceded) + { + foreach (var round in rounds) + { + if (round.Block.Status == PersistedBlockStatus.Pending) // if the block is still pending, + continue; // just skip it. - private void ProcessRounds(IList rounds) + switch (round.Block.Status) + { + case PersistedBlockStatus.Confirmed: + if (!paymentSucceded) // if the payment did not succeed, + continue; // just let the round stay as is. + _storage.DeleteShares(round); // delete the associated shares. + _storage.MovePendingBlock(round); // move pending block to appropriate place. + break; + case PersistedBlockStatus.Kicked: + case PersistedBlockStatus.Orphan: + _storage.MoveSharesToCurrentRound(round); // move shares to current round so the work of miners aren't gone to void. + _storage.MovePendingBlock(round); // move pending block to appropriate place. + break; + } + } + } + + private void AssignSharesToRounds(IList rounds) { // get shares for the rounds. - var roundShares = _storage.GetSharesForRounds(rounds); + var shares = _storage.GetSharesForRounds(rounds); // assign shares to the rounds. foreach (var round in rounds) { - if (roundShares.ContainsKey(round.Block.Height)) - { - round.AddShares(roundShares[round.Block.Height]); - break; - } + if (!shares.ContainsKey(round.Block.Height)) + continue; + + round.AddShares(shares[round.Block.Height]); } } @@ -223,23 +262,18 @@ private IList GetPaymentRounds(IEnumerable block break; } - - if (block.Status == PersistedBlockStatus.Confirmed) - { - // get the reward amount. - var rewardInSatoshis = (decimal)poolOutput.Amount * _magnitude; - rounds.Add(new PaymentRound(block, rewardInSatoshis)); - } + rounds.Add(new PaymentRound(block, (decimal)poolOutput.Amount)); } } - catch (DaemonException exception) + catch (RpcException exception) { - if (exception.Error.Code == -5) + if (exception.Code == -5) Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.",block.Height, block.TransactionHash); else - Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].",block.Height, block.TransactionHash, exception.Error.Message, exception.Error.Code); + Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].",block.Height, block.TransactionHash, exception.Message, exception.Code); block.Status = PersistedBlockStatus.Kicked; // kick the block. + rounds.Add(new PaymentRound(block, 0)); return rounds; } @@ -251,7 +285,7 @@ private IList GetPaymentRounds(IEnumerable block private void GetPoolAccount() { var result = _daemonClient.GetAccount(PoolAddress); - PoolAccount = result; + _poolAccount = result; } private bool ValidatePoolAddress() @@ -287,9 +321,9 @@ private bool DeterminePrecision() return true; } - catch (DaemonException e) + catch (RpcException e) { - Log.ForContext().Error("Halted as getbalance call failed: {0}.", e.Error.Message); + Log.ForContext().Error("Halted as getbalance call failed: {0}.", e.Message); return false; } catch (Exception e) diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs index 32f646191..ea004e0e0 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -30,21 +30,26 @@ namespace Coinium.Payments public class PaymentRound:IPaymentRound { public IPersistedBlock Block { get; private set; } - public decimal TotalRewardInSatoshis { get; private set; } + public decimal TotalAmount { get; private set; } public Dictionary Shares { get; private set; } public Dictionary Payouts { get; private set; } - public PaymentRound(IPersistedBlock block, decimal totalRewardInSatoshis) + public PaymentRound(IPersistedBlock block, decimal totalAmount) { Block = block; - TotalRewardInSatoshis = totalRewardInSatoshis; + TotalAmount = totalAmount; Payouts = new Dictionary(); + Shares = new Dictionary(); } public void AddShares(IDictionary shares) { - Shares = shares.ToDictionary(pair => pair.Key, pair => pair.Value); + foreach (var pair in shares) + { + Shares.Add(pair.Key, pair.Value); + } + CalculatePayouts(); } @@ -56,10 +61,15 @@ private void CalculatePayouts() foreach (var pair in Shares) { var percent = pair.Value/totalShares; - var rewardInSatoshis = (decimal) percent*TotalRewardInSatoshis; + var rewardInSatoshis = (decimal) percent*TotalAmount; Payouts.Add(pair.Key, rewardInSatoshis); } } + + public override string ToString() + { + return string.Format("Amount: {0}, Block: {1}", TotalAmount, Block); + } } } diff --git a/src/CoiniumServ/Payments/WorkerBalance.cs b/src/CoiniumServ/Payments/WorkerBalance.cs index 5e37e49ba..8beee02b1 100644 --- a/src/CoiniumServ/Payments/WorkerBalance.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -21,24 +21,36 @@ // #endregion +using System; + namespace Coinium.Payments { public class WorkerBalance:IWorkerBalance { public string Worker { get; private set; } - public decimal AmountInSatoshis { get; private set; } - public bool Paid { get; set; } + public decimal Balance { get; private set; } + public decimal BalanceInSatoshis { get; private set; } + public bool Paid { get; set; } + + private readonly UInt32 _satoshiMagnitude; - public WorkerBalance(string worker) + public WorkerBalance(string worker, UInt32 satoshiMagnitude) { Worker = worker; - AmountInSatoshis = 0; + Balance = 0; Paid = false; + _satoshiMagnitude = satoshiMagnitude; } public void AddPayment(decimal amount) { - AmountInSatoshis += amount; + Balance += amount; + BalanceInSatoshis = Balance*_satoshiMagnitude; + } + + public override string ToString() + { + return string.Format("Worker: {0}, Balance: {1}", Worker, Balance); } } } diff --git a/src/CoiniumServ/Persistance/IPersistedBlock.cs b/src/CoiniumServ/Persistance/IPersistedBlock.cs index 8ddadd191..e42cc97dd 100644 --- a/src/CoiniumServ/Persistance/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/IPersistedBlock.cs @@ -28,10 +28,8 @@ namespace Coinium.Persistance public interface IPersistedBlock { UInt32 Height { get; } - string BlockHash { get; } string TransactionHash { get; } - PersistedBlockStatus Status { get; set; } } diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index cc30615c7..933da86de 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -35,6 +35,15 @@ public interface IStorage void CommitShare(IShare share); void CommitBlock(IShare share); + + void CommitRemainingBalances(IList workerBalances); + + void DeleteShares(IPaymentRound round); + + void MoveSharesToCurrentRound(IPaymentRound round); + + void MovePendingBlock(IPaymentRound round); + IList GetPendingBlocks(); Dictionary> GetSharesForRounds(IList rounds); diff --git a/src/CoiniumServ/Persistance/PersistedBlock.cs b/src/CoiniumServ/Persistance/PersistedBlock.cs index 5e77baede..4474939af 100644 --- a/src/CoiniumServ/Persistance/PersistedBlock.cs +++ b/src/CoiniumServ/Persistance/PersistedBlock.cs @@ -37,5 +37,10 @@ public PersistedBlock( PersistedBlockStatus status, uint height, string blockHas BlockHash = blockHash; TransactionHash = transactionHash; } + + public override string ToString() + { + return string.Format("Height: {0}, Status: {1}, Block Hash: {2}, Generation Transaction: {3}", Height, Status, BlockHash, TransactionHash); + } } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index c506346e4..9c691bc3f 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -68,21 +68,14 @@ public void CommitShare(IShare share) var batch = _database.CreateBatch(); // batch the commands. // add the share to round - // key: coin:shares:round:current - // field: username, value: difficulty. - var roundKey = string.Format("{0}:shares:round:current", coin); - batch.HashIncrementAsync(roundKey, share.Miner.Username, share.Difficulty, CommandFlags.FireAndForget); + var currentKey = string.Format("{0}:shares:round:current", coin); + batch.HashIncrementAsync(currentKey, share.Miner.Username, share.Difficulty, CommandFlags.FireAndForget); // increment shares stats. - // key: coin:stats - // fields: validShares, invalidShares. var statsKey = string.Format("{0}:stats", coin); batch.HashIncrementAsync(statsKey, share.IsValid ? "validShares" : "invalidShares", 1, CommandFlags.FireAndForget); - // add to hashrate - // key: coin:shares:hashrate - // score: unix-time - // value: difficulty:username + // add to hashrate if (share.IsValid) { var hashrateKey = string.Format("{0}:shares:hashrate", coin); @@ -103,29 +96,106 @@ public void CommitBlock(IShare share) if (share.IsBlockAccepted) { - // rename round [coin:round:current -> coin:round:heigh] + // rename round. var currentKey = string.Format("{0}:shares:round:current", coin); - var newKey = string.Format("{0}:shares:round:{1}", coin, share.Height); - batch.KeyRenameAsync(currentKey, newKey, When.Always, CommandFlags.HighPriority); + var roundKey = string.Format("{0}:shares:round:{1}", coin, share.Height); + batch.KeyRenameAsync(currentKey, roundKey, When.Always, CommandFlags.HighPriority); - // add block to pending - // key: coin:blocks:pending - // score: block height: - // value: blockHash:generation-transaction-hash + // 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()); batch.SortedSetAddAsync(pendingKey, entry, share.Block.Height, CommandFlags.FireAndForget); } // increment block stats. - // key: coin:stats - // fields: validBlocks, invalidBlocks var statsKey = string.Format("{0}:stats", coin); batch.HashIncrementAsync(statsKey, share.IsBlockAccepted ? "validBlocks" : "invalidBlocks", 1, CommandFlags.FireAndForget); batch.Execute(); // execute the batch commands. } + public void CommitRemainingBalances(IList workerBalances) + { + if (!IsEnabled || !IsConnected) + return; + + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + var balancesKey = string.Format("{0}:balances", coin); + var batch = _database.CreateBatch(); // batch the commands. + + foreach (var workerBalance in workerBalances) + { + if(workerBalance.Paid) // skip paid balances. + continue; + + batch.HashIncrementAsync(balancesKey, workerBalance.Worker, (double)workerBalance.Balance, CommandFlags.FireAndForget); + } + + batch.Execute(); // execute the batch commands. + } + + public void DeleteShares(IPaymentRound round) + { + if (!IsEnabled || !IsConnected) + return; + + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + var roundKey = string.Format("{0}:shares:round:{1}", coin, round.Block.Height); + + _database.KeyDeleteAsync(roundKey, CommandFlags.FireAndForget); // delete the associated shares. + } + + public void MoveSharesToCurrentRound(IPaymentRound round) + { + if (!IsEnabled || !IsConnected) + return; + + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + var currentRound = string.Format("{0}:shares:round:current", coin); // current round key. + var roundShares = string.Format("{0}:shares:round:{1}", coin, round.Block.Height); // rounds shares key. + + // add shares to current round again. + foreach (var pair in round.Shares) + { + _database.HashIncrementAsync(currentRound, pair.Key, pair.Value, CommandFlags.FireAndForget); + } + + // delete the associated shares. + _database.KeyDeleteAsync(roundShares, CommandFlags.FireAndForget); // delete the associated shares. + } + + public void MovePendingBlock(IPaymentRound round) + { + if (!IsEnabled || !IsConnected) + return; + + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. + + // re-flag the rounds. + var pendingKey = string.Format("{0}:blocks:pending", coin); // old key for the round. + var newKey = string.Empty; // new key for the round. + + switch (round.Block.Status) + { + case PersistedBlockStatus.Kicked: + newKey = string.Format("{0}:blocks:kicked", coin); + break; + case PersistedBlockStatus.Orphan: + newKey = string.Format("{0}:blocks:orphaned", coin); + break; + case PersistedBlockStatus.Confirmed: + newKey = string.Format("{0}:blocks:confirmed", coin); + break; + } + + if (string.IsNullOrEmpty(newKey)) // if the block is still pending + return; // just skip it. + + var entry = string.Format("{0}:{1}", round.Block.BlockHash, round.Block.TransactionHash); + _database.SortedSetRemoveRangeByScoreAsync(pendingKey, round.Block.Height, round.Block.Height, Exclude.None, CommandFlags.FireAndForget); + _database.SortedSetAddAsync(newKey, entry, round.Block.Height, CommandFlags.FireAndForget); + } + public IList GetPendingBlocks() { var list = new List(); @@ -134,9 +204,9 @@ public IList GetPendingBlocks() return list; var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - var key = string.Format("{0}:blocks:pending", coin); + var pendingKey = string.Format("{0}:blocks:pending", coin); - var task = _database.SortedSetRangeByRankWithScoresAsync(key, 0, -1, Order.Ascending, CommandFlags.HighPriority); + var task = _database.SortedSetRangeByRankWithScoresAsync(pendingKey, 0, -1, Order.Ascending, CommandFlags.HighPriority); var results = task.Result; foreach (var result in results) @@ -162,8 +232,8 @@ public Dictionary> GetSharesForRounds(IList(pair => pair.Name, pair => (double)pair.Value); sharesForRounds.Add(round.Block.Height, shares); @@ -211,7 +281,7 @@ private void Initialize() } } - Log.ForContext().Information("Storage initialized: {0}, v{1}.", endpoint, version); + Log.ForContext().Information("Storage initialized: {0:l}, v{1:l}.", endpoint, version); } catch (Exception e) { diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index ab1f457c2..dc32e5cef 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -75,8 +75,8 @@ static void Main(string[] args) Logging.Init(globalConfig); // print a version banner. - Log.Information("CoiniumServ {0} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); - Log.Information(string.Format("Running over {0} {1}.", PlatformManager.Framework, PlatformManager.FrameworkVersion)); + Log.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); + Log.Information("Running over {0:l} {1:l}.", PlatformManager.Framework.ToString(), PlatformManager.FrameworkVersion); // start pool manager. var poolManager = kernel.Resolve(); From b6522e19b142039da046e21336d6d8425f1efaad Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 7 Jul 2014 20:25:59 +0300 Subject: [PATCH 027/230] Improved ExtraNonce.cs. --- src/CoiniumServ/Mining/Jobs/ExtraNonce.cs | 24 ++++++++----------- src/CoiniumServ/Mining/Jobs/IExtraNonce.cs | 3 +-- .../Server/Stratum/StratumServer.cs | 2 +- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs index 51b5a2f84..ce46fedd4 100644 --- a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs @@ -31,14 +31,7 @@ namespace Coinium.Mining.Jobs /// public class ExtraNonce:IExtraNonce { - /// - /// Extra nonce counter supplied to miners. - /// Last 5 most-significant bits represents instanceId, the rest is just an iterator of jobs. - /// Basically allows us to run more-than-one pool-nodes within the same database. - /// More: https://github.com/moopless/stratum-mining-litecoin/issues/23#issuecomment-22728564 - /// - /// - public UInt32 Current { get; private set; } + private UInt32 _counter; /// /// ExtraNonce placeholder to be used with coinbase transactions. @@ -54,26 +47,29 @@ public class ExtraNonce:IExtraNonce public ExtraNonce(UInt32 instanceId) { ExtraNoncePlaceholder = "f000000ff111111f".HexToByteArray(); - InitExtraNonceCounter(instanceId); // init. the extra nonce counter. + InitCounter(instanceId); // init. the extra nonce counter. } /// /// Inits ExtraNonce counter based on current instance Id. /// - private void InitExtraNonceCounter(UInt32 instanceId) + private void InitCounter(UInt32 instanceId) { - Current = instanceId << 27; // init the ExtraNonce counter - last 5 most-significant bits represents instanceId, the rest is just an iterator of jobs. + _counter = instanceId << 27; // init the ExtraNonce counter - last 5 most-significant bits represents instanceId, the rest is just an iterator of jobs. } /// /// Returns the next extranonce. /// /// - public UInt32 NextExtraNonce() + /// Last 5 most-significant bits represents instanceId, the rest is just an iterator of jobs. + /// Basically allows us to run more-than-one pool-nodes within the same database. + /// More: https://github.com/moopless/stratum-mining-litecoin/issues/23#issuecomment-22728564 + /// + public UInt32 Next() { - Current++; // increment the extranonce. - return Current; + return ++_counter; // return the next extra-nonce. } } } diff --git a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs index 0e4007024..864bfd7c8 100644 --- a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs @@ -27,10 +27,9 @@ namespace Coinium.Mining.Jobs // Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) public interface IExtraNonce { - UInt32 Current { get; } byte[] ExtraNoncePlaceholder { get; } - UInt32 NextExtraNonce(); + UInt32 Next(); } } diff --git a/src/CoiniumServ/Server/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Stratum/StratumServer.cs index 38d12a543..db60b274a 100644 --- a/src/CoiniumServ/Server/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Stratum/StratumServer.cs @@ -104,7 +104,7 @@ private void StratumServer_ClientConnected(object sender, ConnectionEventArgs e) Log.ForContext().Information("Stratum client connected: {0}", e.Connection.ToString()); // TODO: remove the jobManager dependency by instead injecting extranonce counter. - var miner = _minerManager.Create(_jobManager.ExtraNonce.NextExtraNonce(), e.Connection, _pool); + var miner = _minerManager.Create(_jobManager.ExtraNonce.Next(), e.Connection, _pool); e.Connection.Client = miner; } From 7bdf4fe8e5b9517b8a5059c55a7ba2ff9cb44663 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 17:07:51 +0300 Subject: [PATCH 028/230] PaymentProcessor can now handle multiple block-hashes/transaction-hashes per block/round. --- src/CoiniumServ/CoiniumServ.csproj | 2 + src/CoiniumServ/Mining/Shares/ShareManager.cs | 4 +- src/CoiniumServ/Payments/IPaymentRound.cs | 2 - src/CoiniumServ/Payments/IWorkerBalance.cs | 8 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 168 ++++++++++-------- src/CoiniumServ/Payments/PaymentRound.cs | 10 +- src/CoiniumServ/Payments/WorkerBalance.cs | 26 ++- .../Persistance/IPersistedBlock.cs | 11 +- .../Persistance/IPersistedBlockHashes.cs | 33 ++++ src/CoiniumServ/Persistance/IStorage.cs | 10 +- src/CoiniumServ/Persistance/PersistedBlock.cs | 56 +++++- .../Persistance/PersistedBlockHashes.cs | 45 +++++ src/CoiniumServ/Persistance/Redis/Redis.cs | 44 +++-- src/Tests/Mining/Shares/ShareTests.cs | 2 +- 14 files changed, 302 insertions(+), 119 deletions(-) create mode 100644 src/CoiniumServ/Persistance/IPersistedBlockHashes.cs create mode 100644 src/CoiniumServ/Persistance/PersistedBlockHashes.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 4fb34e08e..25fc75800 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -129,7 +129,9 @@ + + diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index e20257540..1a37f549a 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -76,7 +76,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, if (share.IsValid) { - _storage.CommitShare(share); // commit the share. + _storage.AddShare(share); // commit the share. if (share.IsBlockCandidate) // if share contains a block candicate { @@ -87,7 +87,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, if (accepted) { OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. - _storage.CommitBlock(share); // commit the block. + _storage.AddBlock(share); // commit the block. } } else diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index 6da41c76d..e50b40e08 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -30,8 +30,6 @@ public interface IPaymentRound { IPersistedBlock Block {get;} - decimal TotalAmount { get; } - Dictionary Shares { get; } Dictionary Payouts { get; } diff --git a/src/CoiniumServ/Payments/IWorkerBalance.cs b/src/CoiniumServ/Payments/IWorkerBalance.cs index a227e79f9..27f0f8331 100644 --- a/src/CoiniumServ/Payments/IWorkerBalance.cs +++ b/src/CoiniumServ/Payments/IWorkerBalance.cs @@ -30,8 +30,14 @@ public interface IWorkerBalance decimal Balance { get; } decimal BalanceInSatoshis { get; } + decimal PreviousBalance { get; } + + decimal Reward { get; } + bool Paid { get; set; } - void AddPayment(decimal amount); + void AddReward(decimal amount); + + void SetPreviousBalance(double amount); } } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 599500bd3..a2f0a445d 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -28,7 +28,6 @@ using System.Threading; using Coinium.Daemon; using Coinium.Daemon.Exceptions; -using Coinium.Mining.Pools; using Coinium.Persistance; using Serilog; @@ -95,16 +94,17 @@ private void RunPayments(object state) { _stopWatch.Start(); - var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. - var paymentRounds = GetPaymentRounds(pendingBlocks); // get the list of rounds that should be paid. - AssignSharesToRounds(paymentRounds); // process the rounds, calculate shares and payouts per rounds. - var workerBalances = CalculatePayments(paymentRounds); // calculate the payments. - var success = ExecutePayments(workerBalances); // execute the payments. + var blocks = _storage.GetPendingBlocks(); // get all the pending blocks. + CheckBlocks(blocks); + var rounds = GetPaymentRounds(blocks); // 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. + //ExecutePayments(workerBalances); // execute the payments. - if (success) // if the payment executed succesfully, - ProcessRemainingBalances(workerBalances); // process the remaining balances. + ProcessRemainingBalances(workerBalances); // process the remaining balances. - ProcessRounds(paymentRounds, success); // process the rounds. + ProcessRounds(rounds); // process the rounds. Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); @@ -114,28 +114,44 @@ private void RunPayments(object state) } } - private IList CalculatePayments(IEnumerable rounds) + private Dictionary GetPreviousBalances() + { + var previousBalances = _storage.GetPreviousBalances(); + return previousBalances; + } + + private IEnumerable CalculateRewards(IEnumerable rounds, IDictionary previousBalances) { var workerBalances = new Dictionary(); - foreach (var round in rounds) // loop through all rounds + // set previous balances + foreach(var pair in previousBalances) + { + if (!workerBalances.ContainsKey(pair.Key)) + workerBalances.Add(pair.Key, new WorkerBalance(pair.Key, _magnitude)); + + workerBalances[pair.Key].SetPreviousBalance(pair.Value); + } + + // add rewards by rounds + foreach (var round in rounds) { if (round.Block.Status != PersistedBlockStatus.Confirmed) // only pay to confirmed rounds. continue; - foreach (var roundPayment in round.Payouts) // loop through all payouts for the rounds + foreach (var pair in round.Payouts) // loop through all payouts for the rounds { - if (!workerBalances.ContainsKey(roundPayment.Key)) // make sure a payout for worker already exists - workerBalances.Add(roundPayment.Key, new WorkerBalance(roundPayment.Key, _magnitude)); + if (!workerBalances.ContainsKey(pair.Key)) // make sure a payout for worker already exists + workerBalances.Add(pair.Key, new WorkerBalance(pair.Key, _magnitude)); - workerBalances[roundPayment.Key].AddPayment(roundPayment.Value); + workerBalances[pair.Key].AddReward(pair.Value); } } return workerBalances.Values.ToList(); } - private bool ExecutePayments(IList workerBalances) + private void ExecutePayments(IList workerBalances) { var payments = new Dictionary(); @@ -155,7 +171,7 @@ private bool ExecutePayments(IList workerBalances) if (totalAmountToPay <= 0) { Log.ForContext().Information("No pending payments found."); - return false; + return; } var result = _daemonClient.SendMany(_poolAccount, payments); // send the payments @@ -167,13 +183,10 @@ private bool ExecutePayments(IList workerBalances) } Log.ForContext().Information("Paid a total of {0} coins to {1} workers.", totalAmountToPay, workerBalances.Count); - - return true; } catch (RpcException e) { Log.ForContext().Error("Payment failed: {0} [{1}] - payouts: {2}.", e.Message, e.Code, payments); - return false; } } @@ -181,28 +194,26 @@ private void ProcessRemainingBalances(IEnumerable workerBalances { // commit remaining balances to storage. var remainingBalances = workerBalances.Where(balance => !balance.Paid).ToList(); // find workers with remaining balances. - _storage.CommitRemainingBalances(remainingBalances); + _storage.SetRemainingBalances(remainingBalances); } - - private void ProcessRounds(IEnumerable rounds, bool paymentSucceded) + + private void ProcessRounds(IEnumerable rounds) { foreach (var round in rounds) { - if (round.Block.Status == PersistedBlockStatus.Pending) // if the block is still pending, + if (round.Block.OutstandingHashes.Status == PersistedBlockStatus.Pending) // if the block is still pending, continue; // just skip it. - switch (round.Block.Status) + switch (round.Block.OutstandingHashes.Status) { case PersistedBlockStatus.Confirmed: - if (!paymentSucceded) // if the payment did not succeed, - continue; // just let the round stay as is. _storage.DeleteShares(round); // delete the associated shares. - _storage.MovePendingBlock(round); // move pending block to appropriate place. + _storage.MoveBlock(round); // move pending block to appropriate place. break; case PersistedBlockStatus.Kicked: case PersistedBlockStatus.Orphan: _storage.MoveSharesToCurrentRound(round); // move shares to current round so the work of miners aren't gone to void. - _storage.MovePendingBlock(round); // move pending block to appropriate place. + _storage.MoveBlock(round); // move pending block to appropriate place. break; } } @@ -223,63 +234,72 @@ private void AssignSharesToRounds(IList rounds) } } - private IList GetPaymentRounds(IEnumerable blocks) + private void CheckBlockHashes(IPersistedBlockHashes hashes) { - var rounds = new List(); - - foreach (var block in blocks) + try { - try - { - // get the transaction. - var transaction = _daemonClient.GetTransaction(block.TransactionHash); + // get the transaction. + var transaction = _daemonClient.GetTransaction(hashes.TransactionHash); - // get the output transaction that targets pools central wallet. - var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); + // get the output transaction that targets pools central wallet. + var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); - // make sure output for the pool central wallet exists - if (poolOutput == null) + // make sure output for the pool central wallet exists + if (poolOutput == null) + { + hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. + hashes.Reward = 0; + } + else + { + switch (poolOutput.Category) { - Log.ForContext().Error("Kicking block {0} as transaction doesn't contain output for the pool's central wallet.",block.Height); - block.Status = PersistedBlockStatus.Kicked; // kick the block. + case "immature": + hashes.Status = PersistedBlockStatus.Pending; + break; + case "orphan": + hashes.Status = PersistedBlockStatus.Orphan; + break; + case "generate": + hashes.Status = PersistedBlockStatus.Confirmed; + break; + default: + hashes.Status = PersistedBlockStatus.Pending; + break; } - else - { - switch (poolOutput.Category) - { - case "immature": - block.Status = PersistedBlockStatus.Pending; - break; - case "orphan": - block.Status = PersistedBlockStatus.Orphan; - break; - case "generate": - block.Status = PersistedBlockStatus.Confirmed; - break; - default: - // send, recieve, move - TODO: we shouldn't be seing these categories! Implement an error message and kick it may be? - block.Status = PersistedBlockStatus.Pending; - break; - } - - rounds.Add(new PaymentRound(block, (decimal)poolOutput.Amount)); - } + + hashes.Reward = (decimal) poolOutput.Amount; } - catch (RpcException exception) + } + catch (RpcException) + { + hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. + hashes.Reward = 0; + } + } + + private void CheckBlocks(IEnumerable blocks) + { + foreach (var block in blocks) + { + foreach (var hashes in block.Hashes) { - if (exception.Code == -5) - Log.ForContext().Error("Kicking block {0} as daemon reported invalid generation transaction id: {1}.",block.Height, block.TransactionHash); - else - Log.ForContext().Error("Kicking block {0} as daemon reported an unknown error with generation transaction: {1:l} error: {2:l} [{3}].",block.Height, block.TransactionHash, exception.Message, exception.Code); + CheckBlockHashes(hashes); + } + } + } - block.Status = PersistedBlockStatus.Kicked; // kick the block. - rounds.Add(new PaymentRound(block, 0)); + private IList GetPaymentRounds(IEnumerable blocks) + { + var rounds = new List(); - return rounds; - } + foreach (var block in blocks) + { + var round = new PaymentRound(block); + rounds.Add(round); } - return rounds; + return rounds; } private void GetPoolAccount() diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs index ea004e0e0..1664bc012 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -30,15 +30,13 @@ namespace Coinium.Payments public class PaymentRound:IPaymentRound { public IPersistedBlock Block { get; private set; } - public decimal TotalAmount { get; private set; } public Dictionary Shares { get; private set; } public Dictionary Payouts { get; private set; } - public PaymentRound(IPersistedBlock block, decimal totalAmount) + public PaymentRound(IPersistedBlock block) { Block = block; - TotalAmount = totalAmount; Payouts = new Dictionary(); Shares = new Dictionary(); } @@ -61,15 +59,15 @@ private void CalculatePayouts() foreach (var pair in Shares) { var percent = pair.Value/totalShares; - var rewardInSatoshis = (decimal) percent*TotalAmount; + var workerRewardInSatoshis = (decimal) percent*Block.OutstandingHashes.Reward; - Payouts.Add(pair.Key, rewardInSatoshis); + Payouts.Add(pair.Key, workerRewardInSatoshis); } } public override string ToString() { - return string.Format("Amount: {0}, Block: {1}", TotalAmount, Block); + return string.Format("Amount: {0}, Block: {1}", Block.OutstandingHashes.Reward, Block); } } } diff --git a/src/CoiniumServ/Payments/WorkerBalance.cs b/src/CoiniumServ/Payments/WorkerBalance.cs index 8beee02b1..9d167811a 100644 --- a/src/CoiniumServ/Payments/WorkerBalance.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -30,6 +30,8 @@ public class WorkerBalance:IWorkerBalance public string Worker { get; private set; } public decimal Balance { get; private set; } public decimal BalanceInSatoshis { get; private set; } + public decimal PreviousBalance { get; private set; } + public decimal Reward { get; private set; } public bool Paid { get; set; } private readonly UInt32 _satoshiMagnitude; @@ -37,20 +39,34 @@ public class WorkerBalance:IWorkerBalance public WorkerBalance(string worker, UInt32 satoshiMagnitude) { Worker = worker; + _satoshiMagnitude = satoshiMagnitude; Balance = 0; + BalanceInSatoshis = 0; + PreviousBalance = 0; + Reward = 0; Paid = false; - _satoshiMagnitude = satoshiMagnitude; } - public void AddPayment(decimal amount) + public void AddReward(decimal amount) + { + Reward += amount; + CalculateBalance(); + } + + public void SetPreviousBalance(double amount) + { + PreviousBalance = (decimal)amount; + } + + private void CalculateBalance() { - Balance += amount; - BalanceInSatoshis = Balance*_satoshiMagnitude; + Balance = PreviousBalance + Reward; + BalanceInSatoshis = Balance * _satoshiMagnitude; } public override string ToString() { - return string.Format("Worker: {0}, Balance: {1}", Worker, Balance); + return string.Format("Worker: {0}, Balance: {1} Previous: {2} Reward: {3}", Worker, Balance, PreviousBalance, Reward); } } } diff --git a/src/CoiniumServ/Persistance/IPersistedBlock.cs b/src/CoiniumServ/Persistance/IPersistedBlock.cs index e42cc97dd..9e6fe703b 100644 --- a/src/CoiniumServ/Persistance/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/IPersistedBlock.cs @@ -22,18 +22,21 @@ #endregion using System; +using System.Collections.Generic; namespace Coinium.Persistance { public interface IPersistedBlock { UInt32 Height { get; } - string BlockHash { get; } - string TransactionHash { get; } - PersistedBlockStatus Status { get; set; } + List Hashes { get; } + PersistedBlockStatus Status { get; } + IPersistedBlockHashes OutstandingHashes { get; } + + void AddHashes(IPersistedBlockHashes hash); } - public enum PersistedBlockStatus + public enum PersistedBlockStatus { Pending, Kicked, diff --git a/src/CoiniumServ/Persistance/IPersistedBlockHashes.cs b/src/CoiniumServ/Persistance/IPersistedBlockHashes.cs new file mode 100644 index 000000000..a26c96db9 --- /dev/null +++ b/src/CoiniumServ/Persistance/IPersistedBlockHashes.cs @@ -0,0 +1,33 @@ +#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 Coinium.Persistance +{ + public interface IPersistedBlockHashes + { + string BlockHash { get; } + string TransactionHash { get; } + PersistedBlockStatus Status { get; set; } + decimal Reward { get; set; } + } +} diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 933da86de..6acacb469 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -32,20 +32,22 @@ public interface IStorage { bool IsEnabled { get; } - void CommitShare(IShare share); + void AddShare(IShare share); - void CommitBlock(IShare share); + void AddBlock(IShare share); - void CommitRemainingBalances(IList workerBalances); + void SetRemainingBalances(IList workerBalances); void DeleteShares(IPaymentRound round); void MoveSharesToCurrentRound(IPaymentRound round); - void MovePendingBlock(IPaymentRound round); + void MoveBlock(IPaymentRound round); IList GetPendingBlocks(); Dictionary> GetSharesForRounds(IList rounds); + + Dictionary GetPreviousBalances(); } } diff --git a/src/CoiniumServ/Persistance/PersistedBlock.cs b/src/CoiniumServ/Persistance/PersistedBlock.cs index 4474939af..3903f0abe 100644 --- a/src/CoiniumServ/Persistance/PersistedBlock.cs +++ b/src/CoiniumServ/Persistance/PersistedBlock.cs @@ -21,26 +21,66 @@ // #endregion +using System.Collections.Generic; +using System.Linq; + namespace Coinium.Persistance { public class PersistedBlock : IPersistedBlock { public uint Height { get; private set; } - public string BlockHash { get; private set; } - public string TransactionHash { get; private set; } - public PersistedBlockStatus Status { get; set; } - public PersistedBlock( PersistedBlockStatus status, uint height, string blockHash, string transactionHash) + public List Hashes { get; private set; } + + public IPersistedBlockHashes OutstandingHashes + { + get + { + switch (Status) + { + case PersistedBlockStatus.Pending: + return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Pending); + case PersistedBlockStatus.Kicked: + return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Kicked); + case PersistedBlockStatus.Orphan: + return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Orphan); + case PersistedBlockStatus.Confirmed: + return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Confirmed); + } + + return null; + } + } + + public PersistedBlockStatus Status + { + get + { + if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Confirmed)) // if any hash is confirmed + return PersistedBlockStatus.Confirmed; // block is confirmed + else if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Orphan)) // if any hash is orphaned + return PersistedBlockStatus.Orphan; // block is orphaned + else if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Kicked)) // if any hash is kicked + return PersistedBlockStatus.Kicked; // block is kicked + else + return PersistedBlockStatus.Pending; // block is pending + } + } + + public PersistedBlock(uint height) { - Status = status; Height = height; - BlockHash = blockHash; - TransactionHash = transactionHash; + Hashes = new List(); + } + + public void AddHashes(IPersistedBlockHashes hash) + { + Hashes.Add(hash); } public override string ToString() { - return string.Format("Height: {0}, Status: {1}, Block Hash: {2}, Generation Transaction: {3}", Height, Status, BlockHash, TransactionHash); + return string.Format("Height: {0}, Status: {1}, Outstanding: {2}", Height, Status,OutstandingHashes); } } } diff --git a/src/CoiniumServ/Persistance/PersistedBlockHashes.cs b/src/CoiniumServ/Persistance/PersistedBlockHashes.cs new file mode 100644 index 000000000..17a2a8290 --- /dev/null +++ b/src/CoiniumServ/Persistance/PersistedBlockHashes.cs @@ -0,0 +1,45 @@ +#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 Coinium.Persistance +{ + public class PersistedBlockHashes : IPersistedBlockHashes + { + public string BlockHash { get; private set; } + public string TransactionHash { get; private set; } + public PersistedBlockStatus Status { get; set; } + public decimal Reward { get; set; } + + public PersistedBlockHashes(string blockHash, string transactionHash) + { + BlockHash = blockHash; + TransactionHash = transactionHash; + Status=PersistedBlockStatus.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/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 9c691bc3f..ae3962373 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -25,6 +25,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using Coinium.Daemon.Responses; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Payments; @@ -59,7 +60,7 @@ public Redis(IGlobalConfigFactory globalConfigFactory, IPoolConfig poolConfig) Initialize(); } - public void CommitShare(IShare share) + public void AddShare(IShare share) { if (!IsEnabled || !IsConnected) return; @@ -86,7 +87,7 @@ public void CommitShare(IShare share) batch.Execute(); // execute the batch commands. } - public void CommitBlock(IShare share) + public void AddBlock(IShare share) { if (!IsEnabled || !IsConnected) return; @@ -114,13 +115,12 @@ public void CommitBlock(IShare share) batch.Execute(); // execute the batch commands. } - public void CommitRemainingBalances(IList workerBalances) + public void SetRemainingBalances(IList workerBalances) { if (!IsEnabled || !IsConnected) return; - var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. - var balancesKey = string.Format("{0}:balances", coin); + var balancesKey = string.Format("{0}:balances", _poolConfig.Coin.Name.ToLower()); var batch = _database.CreateBatch(); // batch the commands. foreach (var workerBalance in workerBalances) @@ -164,7 +164,7 @@ public void MoveSharesToCurrentRound(IPaymentRound round) _database.KeyDeleteAsync(roundShares, CommandFlags.FireAndForget); // delete the associated shares. } - public void MovePendingBlock(IPaymentRound round) + public void MoveBlock(IPaymentRound round) { if (!IsEnabled || !IsConnected) return; @@ -191,17 +191,17 @@ public void MovePendingBlock(IPaymentRound round) if (string.IsNullOrEmpty(newKey)) // if the block is still pending return; // just skip it. - var entry = string.Format("{0}:{1}", round.Block.BlockHash, round.Block.TransactionHash); + var entry = string.Format("{0}:{1}", round.Block.OutstandingHashes.BlockHash, round.Block.OutstandingHashes.TransactionHash); _database.SortedSetRemoveRangeByScoreAsync(pendingKey, round.Block.Height, round.Block.Height, Exclude.None, CommandFlags.FireAndForget); _database.SortedSetAddAsync(newKey, entry, round.Block.Height, CommandFlags.FireAndForget); } public IList GetPendingBlocks() { - var list = new List(); + var blocks = new Dictionary(); if (!IsEnabled || !IsConnected) - return list; + return blocks.Values.ToList(); var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var pendingKey = string.Format("{0}:blocks:pending", coin); @@ -214,11 +214,16 @@ public IList GetPendingBlocks() var data = result.Element.ToString().Split(':'); var blockHash = data[0]; var transactionHash = data[1]; - var persistedBlock = new PersistedBlock(PersistedBlockStatus.Pending, (UInt32)result.Score, blockHash, transactionHash); - list.Add(persistedBlock); + var hashes = new PersistedBlockHashes(blockHash, transactionHash); + + if (!blocks.ContainsKey((UInt32) result.Score)) + blocks.Add((UInt32) result.Score, new PersistedBlock((UInt32) result.Score)); + + var persistedBlock = blocks[(UInt32) result.Score]; + persistedBlock.AddHashes(hashes); } - return list; + return blocks.Values.ToList(); } public Dictionary> GetSharesForRounds(IList rounds) @@ -242,6 +247,21 @@ public Dictionary> GetSharesForRounds(IList GetPreviousBalances() + { + var previousBalances = new Dictionary(); + + if (!IsEnabled || !IsConnected) + return previousBalances; + + var key = string.Format("{0}:balances", _poolConfig.Coin.Name.ToLower()); + var hashes = _database.HashGetAllAsync(key, CommandFlags.HighPriority).Result; + + previousBalances = hashes.ToDictionary(pair => pair.Name, pair => (double)pair.Value); + + return previousBalances; + } + private void Initialize() { var options = new ConfigurationOptions() diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index 472794951..95e693d09 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -153,7 +153,7 @@ public ShareTests() // the job manager. _jobManager = Substitute.For(); - _jobManager.ExtraNonce.Current.Returns((UInt32)0x58000000); + _jobManager.ExtraNonce.Next().Returns((UInt32)0x58000000); // coin config _miner = Substitute.For(); From f52895e9d661b1525a9d5eb0112af84f86f18ed8 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 17:14:46 +0300 Subject: [PATCH 029/230] Fixed job not found error. --- src/CoiniumServ/Mining/Shares/ShareManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 1a37f549a..b1680ce40 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -110,7 +110,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, JsonRpcContext.SetException(new OtherError("Incorrect nonce size")); break; case ShareError.JobNotFound: - JsonRpcContext.SetException(new JobNotFoundError(share.Job.Id)); + JsonRpcContext.SetException(new JobNotFoundError(id)); break; case ShareError.LowDifficultyShare: JsonRpcContext.SetException(new LowDifficultyShare(share.Difficulty)); From dfd8b62f9c5e9eeacbeb68c59b1a843b325e26ec Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 17:42:12 +0300 Subject: [PATCH 030/230] PaymentProcessor.cs now also considers previous balances. --- src/CoiniumServ/Payments/PaymentProcessor.cs | 10 ++++------ src/CoiniumServ/Payments/WorkerBalance.cs | 1 + src/CoiniumServ/Persistance/Redis/Redis.cs | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index a2f0a445d..4624802a3 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -100,7 +100,7 @@ private void RunPayments(object state) 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. - //ExecutePayments(workerBalances); // execute the payments. + ExecutePayments(workerBalances); // execute the payments. ProcessRemainingBalances(workerBalances); // process the remaining balances. @@ -120,7 +120,7 @@ private Dictionary GetPreviousBalances() return previousBalances; } - private IEnumerable CalculateRewards(IEnumerable rounds, IDictionary previousBalances) + private IList CalculateRewards(IEnumerable rounds, IDictionary previousBalances) { var workerBalances = new Dictionary(); @@ -190,11 +190,9 @@ private void ExecutePayments(IList workerBalances) } } - private void ProcessRemainingBalances(IEnumerable workerBalances) + private void ProcessRemainingBalances(IList workerBalances) { - // commit remaining balances to storage. - var remainingBalances = workerBalances.Where(balance => !balance.Paid).ToList(); // find workers with remaining balances. - _storage.SetRemainingBalances(remainingBalances); + _storage.SetRemainingBalances(workerBalances); // commit remaining balances to storage. } private void ProcessRounds(IEnumerable rounds) diff --git a/src/CoiniumServ/Payments/WorkerBalance.cs b/src/CoiniumServ/Payments/WorkerBalance.cs index 9d167811a..1a4977634 100644 --- a/src/CoiniumServ/Payments/WorkerBalance.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -56,6 +56,7 @@ public void AddReward(decimal amount) public void SetPreviousBalance(double amount) { PreviousBalance = (decimal)amount; + CalculateBalance(); } private void CalculateBalance() diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index ae3962373..c4f2d6a14 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -125,10 +125,10 @@ public void SetRemainingBalances(IList workerBalances) foreach (var workerBalance in workerBalances) { - if(workerBalance.Paid) // skip paid balances. - continue; + batch.HashDeleteAsync(balancesKey, workerBalance.Worker, CommandFlags.FireAndForget); // first delete the existing key. - batch.HashIncrementAsync(balancesKey, workerBalance.Worker, (double)workerBalance.Balance, CommandFlags.FireAndForget); + if(!workerBalance.Paid) // if outstanding balance exists, commit it. + batch.HashIncrementAsync(balancesKey, workerBalance.Worker, (double)workerBalance.Balance, CommandFlags.FireAndForget); // increment the value. } batch.Execute(); // execute the batch commands. From d8f49451402b801f058d1e5f8abb995f65af266a Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 18:14:56 +0300 Subject: [PATCH 031/230] Testing nancyfx based web-server. Updated serilog. --- src/CoiniumServ/CoiniumServ.csproj | 9 --------- src/CoiniumServ/Program.cs | 3 +++ src/CoiniumServ/Server/Web/WebServer.cs | 4 ++-- src/CoiniumServ/packages.config | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 25fc75800..f71656bc3 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -81,14 +81,6 @@ False ..\..\build\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll - - False - ..\..\build\packages\Serilog.1.3.33\lib\net40\Serilog.dll - - - False - ..\..\build\packages\Serilog.1.3.33\lib\net40\Serilog.FullNetFx.dll - False ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll @@ -883,7 +875,6 @@ - diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index dc32e5cef..cb583190e 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -26,6 +26,7 @@ using System.Threading; using Coinium.Mining.Pools; using Coinium.Repository; +using Coinium.Server; using Coinium.Utils.Commands; using Coinium.Utils.Configuration; using Coinium.Utils.Console; @@ -78,6 +79,8 @@ static void Main(string[] args) Log.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); Log.Information("Running over {0:l} {1:l}.", PlatformManager.Framework.ToString(), PlatformManager.FrameworkVersion); + ServerManager.Instance.Start(); + // start pool manager. var poolManager = kernel.Resolve(); poolManager.Run(); diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 208ea29fb..aea79a0ff 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -41,8 +41,8 @@ public class WebServer /// public WebServer() { - //this.Interface = Config.Instance.Interface; - //this.Port = Config.Instance.Port; + this.Interface = "127.0.0.1"; + this.Port = 8082; } public void Start() diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index f5cf596f9..2ba6c7c71 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -10,6 +10,6 @@ - + \ No newline at end of file From fb2ba1d2d8b10e177367de49e2f2c7247cada046 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 18:34:19 +0300 Subject: [PATCH 032/230] Nancy views testing. --- src/CoiniumServ/CoiniumServ.csproj | 15 +++++++++++++-- src/CoiniumServ/{ => Net}/Server/Web/WebServer.cs | 3 ++- src/CoiniumServ/Server/ServerManager.cs | 2 ++ .../Server/Web/Modules/{Stats.cs => Home.cs} | 12 ++++++------ src/CoiniumServ/views/Home/Index.cshtml | 11 +++++++++++ 5 files changed, 34 insertions(+), 9 deletions(-) rename src/CoiniumServ/{ => Net}/Server/Web/WebServer.cs (98%) rename src/CoiniumServ/Server/Web/Modules/{Stats.cs => Home.cs} (81%) create mode 100644 src/CoiniumServ/views/Home/Index.cshtml diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index f71656bc3..de7284f0f 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -81,6 +81,14 @@ False ..\..\build\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll + + False + ..\..\build\packages\Serilog.1.3.34\lib\net40\Serilog.dll + + + False + ..\..\build\packages\Serilog.1.3.34\lib\net40\Serilog.FullNetFx.dll + False ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net40\StackExchange.Redis.dll @@ -301,8 +309,8 @@ - - + + @@ -861,6 +869,9 @@ + + PreserveNewest + diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Net/Server/Web/WebServer.cs similarity index 98% rename from src/CoiniumServ/Server/Web/WebServer.cs rename to src/CoiniumServ/Net/Server/Web/WebServer.cs index aea79a0ff..9f4e4b04c 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Net/Server/Web/WebServer.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using Nancy; using Nancy.Bootstrapper; @@ -28,7 +29,7 @@ using Nancy.TinyIoc; using Serilog; -namespace Coinium.Server.Web +namespace Coinium.Net.Server.Web { public class WebServer { diff --git a/src/CoiniumServ/Server/ServerManager.cs b/src/CoiniumServ/Server/ServerManager.cs index 6fd627453..724bb5974 100644 --- a/src/CoiniumServ/Server/ServerManager.cs +++ b/src/CoiniumServ/Server/ServerManager.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using Coinium.Net.Server.Web; using Coinium.Server.Web; using Serilog; diff --git a/src/CoiniumServ/Server/Web/Modules/Stats.cs b/src/CoiniumServ/Server/Web/Modules/Home.cs similarity index 81% rename from src/CoiniumServ/Server/Web/Modules/Stats.cs rename to src/CoiniumServ/Server/Web/Modules/Home.cs index 31a2960dd..f8f1e59a6 100644 --- a/src/CoiniumServ/Server/Web/Modules/Stats.cs +++ b/src/CoiniumServ/Server/Web/Modules/Home.cs @@ -25,14 +25,14 @@ namespace Coinium.Server.Web.Modules { - public class Stats : NancyModule + public class HomeModule : NancyModule { - public Stats() + public HomeModule() { - var banner = string.Format("v{0}", Assembly.GetAssembly(typeof(Program)).GetName().Version); - - Get["/"] = x => "coinium"; - Get["/version"] = x => banner; + Get["/"] = parameters => + { + return View["Index"]; + }; } } } diff --git a/src/CoiniumServ/views/Home/Index.cshtml b/src/CoiniumServ/views/Home/Index.cshtml new file mode 100644 index 000000000..81c614bc3 --- /dev/null +++ b/src/CoiniumServ/views/Home/Index.cshtml @@ -0,0 +1,11 @@ + + + + + + + + + fdsfsfsdfsf + + \ No newline at end of file From ee69233dc7cc3a98a06755bad3d9bc3a6445fd88 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 8 Jul 2014 20:07:34 +0300 Subject: [PATCH 033/230] Added custom bootstrapper for nancy. Added sb-admin theme as default. --- assets/web/default/blank-page.html | 141 + assets/web/default/bootstrap-elements.html | 745 +++ assets/web/default/bootstrap-grid.html | 400 ++ assets/web/default/charts.html | 314 + assets/web/default/css/bootstrap.css | 5831 +++++++++++++++++ assets/web/default/css/bootstrap.min.css | 7 + assets/web/default/css/sb-admin.css | 164 + .../default/font-awesome/css/font-awesome.css | 1338 ++++ .../font-awesome/css/font-awesome.min.css | 4 + .../font-awesome/fonts/FontAwesome.otf | Bin 0 -> 62856 bytes .../fonts/fontawesome-webfont.eot | Bin 0 -> 38205 bytes .../fonts/fontawesome-webfont.svg | 414 ++ .../fonts/fontawesome-webfont.ttf | Bin 0 -> 80652 bytes .../fonts/fontawesome-webfont.woff | Bin 0 -> 44432 bytes .../font-awesome/less/bordered-pulled.less | 16 + .../web/default/font-awesome/less/core.less | 12 + .../font-awesome/less/fixed-width.less | 6 + .../font-awesome/less/font-awesome.less | 17 + .../web/default/font-awesome/less/icons.less | 412 ++ .../web/default/font-awesome/less/larger.less | 13 + .../web/default/font-awesome/less/list.less | 19 + .../web/default/font-awesome/less/mixins.less | 20 + .../web/default/font-awesome/less/path.less | 14 + .../font-awesome/less/rotated-flipped.less | 9 + .../default/font-awesome/less/spinning.less | 30 + .../default/font-awesome/less/stacked.less | 20 + .../default/font-awesome/less/variables.less | 381 ++ .../font-awesome/scss/_bordered-pulled.scss | 16 + .../web/default/font-awesome/scss/_core.scss | 12 + .../font-awesome/scss/_fixed-width.scss | 6 + .../web/default/font-awesome/scss/_icons.scss | 412 ++ .../default/font-awesome/scss/_larger.scss | 13 + .../web/default/font-awesome/scss/_list.scss | 19 + .../default/font-awesome/scss/_mixins.scss | 20 + .../web/default/font-awesome/scss/_path.scss | 14 + .../font-awesome/scss/_rotated-flipped.scss | 9 + .../default/font-awesome/scss/_spinning.scss | 30 + .../default/font-awesome/scss/_stacked.scss | 20 + .../default/font-awesome/scss/_variables.scss | 381 ++ .../font-awesome/scss/font-awesome.scss | 17 + assets/web/default/forms.html | 365 ++ assets/web/default/index.html | 421 ++ assets/web/default/js/bootstrap.js | 1951 ++++++ assets/web/default/js/bootstrap.min.js | 6 + assets/web/default/js/flot/chart-data-flot.js | 237 + assets/web/default/js/flot/excanvas.min.js | 1 + assets/web/default/js/flot/jquery.flot.js | 2599 ++++++++ assets/web/default/js/flot/jquery.flot.pie.js | 750 +++ .../web/default/js/flot/jquery.flot.resize.js | 60 + .../js/flot/jquery.flot.tooltip.min.js | 12 + assets/web/default/js/jquery-1.10.2.js | 6 + .../default/js/morris/chart-data-morris.js | 128 + .../js/tablesorter/jquery.tablesorter.js | 1031 +++ assets/web/default/js/tablesorter/tables.js | 3 + assets/web/default/tables.html | 457 ++ assets/web/default/typography.html | 269 + src/CoiniumServ/CoiniumServ.csproj | 230 +- .../Net/Server/Web/BootStrapper.cs | 63 + .../Net/Server/Web/RootPathProvider.cs | 38 + src/CoiniumServ/Net/Server/Web/WebServer.cs | 19 +- src/CoiniumServ/Server/Web/Modules/Home.cs | 5 + src/CoiniumServ/views/Home/Index.cshtml | 11 - 62 files changed, 19926 insertions(+), 32 deletions(-) create mode 100644 assets/web/default/blank-page.html create mode 100644 assets/web/default/bootstrap-elements.html create mode 100644 assets/web/default/bootstrap-grid.html create mode 100644 assets/web/default/charts.html create mode 100644 assets/web/default/css/bootstrap.css create mode 100644 assets/web/default/css/bootstrap.min.css create mode 100644 assets/web/default/css/sb-admin.css create mode 100644 assets/web/default/font-awesome/css/font-awesome.css create mode 100644 assets/web/default/font-awesome/css/font-awesome.min.css create mode 100644 assets/web/default/font-awesome/fonts/FontAwesome.otf create mode 100644 assets/web/default/font-awesome/fonts/fontawesome-webfont.eot create mode 100644 assets/web/default/font-awesome/fonts/fontawesome-webfont.svg create mode 100644 assets/web/default/font-awesome/fonts/fontawesome-webfont.ttf create mode 100644 assets/web/default/font-awesome/fonts/fontawesome-webfont.woff create mode 100644 assets/web/default/font-awesome/less/bordered-pulled.less create mode 100644 assets/web/default/font-awesome/less/core.less create mode 100644 assets/web/default/font-awesome/less/fixed-width.less create mode 100644 assets/web/default/font-awesome/less/font-awesome.less create mode 100644 assets/web/default/font-awesome/less/icons.less create mode 100644 assets/web/default/font-awesome/less/larger.less create mode 100644 assets/web/default/font-awesome/less/list.less create mode 100644 assets/web/default/font-awesome/less/mixins.less create mode 100644 assets/web/default/font-awesome/less/path.less create mode 100644 assets/web/default/font-awesome/less/rotated-flipped.less create mode 100644 assets/web/default/font-awesome/less/spinning.less create mode 100644 assets/web/default/font-awesome/less/stacked.less create mode 100644 assets/web/default/font-awesome/less/variables.less create mode 100644 assets/web/default/font-awesome/scss/_bordered-pulled.scss create mode 100644 assets/web/default/font-awesome/scss/_core.scss create mode 100644 assets/web/default/font-awesome/scss/_fixed-width.scss create mode 100644 assets/web/default/font-awesome/scss/_icons.scss create mode 100644 assets/web/default/font-awesome/scss/_larger.scss create mode 100644 assets/web/default/font-awesome/scss/_list.scss create mode 100644 assets/web/default/font-awesome/scss/_mixins.scss create mode 100644 assets/web/default/font-awesome/scss/_path.scss create mode 100644 assets/web/default/font-awesome/scss/_rotated-flipped.scss create mode 100644 assets/web/default/font-awesome/scss/_spinning.scss create mode 100644 assets/web/default/font-awesome/scss/_stacked.scss create mode 100644 assets/web/default/font-awesome/scss/_variables.scss create mode 100644 assets/web/default/font-awesome/scss/font-awesome.scss create mode 100644 assets/web/default/forms.html create mode 100644 assets/web/default/index.html create mode 100644 assets/web/default/js/bootstrap.js create mode 100644 assets/web/default/js/bootstrap.min.js create mode 100644 assets/web/default/js/flot/chart-data-flot.js create mode 100644 assets/web/default/js/flot/excanvas.min.js create mode 100644 assets/web/default/js/flot/jquery.flot.js create mode 100644 assets/web/default/js/flot/jquery.flot.pie.js create mode 100644 assets/web/default/js/flot/jquery.flot.resize.js create mode 100644 assets/web/default/js/flot/jquery.flot.tooltip.min.js create mode 100644 assets/web/default/js/jquery-1.10.2.js create mode 100644 assets/web/default/js/morris/chart-data-morris.js create mode 100644 assets/web/default/js/tablesorter/jquery.tablesorter.js create mode 100644 assets/web/default/js/tablesorter/tables.js create mode 100644 assets/web/default/tables.html create mode 100644 assets/web/default/typography.html create mode 100644 src/CoiniumServ/Net/Server/Web/BootStrapper.cs create mode 100644 src/CoiniumServ/Net/Server/Web/RootPathProvider.cs delete mode 100644 src/CoiniumServ/views/Home/Index.cshtml diff --git a/assets/web/default/blank-page.html b/assets/web/default/blank-page.html new file mode 100644 index 000000000..cba3c1bdd --- /dev/null +++ b/assets/web/default/blank-page.html @@ -0,0 +1,141 @@ + + + + + + + + + Blank Page - SB Admin + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/web/default/bootstrap-elements.html b/assets/web/default/bootstrap-elements.html new file mode 100644 index 000000000..da685d581 --- /dev/null +++ b/assets/web/default/bootstrap-elements.html @@ -0,0 +1,745 @@ + + + + + + + + + Bootstrap Elements - SB Admin + + + + + + + + + + + +
+ + + + +
+ +
+
+

Bootstrap Elements Built-In Bootstrap Elements

+ +
+ + Start Bootstrap recommends that you have an in-depth understanding of the Bootstrap framework before working with this template. Visit http://getbootstrap.com/ for complete documentation. +
+
+
+ +
+
+

Buttons

+
+
+ +
+
+ +

+ + + + + + + +

+ +

+ + + + + + + +

+ +

+

+ + + + +

+ +

+ + + + +

+ +
+ +
+ +

+ +

+ +

+

+ Left + Right + Middle +
+

+ +

+

+
+ + + + +
+
+ + + +
+
+ + +
+ + +
+
+
+

+ +

+

+ + + + +
+

+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+

Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.

+
+
+

Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit.

+
+ + +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+
+

Pagination

+
+ + + +
+
+
+

Pager

+
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+

Alerts

+
+
+ +

Warning!

+

Best check yo self, you're not looking too good. Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

+
+
+
+
+ +
+
+
+ + Oh snap! Change a few things up and try submitting again. +
+
+
+
+ + Well done! You successfully read this important alert message. +
+
+
+
+ + Heads up! This alert needs your attention, but it's not super important. +
+
+
+ +
+
+

Labels

+
+ Default + Primary + Success + Warning + Danger + Info +
+
+
+

Badges

+ +
+
+ +
+
+ + +

Basic

+
+
+
+
+
+ +

Contextual alternatives

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +

Striped

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +

Animated

+
+
+
+
+
+ +

Stacked

+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+

Jumbotron

+

This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.

+

Learn more

+
+
+
+
+ +
+
+

List groups

+
+
+ + + +
+
+

Panels

+
+
+ +
+
+
+
+ Basic panel +
+
+
+
Panel heading
+
+ Panel content +
+
+
+
+ Panel content +
+ +
+
+
+
+
+

Panel primary

+
+
+ Panel content +
+
+
+
+

Panel success

+
+
+ Panel content +
+
+
+
+

Panel warning

+
+
+ Panel content +
+
+
+
+
+
+

Panel danger

+
+
+ Panel content +
+
+
+
+

Panel info

+
+
+ Panel content +
+
+
+
+ +
+
+

Wells

+
+
+ +
+
+
+ Look, I'm in a well! +
+
+
+
+ Look, I'm in a small well! +
+
+
+
+ Look, I'm in a large well! +
+
+
+ +
+ +
+ + + + + + + \ No newline at end of file diff --git a/assets/web/default/bootstrap-grid.html b/assets/web/default/bootstrap-grid.html new file mode 100644 index 000000000..9709db82a --- /dev/null +++ b/assets/web/default/bootstrap-grid.html @@ -0,0 +1,400 @@ + + + + + + + + + Bootstrap Grid - SB Admin + + + + + + + + + + + +
+ + + + +
+ +
+
+

Bootstrap Grid Built-In Bootstrap Grid

+ +
+ + Be sure to visit Bootstrap's grid documentation for more information. +
+
+
+ +
+
+
+
+ .col-lg-12 +
+
+
+
+ +
+
+
+
+ .col-lg-6 +
+
+
+
+
+
+ .col-lg-6 +
+
+
+
+ +
+
+
+
+ .col-lg-4 +
+
+
+
+
+
+ .col-lg-4 +
+
+
+
+
+
+ .col-lg-4 +
+
+
+
+ +
+
+
+
+ .col-lg-3 +
+
+
+
+
+
+ .col-lg-3 +
+
+
+
+
+
+ .col-lg-3 +
+
+
+
+
+
+ .col-lg-3 +
+
+
+
+ +
+
+
+
+ .col-lg-2 +
+
+
+
+
+
+ .col-lg-2 +
+
+
+
+
+
+ .col-lg-2 +
+
+
+
+
+
+ .col-lg-2 +
+
+
+
+
+
+ .col-lg-2 +
+
+
+
+
+
+ .col-lg-2 +
+
+
+
+ +
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+
+
+ .col-lg-1 +
+
+
+
+ +
+
+
+
+ .col-lg-8 +
+
+
+
+
+
+ .col-lg-4 +
+
+
+
+ +
+
+
+
+ .col-lg-3 +
+
+
+
+
+
+ .col-lg-6 +
+
+
+
+
+
+ .col-lg-3 +
+
+
+
+ +
+ +
+ + + + + + + \ No newline at end of file diff --git a/assets/web/default/charts.html b/assets/web/default/charts.html new file mode 100644 index 000000000..4199f012b --- /dev/null +++ b/assets/web/default/charts.html @@ -0,0 +1,314 @@ + + + + + + + + + Charts - SB Admin + + + + + + + + + + + + + +
+ + + + +
+ +
+
+

Charts Display Your Data

+ +
+ + There are two options for charts: Flot charts and morris.js. Choose which one best suits your needs, and make sure to master the documentation to get the most out of these charts! +
+
+
+ +
+
+

Flot Charts

+
+
+

Line Graph Example with Tooltips

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

Pie Chart Example with Tooltips

+
+
+
+
+
+ +
+
+
+
+
+
+

Multiple Axes Line Graph Example with Tooltips and Raw Data

+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Moving Line Chart

+
+
+
+
+
+ +
+
+
+
+
+
+

Bar Graph with Tooltips

+
+
+
+
+
+ +
+
+
+
+ +
+
+

Additional Flot Chart Information

+

Full documentation for Flot can be found at http://www.flotcharts.org/. Flot has a lot of different options available, and they have a bunch of plugins as well that allow you to do neat things. Here we are using the tooltip plugin, the resize plugin, and the pie chart plugin, but there are many more to choose from. The documentation is a bit more advanced and requires a good deal of JavaScript knowledge in order to make the charts work for you.

+

NOTE: The charts are responsive, and the Flot charts are redrawn when the window resizes. The only one that needs a page refresh on a window resize is the pie chart. If you find a way to fix this, please let me know.

+
+
+ +
+
+

morris.js Charts

+
+
+

Area Line Graph Example with Tooltips

+
+
+
+
+
+
+
+ +
+
+
+
+

Donut Chart Example

+
+
+
+ +
+
+
+
+
+
+

Line Graph Example with Tooltips

+
+
+
+ +
+
+
+
+
+
+

Bar Graph Example

+
+
+
+ +
+
+
+
+ +
+
+

Additional morris.js Information

+

Full documentation for morris.js charts can be found at http://www.oesmith.co.uk/morris.js/. The chart options for morris.js are line & area charts, bar charts, and donut charts. The documentation is pretty straight forward, and you will want to look at it in order to get the most out of the charts.

+

NOTE: The charts are responsive, but they are drawn when the window loads. If you change the window size, for instance resizing your brownser window, you will need to refresh the page to redraw the chart responsively. According to morris.js, automatically redrawing charts on window resizing is being worked into their next big update. +

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + diff --git a/assets/web/default/css/bootstrap.css b/assets/web/default/css/bootstrap.css new file mode 100644 index 000000000..14cc1f48e --- /dev/null +++ b/assets/web/default/css/bootstrap.css @@ -0,0 +1,5831 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.0 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + margin: .67em 0; + font-size: 2em; +} +mark { + color: #000; + background: #ff0; +} +small { + font-size: 80%; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -.5em; +} +sub { + bottom: -.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + margin: 0; + font: inherit; + color: inherit; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + padding: .35em .625em .75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-spacing: 0; + border-collapse: collapse; +} +td, +th { + padding: 0; +} +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 62.5%; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333; + background-color: #fff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #428bca; + text-decoration: none; +} +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + display: inline-block; + max-width: 100%; + height: auto; + padding: 4px; + line-height: 1.428571429; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #999; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 200; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +cite { + font-style: normal; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-muted { + color: #999; +} +.text-primary { + color: #428bca; +} +a.text-primary:hover { + color: #3071a9; +} +.text-success { + color: #3c763d; +} +a.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #428bca; +} +a.bg-primary:hover { + background-color: #3071a9; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} +.list-inline > li:first-child { + padding-left: 0; +} +dl { + margin-top: 0; + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.428571429; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #eee; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.428571429; + color: #999; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + text-align: right; + border-right: 5px solid #eee; + border-left: 0; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +blockquote:before, +blockquote:after { + content: ""; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.428571429; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + white-space: nowrap; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #fff; + background-color: #333; + border-radius: 3px; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.row { + margin-right: -15px; + margin-left: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666666666666%; +} +.col-xs-10 { + width: 83.33333333333334%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666666666666%; +} +.col-xs-7 { + width: 58.333333333333336%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666666666667%; +} +.col-xs-4 { + width: 33.33333333333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.666666666666664%; +} +.col-xs-1 { + width: 8.333333333333332%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666666666666%; +} +.col-xs-pull-10 { + right: 83.33333333333334%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666666666666%; +} +.col-xs-pull-7 { + right: 58.333333333333336%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666666666667%; +} +.col-xs-pull-4 { + right: 33.33333333333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.666666666666664%; +} +.col-xs-pull-1 { + right: 8.333333333333332%; +} +.col-xs-pull-0 { + right: 0; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666666666666%; +} +.col-xs-push-10 { + left: 83.33333333333334%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666666666666%; +} +.col-xs-push-7 { + left: 58.333333333333336%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666666666667%; +} +.col-xs-push-4 { + left: 33.33333333333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.666666666666664%; +} +.col-xs-push-1 { + left: 8.333333333333332%; +} +.col-xs-push-0 { + left: 0; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} +.col-xs-offset-0 { + margin-left: 0; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} +table { + max-width: 100%; + background-color: transparent; +} +th { + text-align: left; +} +.table { + width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #ddd; +} +.table .table { + background-color: #fff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + display: table-cell; + float: none; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #ddd; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.428571429; + color: #555; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); +} +.form-control:-moz-placeholder { + color: #999; +} +.form-control::-moz-placeholder { + color: #999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999; +} +.form-control::-webkit-input-placeholder { + color: #999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eee; + opacity: 1; +} +textarea.form-control { + height: auto; +} +input[type="date"] { + line-height: 34px; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + display: block; + min-height: 20px; + padding-left: 20px; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + display: inline; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.input-lg { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-lg { + height: 46px; + line-height: 46px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 42.5px; +} +.has-feedback .form-control-feedback { + position: absolute; + top: 25px; + right: 0; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} +.has-error .form-control-feedback { + color: #a94442; +} +.form-control-static { + margin-bottom: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} +.form-horizontal .form-control-static { + padding-top: 7px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} +.form-horizontal .has-feedback .form-control-feedback { + top: 0; + right: 15px; +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.btn:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus { + color: #333; + text-decoration: none; +} +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333; + background-color: #ebebeb; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #fff; + border-color: #ccc; +} +.btn-default .badge { + color: #fff; + background-color: #333; +} +.btn-primary { + color: #fff; + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #fff; + background-color: #3276b1; + border-color: #285e8e; +} +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary .badge { + color: #428bca; + background-color: #fff; +} +.btn-success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #fff; + background-color: #47a447; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #fff; + background-color: #39b3d7; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ed9c28; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #fff; + background-color: #d2322d; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + color: #428bca; + cursor: pointer; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999; + text-decoration: none; +} +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-sm { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity .15s linear; + transition: opacity .15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height .35s ease; + transition: height .35s ease; +} +@font-face { + font-family: 'Glyphicons Halflings'; + + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + right: 0; + left: auto; +} +.dropdown-menu-left { + right: auto; + left: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999; +} +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + content: ""; + border-top: 0; + border-bottom: 4px solid; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } + .navbar-right .dropdown-menu-left { + right: auto; + left: 0; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-group > .btn + .dropdown-toggle { + padding-right: 8px; + padding-left: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-right: 0; + padding-left: 0; +} +.input-group .form-control { + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 46px; + line-height: 46px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #555; + text-align: center; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eee; + border-color: #428bca; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eee #eee #ddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #428bca; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + max-height: 340px; + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + -webkit-overflow-scrolling: touch; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + height: 20px; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 8px; + margin-right: 15px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: none; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 7.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } + .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} +.navbar-form { + padding: 10px 15px; + margin-top: 8px; + margin-right: -15px; + margin-bottom: 8px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-form.navbar-right:last-child { + margin-right: -15px; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} +.navbar-btn.btn-sm { + margin-top: 10px; + margin-bottom: 10px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 15px; + margin-bottom: 15px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; + } + .navbar-text.navbar-right:last-child { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777; +} +.navbar-default .navbar-nav > li > a { + color: #777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #ddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555; + background-color: #e7e7e7; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #ccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777; +} +.navbar-default .navbar-link:hover { + color: #333; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #999; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #999; +} +.navbar-inverse .navbar-nav > li > a { + color: #999; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #fff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #fff; + background-color: #080808; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #999; +} +.navbar-inverse .navbar-link:hover { + color: #fff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + padding: 0 5px; + color: #ccc; + content: "/\00a0"; +} +.breadcrumb > .active { + color: #999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.428571429; + color: #428bca; + text-decoration: none; + background-color: #fff; + border: 1px solid #ddd; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #2a6496; + background-color: #eee; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999; + cursor: not-allowed; + background-color: #fff; + border-color: #ddd; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +.label[href]:hover, +.label[href]:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #999; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} +.label-primary { + background-color: #428bca; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #999; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #fff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #eee; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.container .jumbotron { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.428571429; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + display: block; + max-width: 100%; + height: auto; + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} +.thumbnail .caption { + padding: 9px; + color: #333; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable { + padding-right: 35px; +} +.alert-dismissable .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); +} +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + -webkit-transition: width .6s ease; + transition: width .6s ease; +} +.progress-striped .progress-bar { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + padding-left: 0; + margin-bottom: 20px; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid #ddd; +} +.list-group-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555; +} +a.list-group-item .list-group-item-heading { + color: #333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #fff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05); +} +.panel-body { + padding: 15px; +} +.panel > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group .list-group-item:first-child { + border-top: 0; +} +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} +.panel > .list-group:first-child .list-group-item:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #ddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th, +.panel > .table-bordered > tfoot > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:first-child > th, +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > tfoot > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:first-child > td { + border-top: 0; +} +.panel > .table-bordered > thead > tr:last-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-bordered > thead > tr:last-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; +} +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + overflow: hidden; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #ddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #ddd; +} +.panel-default { + border-color: #ddd; +} +.panel-default > .panel-heading { + color: #333; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ddd; +} +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ddd; +} +.panel-primary { + border-color: #428bca; +} +.panel-primary > .panel-heading { + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, .15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + border: 0; +} +.modal-open { + overflow: hidden; +} +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + display: none; + overflow: auto; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + transition: transform .3s ease-out; + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); + box-shadow: 0 3px 9px rgba(0, 0, 0, .5); +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; +} +.modal-backdrop.fade { + filter: alpha(opacity=0); + opacity: 0; +} +.modal-backdrop.in { + filter: alpha(opacity=50); + opacity: .5; +} +.modal-header { + min-height: 16.428571429px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.428571429; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + padding: 19px 20px 20px; + margin-top: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + } + .modal-sm { + width: 300px; + } + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 12px; + line-height: 1.4; + visibility: visible; + filter: alpha(opacity=0); + opacity: 0; +} +.tooltip.in { + filter: alpha(opacity=90); + opacity: .9; +} +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + text-decoration: none; + background-color: #000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: 11px; +} +.popover .arrow:after { + content: ""; + border-width: 10px; +} +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, .25); + border-bottom-width: 0; +} +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + content: " "; + border-top-color: #fff; + border-bottom-width: 0; +} +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, .25); + border-left-width: 0; +} +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + content: " "; + border-right-color: #fff; + border-left-width: 0; +} +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, .25); +} +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + content: " "; + border-top-width: 0; + border-bottom-color: #fff; +} +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, .25); +} +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + content: " "; + border-right-width: 0; + border-left-color: #fff; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: .6s ease-in-out left; + transition: .6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); + filter: alpha(opacity=50); + opacity: .5; +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .5) 0%), color-stop(rgba(0, 0, 0, .0001) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .0001) 0%), color-stop(rgba(0, 0, 0, .5) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: none; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); + border: 1px solid #fff; + border-radius: 10px; +} +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #fff; +} +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-right: auto; + margin-left: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +.visible-sm, +tr.visible-sm, +th.visible-sm, +td.visible-sm { + display: none !important; +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +.visible-md, +tr.visible-md, +th.visible-md, +td.visible-md { + display: none !important; +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +.visible-lg, +tr.visible-lg, +th.visible-lg, +td.visible-lg { + display: none !important; +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} +.visible-print, +tr.visible-print, +th.visible-print, +td.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +@media print { + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/assets/web/default/css/bootstrap.min.css b/assets/web/default/css/bootstrap.min.css new file mode 100644 index 000000000..381834ec8 --- /dev/null +++ b/assets/web/default/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.428571429;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=date]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.428571429;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.428571429;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group .list-group-item:first-child{border-top:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel>.list-group:first-child .list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tfoot>tr:first-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tfoot>tr:first-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>td{border-top:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.428571429px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top .arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right .arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom .arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left .arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5) 0),color-stop(rgba(0,0,0,.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001) 0),color-stop(rgba(0,0,0,.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}@media print{.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/assets/web/default/css/sb-admin.css b/assets/web/default/css/sb-admin.css new file mode 100644 index 000000000..57757cd33 --- /dev/null +++ b/assets/web/default/css/sb-admin.css @@ -0,0 +1,164 @@ +/* +Author: Start Bootstrap - http://startbootstrap.com +'SB Admin' HTML Template by Start Bootstrap + +All Start Bootstrap themes are licensed under Apache 2.0. +For more info and more free Bootstrap 3 HTML themes, visit http://startbootstrap.com! +*/ + +/* ATTN: This is mobile first CSS - to update 786px and up screen width use the media query near the bottom of the document! */ + +/* Global Styles */ + +body { + margin-top: 50px; +} + +#wrapper { + padding-left: 0; +} + +#page-wrapper { + width: 100%; + padding: 5px 15px; +} + +/* Nav Messages */ + +.messages-dropdown .dropdown-menu .message-preview .avatar, +.messages-dropdown .dropdown-menu .message-preview .name, +.messages-dropdown .dropdown-menu .message-preview .message, +.messages-dropdown .dropdown-menu .message-preview .time { + display: block; +} + +.messages-dropdown .dropdown-menu .message-preview .avatar { + float: left; + margin-right: 15px; +} + +.messages-dropdown .dropdown-menu .message-preview .name { + font-weight: bold; +} + +.messages-dropdown .dropdown-menu .message-preview .message { + font-size: 12px; +} + +.messages-dropdown .dropdown-menu .message-preview .time { + font-size: 12px; +} + + +/* Nav Announcements */ + +.announcement-heading { + font-size: 50px; + margin: 0; +} + +.announcement-text { + margin: 0; +} + +/* Table Headers */ + +table.tablesorter thead { + cursor: pointer; +} + +table.tablesorter thead tr th:hover { + background-color: #f5f5f5; +} + +/* Flot Chart Containers */ + +.flot-chart { + display: block; + height: 400px; +} + +.flot-chart-content { + width: 100%; + height: 100%; +} + +/* Edit Below to Customize Widths > 768px */ +@media (min-width:768px) { + + /* Wrappers */ + + #wrapper { + padding-left: 225px; + } + + #page-wrapper { + padding: 15px 25px; + } + + /* Side Nav */ + + .side-nav { + margin-left: -225px; + left: 225px; + width: 225px; + position: fixed; + top: 50px; + height: 100%; + border-radius: 0; + border: none; + background-color: #222222; + overflow-y: auto; + } + + /* Bootstrap Default Overrides - Customized Dropdowns for the Side Nav */ + + .side-nav>li.dropdown>ul.dropdown-menu { + position: relative; + min-width: 225px; + margin: 0; + padding: 0; + border: none; + border-radius: 0; + background-color: transparent; + box-shadow: none; + -webkit-box-shadow: none; + } + + .side-nav>li.dropdown>ul.dropdown-menu>li>a { + color: #999999; + padding: 15px 15px 15px 25px; + } + + .side-nav>li.dropdown>ul.dropdown-menu>li>a:hover, + .side-nav>li.dropdown>ul.dropdown-menu>li>a.active, + .side-nav>li.dropdown>ul.dropdown-menu>li>a:focus { + color: #fff; + background-color: #080808; + } + + .side-nav>li>a { + width: 225px; + } + + .navbar-inverse .navbar-nav>li>a:hover, + .navbar-inverse .navbar-nav>li>a:focus { + background-color: #080808; + } + + /* Nav Messages */ + + .messages-dropdown .dropdown-menu { + min-width: 300px; + } + + .messages-dropdown .dropdown-menu li a { + white-space: normal; + } + + .navbar-collapse { + padding-left: 15px !important; + padding-right: 15px !important; + } + +} diff --git a/assets/web/default/font-awesome/css/font-awesome.css b/assets/web/default/font-awesome/css/font-awesome.css new file mode 100644 index 000000000..048cff973 --- /dev/null +++ b/assets/web/default/font-awesome/css/font-awesome.css @@ -0,0 +1,1338 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.0.3'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.3333333333333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.2857142857142858em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.142857142857143em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + top: 0.14285714285714285em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.8571428571428572em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-asc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-desc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-reply-all:before { + content: "\f122"; +} +.fa-mail-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} diff --git a/assets/web/default/font-awesome/css/font-awesome.min.css b/assets/web/default/font-awesome/css/font-awesome.min.css new file mode 100644 index 000000000..449d6ac55 --- /dev/null +++ b/assets/web/default/font-awesome/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} \ No newline at end of file diff --git a/assets/web/default/font-awesome/fonts/FontAwesome.otf b/assets/web/default/font-awesome/fonts/FontAwesome.otf new file mode 100644 index 0000000000000000000000000000000000000000..8b0f54e47e1d356dcf1496942a50e228e0f1ee14 GIT binary patch literal 62856 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 oMn#JeYGU{pbzL1U=O}QIp<2eKYy*8l(j literal 0 HcmV?d00001 diff --git a/assets/web/default/font-awesome/fonts/fontawesome-webfont.eot b/assets/web/default/font-awesome/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..7c79c6a6bc9a128a2a8eaffbe49a4338625fdbc2 GIT binary patch literal 38205 zcmZ^IWlSYp%;vqo1upLH?(XjH?(XhB4DRmk?(Q(SyX)W#I)m#B?7N%&@gNzPg3A9y|F{1i{C~vS%_!vmy8pvq0i*!V z04IP4KosB&umrgOcXRyD0su$=wg0R&z!TsAFa@~%hfn~t{zKgUi?RJbIV1oM026@a zKV<`u{HH7cRsj2daa8}Gnk4^EMF2odUHbodF(eRY6Og71NK*#{I$+FQ#4RkN>Xu5t zDV|CZ0erHH%7mJ7f9C(hMgfc`(&`gnuuiqhEZtN@Gm6qm9jtBTu`bUstuVt`VE1U^ zQeRP-GNx@G1O+8HnNjpn78T|1$sHu=pO{n+?Hbd%?rXh*b{x)ZZ9Ey*heliTM$ph9 zeSOvxJI7sn2z_VOStQwpj}H7Y+@M&VY|#ngtbu=`HY)^$pT2Bh?F%Qz)A!hd^bxco z(ph?3k$*g}cpvrc9fcXhjj;5WPot~Co6>e-hv7*v=?ht4ZzfafOKSl*nvanjGNp%5 zqVHEAb0A25 ztDEMbuMI$uR5*rQ;Ex2f;9~>x3rZo2m^kwR6UQRPZz@Czx8NQJM6qF(2xu!inpqCE zp&p-KF}@yM;D2@511uFKw|p7`rR5E%Q=P-zPeXA1Ktriy6is`S1oMudP6;lGGo*>+ z8#MeQ*S6fE;37Z&V&V2oyeT_l1gp@&a)ah*E|M@ELRv^E70jhArQEOCVR(XrnfK5q zp=6hd;d{^XAPeI<#-L-CBvNu5_(Jtd*&!2*tS%|-yzds5)A{0f(w};Y^KBe@AdynU zQL37Co!%Eq%0_)~bcR`#k94J}qgc4SSR@Ul!8_*tW{Z3Z>U6}ivNUHWn8P$)EbfkT z@k>R%?c7o_o;AP3>Pi=p)K`@mYLKBdm&H(%0ai{ls$|XAptE5F3tx6U{?(i@T>GA3 z^_!F+A*NF}bxUB`5ssZLyE(_w@^Dbsgs-6_CGq92Gx|oi!cA-HhDACy{4K)xs|&hF z>LTWj1(w}4LTGz@)0q87y$|wm>pEPvgpR{F10WY$v~2DYt@t>2Z4;zPN_He3aPb@z ziE0^tt>sf2&yu8qR?@PaDB@HEgBHaU>ZnpXEB^D(;d~K@`H3P(?)J@Vn z@CfT^4qS#V(v@+Tim_UUz_Xd-$p=1fq8#h)@{UE|bVYBR`b>ehNCJ;D5bU7L26}ay zF9bjM0OWm1Ao>6*BK&HtwoOBWueI2fo{G7Y(GD|!_MzfV9ur=<&-+oRNRfybM70FE ziI3L556BV<%TDstB!_UPon6HAw*b{&kueNsC+=#&J+)243^;t8PopRU4eb)@)UjTC z%|J@gDtLqz=z5jdArpDBF8$;L=m(uEBXxr?n&v3{9kTU@&#yiW%YPB)RIU}%aSn`6 z$@EM;F;6}0Oe=&L&gfL&?rfC)Kx@IRPdd3jy;|W(cPJI&mJ)b22%#Jh)6+MBXi}{R zv^IAae*Q9Ff|}Y>L3KPUWC=0h^@i;U8!M>_cS{w^1mL3n#)V zzLDJBVg}IArNIql9*}a_j5k%x5~ySF{kx7~rG&ilzkAtDE&P%=41?qbzUVW>mJ;wI zG5?8dPhnkm~3cU8v`qiyh&L1E1^VPh=!%X+Uo>1c96Q;$2#!T1Ajyyr?xG>dq*93%MpnA#<7B$B#7=HPXzf=n$eqoJt`+9|FBhvLb+Wa z4m8GHx>=pcMvH?ROyEX%6zNvTMAD1qZ;AsG_0HNgMRs*xMPr|7Ah1x>6n>WIU!Rbx zAYDQVirff^+o%FmVd0B_;=cS=Pb5fBM{XhmuA5{$CX^gd>K>tNd;Lue-*M39)i8u$ zvloM|Alu~~`DW*t3*x9MP(pP*a$yx_Za4IsuM$&kOP znIjBTyD&_q?33=(F8vwuz4}#@VC5b=BR^1qta#WB)w-2XWN|LD`9AlpS}&US6%rj_ zR)6|i3w@-sbdLY*wIZzMyd+h(eZ#``O&@Bi9YU38yi!ozx7p}(2j2!@LD^z z=Hq^=#||B`(#WvR3+)d*sr80BN|Ky6Jt`#Qjwg11 zG(HT7qi~b5*RMzyF*&HHxNqS2WkJBe>I_J0^)kQLmlNmelxf#>?%GJIl_lQcfQhMcCHR zpjs9>tRLYo;~E98pm1*t7SyL+0x}cVhI- z>CT#lG-N@6SO=jawi;8;(_?PT(9ie_1fvY;Jk2=I_w!E z!Y^R`3t#8*m?I|Ud>4es$FXWl2HUO$%~7*kxDsbkG4Q&Gd8^ez857WVF=K{GnKur# zV9TxY3P)fpjfiFra;dkVwPR>95jhb+kD|;*iA+l2Oqxik?B99KpfozgmzxwxSylWb zg)%DWt{5oQP7NgLljJDmH3}IPvoJ+PtxxycCnYT&69cDw>&}In&F09a^uTC0WeDa( zEL8Nxmcz5q4LfwxV%sU0hvQRh+z2C;vEp+E2B3SEF-f|#6-mSx*mK)c0$fDM7kPz8 z?`_-7=l0}C#Zht53SIt`Y4vfg!7WuL-bBA!&v`K(@{u2PXiuNAgvs0jjDCI?mYq<; z@mZQ{ZtFKytujvz#Oopf6!|7kA*r+I0ob}^W8~7^gRdfY+9S_F(zSHB!HwR(Y{(zI z-ibb7)VpopINsALOXkwt^<)cm?aV--LZ?;j*$ezC^n=3iBOB=!JGQ8>rYy~O6p6Wf zY~=*?XKaLp<&Qo6W*RX!e1xBb&9_ct3YV5z_iE#2JViml)_rvMZsp2wS_7iXxJvew%gf;mkQY%&1+`Gi*e*2*B>O@GO()_#LH6z(C{)jcjQ~2H z)FMk)q>Sp8;Wk^A>(}J1pqse|RN~jF+6{lt1bbson9)wiI+YmW7Np-sVNxH|T&AA! zBI7Xjs!)N);7)_r(h`BeuV_SgPbsHm*uRBUVktIpforWVBjVz-avd%1F&mvltBvF? zfNt|pMlEQ@*r7Zr@j1anSI{yWHPQ$!*)ikAEYb7Vw$0#qFN1VR2OI)KFA*m1z+qk`Qy*pW{`d{N@Nn-0){$edMYF#Lln)aUBU%x zpbeNn0tProp-?4C-fLh&EA7jUs3uXR>mE(WMi;sRvb?M`LI&#S!`abZ>*?LAUzBEv z;)Sf?7eJk&T&RX^Zw74e7XPe{@Ple&hu)^v@rLAWVA)heayJ-&0YhI9ste5a#M@pF z()}*Gekga)6xf{ah%_;p~T z+j{vjFu{}Ns1UWUeQeT)f!3d>d;a(X|5DX!wu&XZ9eRYc!uzZQ6r{8oI2ArhVA%G? zHyb=YT19dD63$YpPa%n8ND7_Z+Jr5NQ>dEfM3VIVW%dBxo*UEF9g+=Z` z3D|>we0$`qMMT%+#&?bKsMuGo8^3qSNM2?u$wL0_nc8UkL68&{gP*hNYcXSBRb%cB?pVTSk*kfIOciI=QQrZ1JZwiYyN9#?{qgO7Q!32 zgX+p(BAS0u%GTgED?@bG%^)gzHm;AuU5;tPf-`#gsCDOP-I(3&c+iFWwqT)~_?WRs z0IY9YJeXjU!Nm%OqKuR|k8Mk;_D%MBlM=Kp?lshdEZwvMKMFR{C5D4la_j_TyeaQ~ zdSvtTk@H$=sJHwFks8_|tO%{fojwPmtKj`Q1zQ>HauCfT53_ze)l zTG-M87<=xxy| zDdO)&IMC;(lZM18FVB?v=R|Rw@)!k9^%zF2N_oFCDrd~Y_ws}mz~dKX%-kV41cU}} zQ~qUWCv|=_P_%uplL?G&6J|d>Wk_c3gKFN@F)jA%#ii3cI4UcpfE7lu4V5L?>N`$! zk)h#WZ(15(Finwk1ceGKs3lJx3!EAjUatNdO{TJTR0f@n1S1an1=2=8TU1Ml9{F^EsNZr(g5=z%U97>sgM zril2uR`W@#-Wt5t4Bn5Yz{|T;kcFdy!DE^@u598ty3OaS54s~Hb)tkY7zz6}Z_G@k z&5BO9g?I?$$5+Ud9=`SC0y?M!A2=yUZ(a`GKLJ%Ec-W*#J(z zal~$;zmv0W6y8{yxu3p}rN~roYmS7RdYm}J=#D391J6{cb%T#4)$PQp>Q8-uV-c7&nmY~uoMX$~7PY5dy=uY?@pM1GFC@wI|v|Qrw-=$Sf4{wk5&4_=sF>gnp z*P({nvArrS(l#^E8wXB^60 zjj8eIprA~2PY#gR{Q)B%m?ITG#X@32;je#;)B6g}9@Lo{@=*J&tl^#@&d70hV zqvdqNZSrNvD`pj@qo;n?u+SB3dYiht9J6DcMtae}KQt|F%fb$wYUmT-k7u?}UG8yl z)Fn}2q?zp*uBGX@u7bNWI76Nt7RMm)!sbX2Hz;8bW%E3gv$UWV_F%`6i4Cp7qpcfJ zDggycgt){-@q3Xf(|fbVc=5I>92_~)!?urM`!cFbfKnO~Et7=kL&!+Ci3&hjX#21i zKFjJr(e$x^2(e2@eFplc?uR%6Bo=N#WU7i-P3r}$20vvC5=maef9!lE`8^MhF~c2C zpe=9m1d%QT;koR$`WI=uIaOv;*&wjp4F`WIs*eFc#p^<+tI9=knDS`Y5Hk`w5F|r_ z4?}k75;f>g@CXGS58Xp^u#Y!M9~*|c8HAWY>=({SS*)Ox9&@4z<~uD-@;AQcA~6`) znp0N7D_`!W=)@bxJMyWUz#U*pQ{cN0!i%$t+J2M;9RU6#E3;dfkcw9t9*NT*lcI1S zbVTz`ZG|Ev(sHZt5`F5KoNfAh|<`q^eO8loN$OjJIl2#PXtQA)~wGv&f^-Al_TjJ58Pa+M5kmz-NhD0 z>XD-aM~}AOprfr!hqfUw;f(eLw$1NUyo!L*Yc&h>8ZR3PcRsr zpYsNmhGRf-y508v%`$L8SaCUt#Le-|`Pk(FB`->6b$q*QiU>;5;ZO^-`(W`&3^SQ( zkqH=nN4>YBjf+!y{$c`$oM{CvIf05nmqxq36o*w@|2|2@sQgRAPEnrIYoiG6NcTuA zi20@ezU2fusTA{G1B8BuLkp+2=rSrPB@K@xP~VI_i<*3sk11&W&=Hk2t3r5-zDpV6 z#dQ?z6_e_cU_h5fCw*a;JR+eAljWPV_Vci#Oh=B8idNeaXLW~$1j{iF5rJu`*b1F% zh*c0OefvNb3TPm=QtqJnS&kg0IhUac=EH`4_JOdO2>dyQq`rdoW9z5}NrSU|aEVe@ z!0U9?EzH~X@v58!f-M3vXUndSwO;G6qI#e7_sY;FZ`~pD{4qHs6Dq@w0jvTvuB-~N z8+2+lf)Uo1oXzp{W-SR*n2#9tSW9am$`FVl_l@Qnkpcu$B>@qN%5&yQ1Sw+BnKemL zRfpwW%f=D?SAe7)%1{97X=s}IQA|YiL6S9K$N>{4hvtXo3ypJsGLwUJwmpXvvPb`i zPkFFE0I#G&1qC%RlILTgZcE(q9+YC<%6We|>5Vf%t>CBZCH(2j~p;r3-+a*1_ko zbDXT3(;;8uXXy6+1Dk)LQsHjW_wQy>RZ=1Ndb*^$3dPZD;?iXgYVT4mXTRmuV@H@d z+u^8>gmn-Ztx&?PG9OW)by86jFo4ZHASsxOGZ=Hk?0FLtV$3cds2baN$3E4A#Cl31p{Ux18pUuLY!{ z4`cJ3-aWj(HRT`W2eeMg9XCNOM0LZ3*_F@?(ptb*MXl6wMq(2O8`(E*p^_64!N@mh zN}T6Iy|eL?DEPiQ3hfe{h(y80^dA*EwBR9&WeP}~^-1)Q!~NsxR;~NduFokawu-+X zBk?;o@e$fU1Ti{AzikyOdXzd22eX9kBS`pQkdEjn{K^EqmgG`{$d@+XqZ9O6SY_gu zVF`tjkVmDrsCq}^dc~hYd`tGM!y0j&M8QMw%5XSu{5J^=s>#z|3VD@{Gx!}uptysk zT-+YXFP4p2TEnMWl(`?Zi-2;tKPjKmJ|@->q=`h8(^8lcI;rt9Vh4rL1X0bU&<>to zQ6;sD%}9Rgx_URn9|V~;>{Y$#W1I~`l^ZP`I}3}K2ERDD$UwHe2|PEk(Z?gSX5)<+ zdUVERMQ8fU8wU?*Omoc^6-f@ZzMlOCCI4JZ6pFU7w%(&U3w2ffD{wNRM)kBsFp1D~ z$hptcdV!tgO9it8id@_=mRh|S1`n@*{P87e8yPYawPY3Ej4zfgPmjpJt2xkQ)}yWE z8!BwmbeSH$?$nPCXocC}BuHU>8G_#JzpON-o8dHDrRT}GC=zG4n-7RYj5gxvKZ=Te zSOn$?;)Y`Oh+*oP4+?!cN|V?jhT*7k+1UwXf3vmw_`8RK38Xw0v`a;iv1{x~`@aLM%hM*qtStGVzXCYf`q* z_(Exk=MfFjEUpAv%V>G@&>gR|FJndsyiouJU(}m+h$7w~k3( zW%y9pi}!Z98ob(Mvpx~OfountwA-jxjjOYhbyE7{fri?p4n@6qdH^jr7&38fVczz`O5|rS zdy!`@=)KgM`o`*xTGX6Xu3ZvA3j2C&@tIF-vj3*NrQ~{bnX;X!<-Ae3z#`X$V(A?- zR>Eba34!GF`jUademjbn#TO6DETFmI1 zzS4Ag!l8Mt{T_^WuF)6(;xNHm4}e?OJGCJrNUFcL`Kh&jmc&pBdHbLT;X{(%Yck+$ z9rjdgp4HO5J=y1e6o0fXPkuh0x`e&vK^jbN zLp|T>34R?^3!C<1=U?}@-t=y2v*M`L27Wk8BFOxfx|1;Xni@||$FAh)b)?sBW> zzw>aD<;V80(-5HXqbXyvg-F(qA6|AbNFJ@SK>r2 z1KK76v~3*m5M?RO@~rZr4@<>T$Pxjuw=^e(_#E?V8&W8b5hz8G9Og?S%wxe24~VR& z0*ZpRTVmJdRbj=qb<5uLm(abvLXYTU9@-jw)?ms&mfc8AE!QY0D)J>g-lmy@O#5rY z6WLsH{weaGczE8jONV{}7m$23_L)sEBHTLA?Zbb6s1(3*q~4x|K72BGM_9-U=s9sU39y!~V5p@k##Z1v$ zRm8R`n7%GrkuQ9-DMesZFZqp1B@nB$^Rq%jm}XzRNYPx9EK!;LbE>VkX}0H7VYmtx zJjuxDl_{Gm<0co4N93{5g1C}PR|$ebo?XxyrGGPoPNS1T35K!QkOYXJjNv~{hQ<}) zj=PwUzrPmNOe$M3S>%bIQ{zQ?gB@@uBh3V44xG940Al0GE|aM6Jr(w5h1=03lZIFbBq;fVp3GD+(ARJ!+=|3t4d~)LXIZ2?0`BfXcHj8 zbFHKWn9noh6O;9%f2%6a{o=6@ySg)Fj7Dl80r{ry(Q=;~OrOv@ysCr@xCg4Q?h) z0>WslwOatjzulyT&7q=aiqW`VEU)869Tu$`L`7jXD3k3&LeBAPXqa?S`Pd|7 z2qFA79}#)cd|QZvZPO?h+Y&M#*`{8bO5oYngy#14(vLt|k0Chlj3L@1ZEP_ANPmHY|$QXQ!wD`4GueT7t zb9DaP`^6}`7+hfI+Lt3byh=*|2RmW|5RYL%|k;X#f~6nsc z*CEiAl#o!);6?bZ&&7Cuw=)?`YsI9rCORFy;ceZau=(}DK+fzi?8WFD6_MBMG$ml= zMsh-4ss&nJ$hgT~NSX41@Jwctel6t^3f!aS7D~w?`X92Uy{}4vADR1Y?ObuRR)4U} z2pv1}O4qjvl5YamQNHtoGN&HSZttO^zz9Oa6hS-=n2);DK{SzE6Q+vde1;^FCjSC9$*dy_*- zJ%hTbBmFU~CdErX%Nyeb$#OsI&ESCeA;@k@I4(q&7^1U1`s(G-VP}*LfJS{r7`{#t z3XBp#j3T)A zE{aoA15z}9lo-8(YRQ(SblP(l(>v_To=WdGwoOA(@uxpNPV2il0IpNJ2f3e-`Bpo!hL?RGM5E3eh8=8p>5^l_lXR9EPYY1}o z(k*0k1kU9Jyl--}Xw&XwA1P8^Q?cdv!cZY&l&Kq>B9GCGmdj4wHT^9dwMXYPap)$` zHcW`T%JL;fA%H>*c_mB?l#JLN?qHDW%PHjlUn{q>GpoUxp}-?hslNMUVKQVajYo`7 z>$&QaAbR9@gn)v*X_q1S^FTc3n^;^>(C45_gJ;x8ksNA!J8?Eww{X(y5t1#x)f`Qv z$afQ#`DUDiAP+HE#XzFQfSdoe-ssF`yXbms&A6+g4ZQu2BGnb5t5;(%?va?q$&kRJ6O8P9QtkTz$f0HLozGu3sL1T)XQ$jv*TKZZcy0*t| zK_TQs!%2>%4P>HGk!Wh`(xKdSBv*e;=wIYw7-Vd3f_575 z(1=MApsGiLJ4hjLR@)szko>7!=Mo)iqa96vMJ&dRf?a3#D;$evQ z{_YY+Q+@rn5PCc^9*jnFAMTfUSH-g22#!1STP2Pao1A(Ln%MXc8bY?jv~j`xipY2wT{IOb13X&AJk-5nTR+wl5td2i1=+j94+tN z#ltppQ4jMkmI!9MfaNY_6h(w`qsE!^;@090RmQ!EZH8N8Qs0vKiosb!dcr~y0z;3Y zc?m2$yi;?v#SgG}?w`?N$lDPxJUGnrqzyF6ECSA6iHE zMmXjfI#M|SwM2gyozz_z3C})%JT?s!dVF)l`84z(f|d!j{UQ}Ap@rBDEw3W{Itg{I zNJZsRdQPFi!zloCuI^&>(+Blj{~CtNs_W>xFkZX125*_wJ98t$i=ehjc`5@(yd(2u zT?>W>QqvI(U(%#Yz#1J9RBWcyAngI(;j%jXs@elcsgk zjas-ld1lL{O~fH~9q|_tC9}!DV`;gM=*! z8ip;mpc5sz9uI7RwZ8;>dJ+ele$aWeoXuWdAdG)CWRFuFEcP@LxmdwxSkc?z&}UJ_ z08WXvLj!wjn}~#TCX9NPIc`2z*W@bg%&xvOIewG`y0STb1mq~gp%uS^6(Q2#as80L z|18VSW315517}JcsqYkA`{6di;aW;2wkA=R*}KLiI|h=(ZGMB;EvE)S-hI2->&k0% z9XqG;&yK?V5qPfiI~0EURzMh8%w+%yGtpQbwTJUzWxcJ04&k#-5q-L>x4-B58gbL6 z2xm7dvGamFUVE4Zr@ae^f-=YsOjlm-GtAO}f{z+x7G{VW%aDvWBS9C{t6kOzj6H0^ z8YEmZmqmb$bHtEg+s8(GP#b=%AwIf3^lBpJg*Iv)ludv@gk@!u2{OHFA6|f=Fq7aj zD+OB~lm_FIcUcWY;}m@2*m(lKDEH|8!o1JKb|~q19`#wLQ_GD~ON#)q2!G}Hvt*)$ zd9t^xsn0=5lknsVSWEoU0229mEB7LcH>W7Vgsl%_@8?~uWwUD} z`XxhMRw~@(gYFi7+syt*GUAJxp0gKYG=_J&X?gwDFQyc*lF^iqR$g!<7wKhv-j6q& zzvr-n4l-w3hE0T=>}pxf__W3O`L&E&t$3^wrU9$^^ zTq~O8NYqYbldSWw*?>enK`TBbRn4&WcxtJ4QS?lHx}AtuYG_I?@`rj4X*rCV_~hukuD?XojV7i&{J2ZIr-*=BAMJ&k0JU9NIq# zkz0mMp78F9fe^?!Lg>!&0Zv9yf1mgsQlc6Q2-;;B1cw%=UqR+R=4DvR@&Cl2mBVKp z^$`k`%+4)*RPDpZ+$`m!LPH4&7pOZJ^plAKLhYLIT;iCK$q`45h2sKPP+o4cvJ{4+ zpZ%hK0QCWZEa(A+(-JPhPI>g+A@NBZ4C1@Z-ovz)*y?$kP0pSY@G|23zIIL@AFT2F zs-71oJ&Y}5MHOWGq@sArAoRIn$v&m}RBSsfUX8-fT)OITeMh~nx83g&vx-Oqcgs|* z0bOZp(4vsA!q{KcO(H5w3TQmzrO>)0VYDJ+$~Uf)iS6H$2*$^fsf}xz&Yd&Y5X0HZ zjHgQtaD};It7$bx3Z?b+Fq}>o!)(VO$Jw!?$W@^;heX|Rh=zOW3}!StFr>yb+lI=g zJcd3Yp$`6a*px@(a0;3x=(&u1`w?jX71o9Wt9FhHFEp(_D{=3x62uA}6M*ayf6r`9 z{auu7q^{SrEDhaj2Rnth^rvap#Bh}zQhGPu7Cg6vIMx20KW7#nSo9ih-fDL||8rD| z?F30se51-f=q|`|T*15_ITLh-woarjY*hr4YRGl)Q{BK8@AEZqf4Nti}!Cu+IxrT8t+nm2+GO*-^Y=+7-}W$WHpXp&=F_>|8~SXJ;k>(5GYwS}>~9;4YWl$R5|{36(|VO1 zwA-mm_p+urSKUi)o32KYVnVxTZ^R6m7W2CBzih2-%sCYD18CZgOx?(EU;#>TVzC z00(zo?At;%HQ60Bfd^w)H!PbA>p26=*O9x30bYiwULWM8Z1)w>k0~~hV*-x2hl`^5 zwvGQLmgWW69OCf}RVH|!GS^Kqj3uFc*8R z>e>_(uv`W0+l#JF-(pIhARC;Vf_Ng2GxaJ;u7u6$exj3mrNpQ&j8R5-_%w#@_dyFn zvfSFh;%61eB05sSi z`Yhwg!&_DQtF z@0MJfCj_nYMS;n0llhGVkt;VYD^)vdca2fi&Jxmb>Q(!TcrtN+d|{4d!pqNB58zvq zN6-gHE(cK#CVr}E+uMbADdD5Fx1CzLaF1G$h-i^8M~qM+U23HtrBU;fPGThCE3r#% zopji+n%!Bnw33WI6yuFBU6F8W<0iVBzZHiZWi_U8T>yt@>h4K-BC1D$QCEsYhW~%%K(pj127tbyQhk7Ay!gYzjdO6Jt%k64wTo!kNfR0(2(dmneO zNT(;B$nIq^p)NRYG&JB=)I$JLR%< zzmjY5$0?7q491IWEL@6lbW(tFH3cm-iZR96WL+7riuoI&%Wvc%f~Rk&UVc2OqyLh0 zt)zq%Ry*TI#p1L$g8ypa{k};(6X(P$bCI95$H>}a^Py)5qYzY!9`U4vuN1P2rcC?$ zlVNL5_VeCzjsC-y)gptp;v=bE95bAGZY=oqD|OdI`#wjEs&x1K_?Vh-aSb&0BW~pF zs_jI6Q42NGbW9u1-kcK!^Cb(GHYHzs2!5ZWm;*f(d>Rf96ldZ=5^gw|n50nHT?n#+ zm;B|@@%4;pV=36ej{7<&-t{k{6hYExI-_M{D1Igphg@gvS5->f7_GdMA|ZD`{{(7& znEZjFK$xuM77w{$+D~*8T*P3WT1s#b5Q4u3&1k}6%e}2$Kk#&_wV}x|e-b-#^-6Fz zYTo-I_g zT!2Be5zcJp=#oOI`tRcwDTDphmGbYOy+Sz4xg5n@({V^nWI{v3uHv~MNTwqAD3yoo zXuN)7AcX>t?kRET5$a=B0h5q9xBQG;s!LDHZ2bYy^Icm_ej+o+SP5`$Jv1f%z~3yf zP$(J&Gv_JQaf`vy|1lauI~cJY`u7{0h;ONdWBoh;0Zu|S9*(5HDdOq;z-DAQ83$ua z$3$3P{qZ%b;Tr8TR6eMpX;~)9WQyE7>E&uHhlxf)j?>=2#ILCvT8Y37Yr(th(MYRWZ!h1J(B(s@fbpan5 zN!;*SXL=%wfQf*u8edjrRe}VIxd)(`@`S8pv<^cB3GPr~O5j%vV+_XR*J?o$HB+kn z4Y9}N78Xe-Kgh_5F}hK3)kB?}_`hl5D_2M)#Dg!nVO|fcgZS;a%r)26Q2> z5s+VrrE-t79bfCeEzP8gG@&>rv>9OLf`*wCd+8eHPnwf^d1b6*BBP#@uy{NcJURbR zn?^PGElmeWUbqANIGDFOsRx{weXt5hSaGCZ5!UuYo_#03-SBZvVyOHi@C7fKc={u! zy4obhWSV$($=o?lSk|VBEosrdiomxzXx0$?t32;oPxD`smBja5{XM|GkytzG7HB+i zI+_xONpRW*Wd-t^I!(3t7vo7RQW9G!Ly6#|(XcAj8qJ;fwg=fURXgNm3T~Jf)b?{AxFghlwu)YxhxEJiZS)NI7FL&!Il2W z_|u~DS1!2t%?WR4WaN05$M-KE7P>R_b}bE5?Q~_J7SKG$*`2s}@rt`P6VF%tDnv(# zFb5Oy28(nbPf?AV@MPu!z;Cr6lx{K#EY5&jGQ`6&(#r#JWGyDOXM1CKL7XH!)0WSWHc&>o0D5 zS0bJEzjr@awn>pb_vpmH0}$;w3^y;zi#CF!#oTN1wYo5-P zBKPi8elw+db`nlW#MhUR`Gybz1|~kx)*uH6Wzad z+4w^?sTHI3FOWV(vrBcNKzGJ*RG`C3rwb)b3H zG2>8)%R{9^uPtgBJe49tAcmer5+`{{ckMtKLJJ}L`+>$>9w!FziW(a1tEOp!jk`8- ziUe|c5+g``wWAGqkR+FCJMleG!nIX)1Exf!WgJwMv=+^n(5_Xq)Sv@`bj(;%W)Gzc z@2ZB@YYM(l#Z<}C#p@me^!LN74(|KfT%uUcU|}+(B_v$!tp1Ij*ivQ!BtjAZ7^_ZW zOr<@(=633BJO%nWl+>z3PW^{!OSd>f(E@ozDI;uR>SxQS=K;IGAvIp9NAeyXR&TQA zszK87!&H|)M~H~41*VL%r0>+ZHg4H8u5s|WOK6Tf0x0}ee<|?ixzaq?qNg0;gBD_S zA(=kCH%5uabf_=}GKd!2$Hm|v=pM*BBGu$WN8UeUKFk(Gu)XRKFBbyA5bdb9su7m6 z&HoE9K+nHtmRW0-n>^F2HS2=1!7d-&=XPeK!D&joa2^FQ1^fOmsnrrI8pg#BK6(W`PW8j-?^%>Y%1# zJ?EQ-4xVGt)JO^*IJ8ZpC%76145J*l%rM_c)PW==CPc^UnFSlp1Zig~W&`_FpnF1Xi-ZmVYk(M)eBG z?*xE7f!3hW&5p7p?Q*68}WEeih55*V?c8|1V$59nxh+M6$Er*@mi zJXApP#GbfKPF`P$tQWePqVvkuTI#?in8t{3n!IC%v?}j4r2w!9kASC#R=ij+*9OHG z#-mmxq*0CxB=RJDD0w~`DJD0d)6Y1526{m8RLF~s$q&f?Eg3~%@3_}Mp{;>m*~d5x zoZNOGoqVK!^*FDEN9}TgK*FJ@=_DSdb4rO|99j7}i zg2nv#36Zvh+*I&0=IS9z8w?l?ItCn>+5A{|YTrTa@BDjBwGKeFmbB{yd@O+>t25QCl;N0D7+GD{+rcr@YAL>3O#8Ao8#IgKqSs++?_8G5&SD8{oeu=_d^ zPQH8nD;}21YI&})RXV>w;%I=wYD<|FyXHY^?LKFo-x=#7y?7wKIv3- z^qm1Qe@X)2nhgT%=@9hxADhYWm^{Tc@-FZ!qeoY1fk_A4>jqT()5WL8QpDkH*#t3V z^q6CIQ=9(-bT*R}(w0_YQ)=so&l84Kl+Z5n_IM4D?fNXDU3A8N-eIYMzQd4^ov#`b z=OMNrM+ovoct55A6Xn^vCn>bwjWsr@k4zjGJVJ*ReuHoK9v2Q2k`mb`A}H-Rl?HqUD-6VE}d{ zKiY)If#boCCP?xG(~-F)BEZ^#M6w8VRAdwTF}}APoU|_`X>tS2)FX#}h+&5MjMjD_ zNb#H_>vxTmnK@S6zz3gUX{Kpb!u(?ki2ZQLB(z3*C~FZY%k+?>R6`9}a17CzKq3IY z6og`t1{o-1@G2?dYR}K$O(bYXbAjQ}KI5~Pqd(1cX102Xv!a@YQ0^N~#8EJ8PR60Z&V|tu8sG~O zUg01sgSE;DQ>mer!Ua2@c@G^BO&6vD@JGmi z&U46(LZ0n^Cm*K{l&cM()za{B2i_ zza!H;u&@;2AN1^9oaU4d1gFo9wWGCeFu5eYJeffpbny^_WC#XJ0Az(?c(*5u!ww*2 z>4*TRoV`h4lCeIr_;@H>rQhFv7}IeGP#9+H$ufm90V#rx)8afQ7Sk}Jj=ZAuQdNny zrWg}qxG6*Hz%)puO@?vnTI;SMggHx7pQ*lXs2EJt0_EYo7q10Uj)2(Y7Mn$zM0 z2;K!2GTt_#I{tVG*R7UlY{@JXLCXhHjyR5jquHnq%~}aRseT#fK(n8n7gEsrC|t9Y zeQwgw{od@g)ecMG4f=c`u!$W98mz;RR17*_1`sMe6pt1vuof<`Rq6V{GN8pd>>HUc#MOtPD5%F% zRl!K!W7Fk2A||J}`DHS*>7KUI?Vov+c2P`yJ4_5MQ4$6eKwPqOdmn zV5adY8IlxSSb6$&EFypH8%8qJNf`X8ODmSwVUgNf07D@1u`==`G1{lR)nCn*?Uaze z8ERJpU?O{DDgeEP3u+nP(dnk&8#Nh(@(X06EOCgvgMvge;pb%p$82x+-$;n}lc5hp zpG$z+hc#3mp?-|6fOKsTDN`FHP^?NB*PUqO*%1{BycWECs%9*x09AB^as8SPBrK=W2-Zg zeLhUvw{SegHUv^P*pRj|RI9YJEHbq?Ik3&E3*mcMp;4|kJ_Bkh?XXo*kz9jEw%|O> zAdP*cBGgJ0uz2SQmQ0E}jenNSVxtW1dv@lN9q4kNGh`W~&}NT9s@F#3veFQcWS1y` zA_lDmAZ+3-4aow?Kq??1S3;p;E5vHNBm@9?+>D8%mIOHPL?$WL5dLlAqP=Q83Q;yu zS{b-J7yI6|9OiA4X@erlLErB|?E4i*3?#}l>`N$&p8gV=Pvqr?ED=fjrWz>1E z6FUJJmx8-a{V8)|W_~tK!M1E{FWA%5M5f8uw@Dd8EY07aYO(d)}rCQOWY65heABPXqQErYW-2fDnrkO ztE2rPTq!g!0x0Atth5e&kuT<(yv#_BF(!)`^SNmJ#{k`<*_prG*ZZNUVx-d-uMkDp zqEKQI!9SFjt0+Qtg)D(CiD&TKLOfrp4g}VXzzU~20OcdVBM3yKcE_5dW@g&?l+>7{ zIv^^qF0z7I(G0j-EA8yVXg&h}`xcAvUJz~!1AmeAS2x5(3a!zyC&<5RnWQK-hqOd_ zc&(bTi8g`G!B9S3vE>@j!HHKS)Cp5?@`OBIP{t;Eh`m;7d7&DDdR06-zI@Q&Zv-Q6 z{oV+P!PH+yFCt{2@6g%lc(b9)+5om{bif=Jxh)rOjZS!2`BEG>Gcw_ZNM5K%vaD(tF!1aj%Rtq_uY^j?pqW2L}L|!!!mNkhB4gzT$Kjv@yA= zJwzG=JTL{22aiBJS5s73{;d*vfJdsGM)K*(8akWp3Y}5?>v&b&zt{&0_g|ruU3^hPfd@fw*3_UfnMaL&{H+@!#6amQ70ET-< zu|Ypz1`Fs?6q8c@vmF*bieE)i2%3jEB6eIxnYLdXs1Ypzl<5;IWn&Y#J>jBb*0aw# zs58CR#-X+&j1K(EE-YHLf{8VZe`mqWH?1F!a9p_HrTLM<2Dz}*rq39~1`Q$QRL-C%0vP5VD zRJBqG!^prX8%vOQ8Rl>)Y*PKEMEU0X1_6a1L<0{AEQ-YAIDy89oQcuUb}=VR@rBu8 zxS^a4jNSU>db0Cx46A4zlb0|pv~5w4(c?Y5GGSaDXCX!{au9dzE*%e(k-{o;TUrAT z?EJxOx1|o@G_ipNNf%>syK^T4yFdxqVnuN^N4mazcURzTMGoA%!Qlgre8$qF+&32E zmkbg_VtL~+4@!v(%fsYHoQpl|MfFJc(u-m!lnD4mQvMeM{-EE5VUY#LUo|A1)_fqy z4e46XLQ%odYP%q#{E9P%MIfveEH?7bM{63%dxtUDP6Pti6c6&Ic?%n#Vdik-WhiVY zI1v_rMF!~t6aU1NDHo8)**-``MT3o*Cj=*f;-8UE;caqdzezL2pO{6hFHn3kOji;( z4EIkc;b@F){zhYjuyu&-O=+d7{`fV5Vs^gS}r zSlnz8Ufy^}Z1`vtnigWm!4?Xime#mJM~<5aKp>h-1zL~HA9X?et-KMkR!ZBBSEup} z<0}P0xUD5UK^yKajIh)6%pnU3$6^cnUjs^(WJkRmGGqQn|94Rz9JC3vPHbpaH}2+m z;UNGc>@|wGTc zn*CC)q?r!38f)2vsgP0}p({#+tte3(dAODUxSkY_Xp6WM(ycQlk>? zi90?Q2y`8f__Bj69I2m_C6sx+$`Ci73zahi4QQ#f7PvCCC--9`@nmIR8rm3^al&0+?ciPZVSfYtY_kBWwX) zp6!T*Elqhf2}~d$8UgO(P0b9H5-m$5i?4DAMEqWaKU51A8=pheK>-U2!brk25D-jZ zlt!DGCN4@pZHe4wRFY$vCjp@%m`2U*lR~5YgMq$kDT+Gx%+D)Pl*Kww`z8%2&`4$& z;gM`8E+{mJ79N7i?emDeL75VTddW}~l79wxVj=@)O1g*oiONH*B7l$$y;QYF{U(f> zbN(Gh22oA$&m}bHx+8Rjz-V4F>1U-sch#wX4$9!Kzf5y?qR6C`%nZ>}i}kNDb=8MW z&@a*la2TgL*_*dnu}`!`tjs3A4frq7=1b0>#>CJTQ;TuLj;|$=Zs#f^#Eso-jzS$n z_#5!N4U<;jYQLfw*}|AGJSzorKs?F-nS@Mo2Cgtjfd;|)WyyXl#t9AVro(Ji)cy#C zI*Tm3cyJh71DShm3fl-!FhCYgK3#Ij0GMny<3MrthIShbB%$A#=jA#HrY>sg)ScIG z>%2(!sh#7(gR&Kv>OZ1q8Sy~2k{-pOw?&-2w*&!cc>&HmLJI@LA&hvKQ3rw;t$`5v zDM*QOIQTChL~kTeu@e*oe=}fE4M$fJA?WR$j+b2PnAyXL(~Vfi`fRoplMeQJ8|Z48UpB~H_8y!d!9pe^6HHD1aUz1_pVYE?jJ+3wcV#7-iw5}o<8 z&AS4Hqy}IF1q{@n(RIvtR6r~&ga8N*@PIlq++i^l|0TDP=;Hq{UyzJ1OVA?6n0 z4QlwkniuXNq0ABZ=3(Ppe^{zWhR61~>Ga27j`Gh254B8-5?STtj!x0X&@q<+fDe)I zaFC3whx5$L`U8{1!ImV2V7Ukv0HLU&fWmrCtO=I2{4MEXZUW% z>9&DLp7LW-HLm7|q{-=nhk~AF6Uzu9Nc$}fQ7bZ)bmUmWU$Hcst&8(uYZeln08gBQ zNRYG0F+E}(L%f@lr$~e7laWe?ngZ6Ds&l|Oe4)ol>_v$V8oJi=6}sJ`EHD946S7pG zs{9ZZr*dt~6UahCj`Op3_JBwW-Q3Bx z|2mRHEuG2CBLVydoBRbJs&_OEv%Wc{5qVaKF18Lc)8n72VHMq4pd}P_Ao+qtQk-mH7em4XOK1+uveEcxLlJ9YyE+iI{!6(Zpc#W~ z%a(LBj{H92-)(`>k@G)^M(jDoLS`@#rbmtnbE)AMo)UTE9rs6T`Fo>R8Tt4bvx`{1(3U}|7q1)xk?AJ;`EsNSj zoot2O!X5_KVP^7>_5!!0H|+N7rH!CY!%5`+ELrOV^?*o~@zJcQuwG06Z&tI-HhTsc z{HWxvNl%VcCoL?if#}y70(3J$`vO8uHU5v75-j7>4w`m>&<7C{nO$X@v(ftV+O*RF)vL#5k^C_^Q%7jjvhR_`)>;Vm+FN|}p z)gymTb9zD5+%icdKC_YHs{l#h9$}Xif)Na9*4p^K@+qRX%9X%h#k+0}fpO6S!m_)2 zx#?$Kec=qO+g5YPdDNb+U4OQ6C0grZf2?JpM}Vk?5ugl9v4p9TqU(R zwehj_SZigl-5|e(BU4I7ot2wHR*M82NJvq#Hemw_Xa!TNSl3#@p-SQx!!Bh?;U2=7 z@7dSC57Ir9kjC3}RhAS{@d#5;1lAS-%N7?X#!ObJ0Q*{#tTKA}X@K(n=oZ40Z8w8j z-H`WFqR5_0%?P&?uV7fD7Ec!bHO2o|x_Vq&66q%du~yNeGg0!a>Cm6Um`808R+Vy0 zFcc69fue?5SA_LF0IxD)W+9-i;G^-Xx(;_@LU#@?kqaCzaFYoyp+cfr&4F^A(ku%? z6b?(lBjCjpw!f^kq;XMRRB{s&WiuQZ@C8d=aq;rB*j0$LOJL}5oV3T`iqZx-PFA*P zxGk`xy)Z(el4?S)0Ki~l*Ubb&k>#cW)6$Ia&5IF?khaEE(;Y?*!LU^}UtLKUw4t{* zc+q~-)bHIzLx@az>jYuL!j~kJaFKFvUR#Ptw#H8#MwEttL32Z4mJ-=K$}Y6L{*L7k zErl;};dP94!}>%8k|o{K%71cf!xyuL{1}bwW}&^qar3-BZKY%;;+f`ci;jQ$4CR^l z)Ya4}O@PFoWsHJW0C{#(t!RP_t`>p?-61{8QJO*~IGFe&CZ%I2zxRnz7+UWuaody- ze6`-on7{<}gW(jCawHQDlYK0-p<`#B58DL+Yl5)ZFcFHK=g5%Ihx58Q$b(o&9%6mCUc^N6v-aAsc ze7TH23DIau58oINcMYJz$zY9a#lDJxq(}hYYA@{%ZE*XTH3u+jmi# z*(?MSVWH2l(OGhB7(Znaj)rjuOi=dh)PIZ^c9TOu0Qv^LFaWl;!T@^PSg={7;ipP- zuK66IeGU`|=NLR{fJD)xb|)=a$8Q!APZ)r&Pl{eK&4c3FoiAJ}IC^goa(@a&XJ$y* zBU3yIMiVK^+^WzU*d{~CS!Q>^d|;i%U>&AFX#fjR(mdSox5_4DWD2m!X!?IkdWbo5U6=| zVPgD^i0w!^S(2L$NHLC>Y%%^q&e@Fk)Muh17!6Urj6@{4C=bT4U_BON11L58s4?PX zF>gdjJ+lvaLS<2FIbxZE+8HVvQCQu*xjBXz&tUJk*c!DIxB28dyFa)SVJTL3D*E5qWqDE7Z`i`Zd*P#PzBqVkyZ z5q%lpV%R|9YCX->J21*3l(8x(<>|n|+n(5AL8=bd1Ry}5wzdQOPW?S;wSfddz=AO+ z!7U^Bjn3$aR_-W+pLpTYsJ*&TzW2{|A>&*in$F9@WI@OArgp_)KHSg33^s( z5~`f2W7b3(+uN`9F+<@5e(Z;3i8qzYNWT|_tjG`ta71e>%F+7AVNV<6Y1}AA&v=Qvs%_gNXx=;*d6MyF0m?T?Un#o31OYwfPZID zZzNh_l4ob41SEtA6oCx7@U6ZIRZ^n0mlJ+8srg`Hxk>aaN5?3Sa|R2;Fj)4moM}UZ zEINtcya{S%&jwoJHO-jj#smn)wjD|WBYNOQlC58nohb2jW;kgbrh(W-)7%G?UyuRK zq#$@)8N|iVL4v!PW4=H@SyOn2@C5{mEGbK_y07%OMkOEMw_}S1z9K~+0eY|#i8L&r z`O$RIAgy_)#!?I{oEbyMwk#>y%Ly`D_c7-lEIxv6s@cGjum~#fakjfVOI#U6$FnS# z9LblHni{IC@p|&viO{*&-8yhv3?c^*I5y;d!(m?ftBs~fM6gn*^zmpW!m?BIcZ98y zTqmBGxINDRj1|tUYb{rhbEx^-$3jOeD1p&73z1b@8nXhKR@@6Nk?lHQ;uBp!ZM%lR zX)|>lLL}?SKA$WH=y@juIcC&!NIHkhOSXnQF*6fAANb7#OM0K-N#muPPZKP~#BHNVp!*5$Nou5LQxB$Zth)w9_gP8MVrYqkOc0 zkHJ$*X%k9xA2m3onQgoigKInz1YaP>Q0Z%VmU+=VfXd_X^0KA0ut4QcWJ^5hJ`6ua zuCpX!n_L+Hpv)nsrl<;kD+}s7la&>tnX#9|>Eg-?JD66St-s=I(J>+j%4L(%SpzF; zS>fk{L`;%*6VFrQ3Ob9LtAU*f7iP)Dxg*8$LpW0nngO&4DGN6Ga zz4D*cG5Y9&*aaW$)`_wl00W@7hzU=vjJ^jKrN|OdB_=|R$)IErcOzU3PXGzP91Hvi z1Hl^^bMsoP8b8*4*}h*`t?5K5o9(L2m_g(;hR6-;>4-nw1Y$essv5)r@mv=#!+mVN zy369O0e5E`5Do^y)Vq4weGDxy==KBE3$&*InScmzgD^d?bg~3>CN7J|hGT#TVq6_H>LXckc$bjRTuVCLUusB6cyzAmf)Ai!_ z#NL7-QejN*Es8S0`o8uSvn&U&yki0>-hGK8%rLOTKyd0wIP}F1=VeljySB4p zAC4tj&8X^{G3FU9TSGOf;e}0Tv1%pb3~bca5GaMH!j^hyKwv2Kkoa#D z;0KmE9^Cr~I>STVp^-DAxC0TX-;T}}5|Tj*&`S6NN=L#tauE?ESk}Y5B?#=6kBD_1 z?hI+lp^#}^Q@oV0SQ}71VqQ0ZWKiZx2cPjU$b?FL&64ep_D%dLZb(=#sQzpHc3_4q zOhFO*A~K*YaSpn7Q^k2$pduQ{R0s?AbcoR~WCYX27hsSq3kKuCmN9KIkwi;E^UrCo z6naP;$%&f&33H(+k6xX;W_o;%+j1sjpg`HqnUg@1&UA@RUDky%TBv-aSXR#SThC9Z zqE0FlL_fE&{ra&uWBs~jX6h&ozJOS-)u3kQ#;1c@bDs8CKdCQ!N)GOMNgPylAM5tB^Tg+x(7axuJy z94GC-zN&g^t1IzBVrkMB9GRjbPOmR0msE+i@AmGVDVox*h+UJysK8Q6=M6dl39=$S zs98&3*h(IP@Y3j|uAJ-d52&RW5E-^N#YWVn{i{27&cWY1_5isF1~i1p&!Ps62gUYd zyxX*Z73$wL|Fz8)_&gFPC#22_m*i9$rLK1YI6@mD*C{G-FlpZYw;i0twe}~AGSfQw z!C0U7L)gp|46XKQ2ep-=RAnwz&dX%Kk=HGRLSn&OW)TMJsy_rj{=1K*&{WXgo*Gc2 zn_nd;t5X*425l}ot30tixWqiA1b!O>c$yy8v)-dFG&L_|65kx4v;YrKVbDI5MHG^R z3el>MOrP7Pj_VrxAhHnyw9!6MCYp9Y1WKWQNh1Zq!Na3sjangyjt@GKro}*W!(I9< zGoj<@=PAKtkg`gB0Ul92Sa+2KJcXg)VL`sCP+QUac}1(GXjdOh0|Rh6EcQPvaEBBi z96an|jEZcYCz24@lz{N2E9Mw#5P;LjI&F=`q~&C7<<)zftjMP@-ieh?ELQcxyhY}# znQ;OSr;t7=q*m{7x~Y88brlsasSa|N%ZuqZnvZIfWvI|-gru{fY0`zn1&Uy9_%Flv zaahF3-!VeC_alhq|Hd7K$NqU#`$(ja5uK6goYrYc9T*cpY^LA_d#(g-s}_hO33!{W zu<;{BC^|VSP^6c|Mx%YvyHsRkzATp8cR(dvA_PUU;>Z~!pgDpzIf!)KvnNFQg2ht9 zM5x*Ffz4G3I?7qoSRr`TivVfRJHd zoJFkEZXfR_Xa$IP;eqzNtvG}ta$SJG&5q4E9gjFE`b*4zE`c%F9HiNZg=JB9(&1{0 zWyr5e$4?g5fi3p+E_BhcYfTh#xGL@-T5T6GH2&F@G&x9)s}12;tzbIaBnvJ$ICaP& ze^nu_1xDfs08>W02FLy635_!IVp;=mhx=QG(k_I zyz44f$^wBYtxB;?Q+L5tvdZh$lFC%@zB?seOIsPAd)7I%!%cw$0D5N!$csEp_%82T z7%1q7K9@w$*S3fTfD8*O_c9H!4uLR$?~8yH_N?EHi{OZ9Y6u7tNkB8xFye@Hy(f;E zy1z0c!an5ClOL9O*+xdH(g?FVCq4%2v4P>XWh({1DkWn~aTXvyP$$oZ`H1u^3@5_j z^`+Zb)|k^Jk!jyz6cunPNEhJ+e^=0dy~U?z$w;8q^|o69JE4ZgJ?kzX4v3@%!{UG6 zu8jx)Li+`<$4Jr70=lW!pVL;v42Vv@+hYx8p4PZTGK!^yK|7RV37)0~2@DJZdm(_Y zWJlV3VBKqk^aw#!Y6ZVl`Rw8zfFUKIMW*0MAmsXzCsH;$_L7IkIfemz5C8}r{r$5D zd{=>IW55BM`8323BGh@z_Wg;tF$51pm=?>I1e?->(hQ|5Q~@HSp6wiM@!z_77*y4n>&`>+j z06xsW@8mRfTozfzz zZ2VlioyxFOLUDBtNoW9stu=ZI4!wsq5=5lHqz<%jQa%WSQ`Dh2B7$2V*<%y{Bqxpr zSK58v zG`SZEQ=|FhA?yJWAsF#gP|xxo3%&nV;a#u9ktlmGOm__!Pz{@VFc|zlsp0ySPu9M? zeaA(C1_wjnsTOhtF-JbpXI+W;8kXGymUz#ppCbUharZ^hLiJ|XU6AwdX=E@`DCkYi z3=}IaC6LkaY~Mqf;N}WLQnyNY<~v!EXk*v|JTf7ph3gU?8Z$A`?Ib|sGDwT&^;jYf z@DX@RLt?)HeKs6-^j?MdWop25`Z*SF_ySTGf+sOT6k#+1Cdoz0C2SltLr1lF;7$^= z?_{OrkFfcWGFgmd(*g@hxl6Gk{Q-XpIj0_6N=__4;69cAsXC+(FRCEY!m+F99IQ-h z1HkwQFlgL2WujwMNFk-Q3r2G;=5^fQHnrRd1G`-$qwpTjGsy}kBbxZ1Dr*#^Ql3RQ ztw$2#r?j~|sOZDDgb;a??gQuu9g9|#=*5hMt?@;l<|9ZCj1 zEcQqS#+J4WAnm_GsU-apwifKKT0X_oO;%S{=_oixDKMnfR#Oy=sa^o1lAjj6pe#zD z(w>71(70IF1Ps95E?yfF;RSSxE~(cug}_ChZD73;>RsK;YhLDP99uish%65nL|wUk z?wifwh;p@{U>OP2NYG0V_h`krC&UzFK53YewW4tCLz~K}yAe7vj9t&o30)KecRGszp2)O(re$IL+ zTFc*{gB=R3l0c!5`xArP0!JG*7)Xp)xg(CFiId6ztZ9+lf*m;#X?Sd+9!5^XepPlm z*BBRwM;+;Lnu&1cW$STl2=-bVP+bvO?VH`;75SKt@9gK zP=cW+lc`mCkoPcV_vszRmD@ex;T!wypI}$sw zSGkxS?#QQ--pnkXWY5NRFV5JZXxqG^`-*(f^#8A^j*cg=Q%EwvQ`n(iguOCU;vEN- zU@zIu0Stu`e?$pkytDqWx9in z*8g$Cq2g$-73Ta+OPoY!HRt5%7`zn?w&ua|(q`eHe*@sk&k`J?f3S72vLk}OA5cI5 zg*}x#yD71X0Gc@0j*;{@`>Ay{JS;HKi`ejso$^(&<{_@iN#8Q2QNO{J1{d~yo_1Pt>@V3Of?LefzId^#%f zyI?dh=n-Xd$mZBb8^9jWI4Ic0Yprv6TnmL0!a^CP#1Dv;TJIV0?1yu8+3rAtP#o?tr>?)Kz|DPY8472R0<|)qKOh0N-uY? zS&<-XyFRE!FFIs42kXNOVLG+K5iKBhV;cT%dqH%71kDgp)& zsgH%$$>utLqrN0_%%VK`;T9?hB)#ddsz`*2dmc9sm|w;-jCV@k;dgQ5m`sG9am$^N zZD7LSP||v>+9wG9AU6Z}%(dV<5jE4cLHkZ%)wx3X&AUmByS}`;)eFW@-42@?xiAs$ zUD#%yNQ&~RHEfPg1B)$?mBQw74TAIh`(0_S0jCS01)VNl+_IwgHLH@%qQh~!1 z0m1J#M%#181prie;{Iw`tcURn`FnB)u=|+MfosUgz+FYVBR`nS(3$e`9#cn0$fCW-{J- zKV70+l`gtvv@?pyCR?*Lt6sBYMFG-59y7P=SB=e znfRUiJj{hf^3dX+Nh}7xaD@Sn6Ca&T(u;o*fYu$urJ>lL!}}XwE0sQaf0?B>Lyt2} zVy#S4W}<1IVC(V+brX(#pBBmxQVOkZ=N~UORTS^?L5OVy4q>5yH34u8o5L4QqBNrX z!^UL!N5JFLNH!*Ei|~J=ECL)M_I!Sm2%9@WW|fvo&?u1v;jBW>IiM{R?6#etr_OVI zIQU&g6E1zW?kwuekEum?T%FjO7V1Q*h_LxLugHDNzqf$Q$Ae5xLa)JzWGHe{CZCQR zy1M;5&tk?0$|yGqfA>VKQl`K!O_QSX`$k4-0vCsQb9_!QwD9RjUu6!ie^~`!zxDX+ zf`K`#*U1MwJ(tgaiC~Ts6ug;b&hl+0412lNDn~fqdp!GdQ=2xB48v0l#V=e z-Zzy}H!z6qYkF0QIkQl*QW0Hwl;>%)y%oUdn#@N04uw9;0I2{h>Kksto%Gz=xnhgB z(YeZSjkYBO3BdYSv<0h};;DWjja)bq&Nr`_1N|zs3hw- zBNC#^WvvX>*R>2&{Jngq>f=lOCRO2GkFp!K7B#3-DVb;Dqk;iwzE<{dn~!|EcjC445>}()P{b< zz^8$<1M&7iz-aM5WDn6INCyA~X0J`n1P*oSK4CzvaFP42tD@&CoV$h|wupoLVU1mn zM$rgRiW7j@v+q{ib}?Hy6%sR)N!DCD2d>M=Vw8qZwpj7u_l8XhK(`7YN%?hUOcx5z3~@%eZ%$4vBxE_@q%u#}-1&pb$uV$*w=4)7;V|ZE5$An? z{9I;)2{=%L3P7i6YKN9$XLEdik#MMHU1S`PDU>vzxV1ANl`#~+Z7z948>~;zO@QH~ zQz`Ok=3%}-%mDYofnd6^5xE}vgClw1%oVuSe(y4S6ro{UJSJtz&cq9*;l328SEN0J ziREB3u>~nC3&n$^XmHnHao*#Xk3C>C6drl7{t7X8TVMt$0>gh7W2y;UfzHci5^E{A zAjoDwhU<$3Nf$+sDx)#@<{^$4RrO=IWjOsz6tKiD`|7ptclbNuMTurBxGQk;8EI=7 zP{QGVgCKjDSi>VyS%65N60zB!ZF-~Khd}XW<;qT)1{FR!9p&*4P%4py_sRs4A)>S^ zE@m-VKUc z!OHht{0<^eb_VU1#JXr9c77(D7hEdo+{6e*O$7S@*M{{GUMNIvWD$AqQ z&=#rOB=m@f09RTZ$vHXq+2f3{Tg&lO6GQca64!0=Aw5UE$l1pJSEU4%g$TpG9kKHIqV!5 zgeI`@2h{R>Z3Njj-G~4Lv*!?(VmAOFbH2j73`2+{U>f<1lxjT|;a-gfDPi=*#Pf9ldF&jevss!IsT^wf9EB1|385PE*HNG`qdf@G z1_m(bjwjzQW&azHfE|co3j-|^%=7{`4EHyFl}=C>HYA&4^3g?+i*I=b%s}}^8mB;l zh_!__{Zdy3=!|9@UW4(FrDYKrMZC?tZl~{q+CodO8-*y(hRh4hOK$GguBQ!f+tM?Z z`M3v{_ok4+;-Zr=Dzi1bPOQ39yGDpO^@@jVf$N6EX1)nkqCTNH#!vSt^@eyqAre-M z#C&S)u>XXeEKi}tDL~`T#6OgH#$g>>YhBZsNLr<9Zb0yh+-2C&Ar_5e3SJ_h#+$_= zmV4BVq4~PWPuncYsg;H|!n}|+cpyoIM774v zO^--5^f&-+{-;gsBT{H`)h7P&H7s@2!yT4Rk%lk|bb(1`V2F2t#L9DrR)aF&m)D{6 z*h~Y;W8X>Q8#;~v^rqD_q#p-Jx8Jb1!bs+VfewgnX`Rp0clH>+LJJEFLX&Z(9s?%% zQRO$<@Xc-+H6Ui1JKUym+-IFW&|OG!B#+gRl#z+)cx(k3OdM@aCyS$}OF$98TO?6_ z#;Mk^JQGrumPEUJ6Voflg1Q%H&UF7YFA3A78q?qTf2xXD*gn#OI_j0tEiU?!{O$}O zWj`g-VXyO9eZ8}k^C`V$c2(JQ={2~wt0nNC44eFvtO}(PCTm!q6}7$mWRE} zw!{JyaK*sQQc$>zr+Mk(A*dC%a}1f|g@+12-H$_gG3_80Sk-6uWY=;5|z`tFl0=f;#mvlGQ?zli^lD$F? z4C6mPY;}ZO!ghjx((8e3Wq!ob4Yvh2R}FF`%K4=VT-FoBtPwG{hl2|uJp#RTG!5kW z+dn9haS~>!qX0{xE@(jLur?H9`H5?dL0zIZT95I@J1-Z}>(q$Z-$R zgTrU<6Z)YW0)Efkr~;NL?7bK7rD#f~3iaa2oGV2|W;?|ByTi?Q;H6Cd((zGs?*{Q$ zqusfyzr098LnDxsBq(-oE~!X4oI|J+S_lteX$SyxV)05`L(MJShk!f)Sei_c$fz4y z{0hOQ7YeMa{Jn~oa2_EA+plYBfq@8;)`abAB-7HW7eP?IAoLL(fuVIJCMeTG?!4r$ zget<&RS@b5FuU`@EB3j}r(n-kLq%22p>bUgVaz?qKk9fOVu{EP-u}7yzJftMZiGg= zPDo7C9UVkE+XcDe_-clr*6u6RVmP3E0t<~wRJf#q-DHzwFhIG)Wx8ni@k30GP*DM|iyK_C#|&%$4$fe|X^3MP=RDL7}@U9SPeHP^N^^sb+1 zp9V2PcFt(@!BR_4!3Eksgk+W$yxv`LRVFeUHfV$v|Gz$m8G+0Y;KMtL7$C8sD&6A^ z8tt3^oyl$j9a`u{^a%e3wlpLpx}o~xJo6k3IAsLJ;0rFHy+=p7$G=cTy<>2ZLJ%Vw zh&s^MSO%6!AovQlBxTyI1!)bagEXAh#COP3Ga5GgI0E|EQKd9qYk8pG@EJMB5F#Ii z(?Zz7?-n5H1*R4AMOltZkSDu<`T+(YBfTzV(scN>_RL@AQ2z|k%$yh<9O^O%+V8H$p^x5B!&fqwM6W5HnQtZ%KgZtYJ;%-J0K`*@RNKb6 za)5XeBeyWXQX7bMpeB$(j!NVcJUvC$v^lklNjy;sn*rn15LkysA=j$g(w$pEBSLVkBB%Y88T_Bl_`FrHJ77>&`7rX90BsbvmY4IU3Ik@&d# z%V0^5Ss$(ec@&20WsU~UsdY+9r8`n&L4}b7D_!|ZNIF?#uzG?vZ&9QH2taFUa;U!) zpOopLPK<+Q2gz_+$(3+r(Is<7@|e>CBxI;{!w8eo0cxTh{@wKG1UN$!2ns5)0UiL` zS^ZJ)5peyp?GBBBF*FkE7F|35xS~-n6BFO}dnnw4UWgx2sQ|l$#kyW0O)N#s;Uh*| zBq}TXPIUZqvNQ-;&gm}{CS;h{G9Rz~#K^@VmI~y?PW@S+Bsvi^Q1QsarV|4NkOenG z+EwQX+zdIWNy2FjLjxNE0_x~>##mpRZP38KfcC8+Dk+IlBLT!>3HlPDT^PRuv#vR5 z;W~d@MG}Ja(g*~_Y`}dqie{ADK#J>}C)kdxy%WoW_3lEWpJ9`UK1P&|j*Pj2GCp zWO8?>j97(h8LiI1Fdak=rg+nF*6O7Q*-Lrtn}jy=mm??!+jXvgS}lbgqg!qHo(L5q zGnw$|r3yz`YrF|Ad6pj8!nvd{nc@)iIy2xJ3fg)d z;X;~y_gH9gr0i!OO-bO5xJUadI~D@^(*)GM85dI6=x`j^3T)idi0ST+0ZHy8e!Uew zAAn&6zXu95(GS12jO_}Eh>tLc_}5U3-GD4k6Y``J#UQCk{HX;)60)9Z53kunrzrXk z#FWflWssd;p@KC%(t9ig7xte~4F-jBIEQ>Q%xYxLyW(aav*v!r)YQuY6DY8U#_N@j z!q^OtWE{nwF}tm>Bko_+iRyxQ#u>ftBx#bmPU@1G*XHG4((<1qwqs3)v|2=Z93W^B>lK@N%1DWH4 zh-s>K6QbdX`{5=`X|U0dH8iO2L!8lTwZ5@G8LRCq07R^VY0X_96LH$gDf*#fC7 z*>*NZ#d$6hNI@Vnr~2GoDt(H}Td9 z#W+(W!}0*A3t{vR__%C4|h><<(a9k0mV89;2~y0GLbaWqfqb&Wdz+2 z3KG|Q9N3(hLI)18PI36QP$0m+oB}7zoK=gipwZ35Mh;wUPl5W9?igb(VyT3ff#^g0x^$1zxXFf!HQkK zS{puhkV&Ig{Nc*%cR(7`rnp9-8`s!kd}3fgASbXLHq zzATe?n}agP1VU6Md0b$;cBXcE9cL zVR4aVL`QsTXbZup5SGk+Wr>#~gv45ic1M~gy+@flV56X0T5vuO>3d#i*x44r;fBGWnXCgZ3w))l+TvRFz}E-@;kRK zoigNz#0I2Hp_bTx1F_l5jZz64O~lS1P(WMWYSqKy^>86z9$jj&NP;0v^krWlV2lDa zP)$LNhM)yw-Z@FZ&jhPn_K}kk7NtaQTMLI*fkKFk*aH0la&yH3TI*q9T~3T_;;Z1Y z+t*=2kKrg5fZVHPu=(nkezaBSUU)z>3|Fc`_?=El@VefO=oo!#-O*%@N=lG=0J@+x zqR5msA@8Z}2t#rRsTFu+X>W@II`HJr3KsRvHSa8Cte4vW%zrVOWb$(gIya=L&F$o8 zC!W)pomoa``&sOPNNy)jWAuZ?Rn%oh!j=Lkb>4hg*+KkM6IiJPh%is>)uF2#S2@}I zC)f9Fwm<%b41e=g!jkwC>*Hj*LPdKyL|oQ*K~DOA6erODf?pG%!i`9Ev{G_4KG-z55hx3fZ+5}ux zFll&T+^*}r;D#@5E_TJGY{}FywEI5_<gk-VGiT)19+e5*NrCbeBIB}VH$^_t0a~>~ zjTLN?6QB}6UB2u@JG%2%H!9(dsA_mf^+gn0)Jdgh;*=@P?aGNXsLTneKH&8AIwx8} zPiEIK;(Xd9%UyTw%bNqwQp9dR@lAY=E=_w>b_JZYYy?BicG)gTXLb^MH(wyr(xVwiY5GrR^@E#4%k`@6b9;KCHZZ z%L?u_GUh+{HCeE#LOvoSNMb+~aAnpUfvf!mZfG}eWeau!ARQ1TjWEb8dkAp39Vj~U zv@iG5SJew&N^U1T(A+vFra=^5vu2PrEM!F6TUH}CoL6JJZcM2#mC?`?XOy`@g)wL5 zKteUGP|MIw*v4}(AQ()W033j#<$fR)qHJ+JC5vlZwg>X zD_$6PGfZir)_HHmiaBCg4}{=Z6jOaWzLqhEi4eguCgSCnrqG0wgwkGg8&Y13uzZDN z#*>x?-GL|;`zd%;0YvDoArwX`WKaa#Rx8dVrbIP~RV6UPt-Cnt>|lp53j8Tr@fshj z@l7;VkOrIjJ`Gw^xsa&sS_)x;0c)Qi5k%+ds3yD$Bf#3c>MM?6fiA+19}qV*hiFgG zt0D4Fz=E)~Kg6+=(-{WUX(TkALind7oaCB#Yea=&TcAKDj@j5}@WE42@&fFrUg&=Y zymO9hZh!_3`Jm&_bFz{+Ym%+~jJE}KoP&fWh9{OYUVA&h0L%n|X^!?3kRZeNcv|ZN z?lr6BvY@e{w^7Zst)uFD>Kop?J#{8%t0xUE8)5DgL{V`|a-epGv(n-Pq*F|(>>0NK z>f%sQQiXmM7F7W&B(Rd8P8lYmaS23{uO+NYkda|K6kBPt}dP~TV`5-bc z2sk3(hh$&~q!HdAbcAFdkXRhNJgjhlc~JNf)FY_IE*O|*V9OD?15Jj2400KoH0WjV zp9Z28gk1q~1j!ICB)~&(kO2Y$H3-uWTpXk`NMvC7Ln4MJ40Ippe!-$cfQ2v#LKDm= z&`_YDK@);zg4PDO3WOC1Ens|rssL&N><9P?;5C3LK(zsD0=@?T2pj$Xj{m!S>;D7& z|L{IieNpqEupdodiF~W@|1tRQ@muAWsJ?#vX!z*%yTG4P{5E=f;iJZ7(0Ajn@T#4z4zC7QD2%3Ff)Ocg-i0?QXz&0ASR~&F~(D z4+FO)zwl+Ru{)gF&e(R9ye*gahqMOOdS_{`p&TZbN3} zO4>MqZ5rdExMe&rj;N5jxiq|QdR&K4@n$r5YVhF7^ggha6Y%&gcSaJzeSVDx4g+gLDYO6l@O(c_MRFWi2fFL0*d2lr) z8n#&-XQxbsNQp1-1>ZE|25lV(ItxN336wT|AOUA~<$G#-Lm;EUflWQ2PaKt!V0)2@ zjJ^F|+4&{1156y1XVhq>2He_=DqEeIy1hpzgCD+R&0^9)0J$9*>C2In3%|&ElmRjaUw6#F0}I9dQeSkV z^RzLX`Af@FJ2@Woj(}VlLHkjbhA`x+CcA>^#@fP__w;dyboTg56DwFGCb^;j5X8cR zLI{`Gb#h_5wKMp3fnJO4ppzx@>y2a(Io#{*0K_;QW;p`_@ys!fAt{OENE;VuFUsbC z40h0pe4(G)dKLkoLJvYaa^3p$CM(sf4-6kw&$s8>k>#d3MdQwty-GY+EW*B82yv!H z8Fn=-o&)#nl90Ts0VOSU&X&>=kMHhvbI0fY{(po}wG&vZJ1Jm_MJ znZg=Dkqpd@MdosKGVTZb?tb%;6?47t(q~qaF@Efi<-zN6t1FL;l|p`+*eXW$PP8xU zwWe{O_Xtuc+^SR3q|qm4G$l~R@qD`i7bMI(4}Xz8p=K+^y_=BS%Lg9Q6@x9R42G{_ z3ujo$F#cfmIf!D-V!92kt)M)q0D%-tAve2&X~N~C(5xJOS!o9sX5A#7=E-d828}6u zEb|K&T5zgCoJb4p$9EH%f$C+G{LUH~tv){r`^C=p-iX<)ZyiuM4Ejlj;Qv_AJ(c<1^(u_O? z!9h&{iHbJXecG1W(?@=BXRrQfFq_r>Ns)O5dSc{+eKeE=LOWeoQOS>{1I3Ae^qV~& zMVyz(&kg>Lss1J>_F3JQ!_(JMF8oZMFC>f!8((o%fP?>WM~N{K#TOxx2Vhi)P6SnG z)VYfB8mattOu)u&z%DmUTfB(}1hry-W*%Yg>w+FF)KGK#rMv?{gx4!L8ZvRY&?8aA z;?n6XbgqHq_MOB=vo=uJ@dBJizk1;t-NhFZbHOU^dIl=QTGU~9L~Nxz!`v4c?YE}^ z4+HBd(|2gGF>P2X@V2WdAP`hl5OzNW-tpn--;vOvJ>heyF11A#Oo;gW?0Uow;-T@b z87P-Fkc% z~9spB&5E0V2-wEC_4B>(&?nod9X8@&nMmf`& zo$*$@gQu^K+>qXKi|&%C5CBQn7X`%)XlLO0#_N}~Ut#AR2aZTmd*lP))3~cX>ZY-5 z)zaJ>3=Mgmg{PR(r*IL{;-cKyzQcsI%^R(R*z=GO28L`>2+IhR4ekE+4 zM+Gjxzqe4kWU~R-5>VMZT-3ZM(po&(PI(v(&1dv(86XaN;BvHm}^fU38+P=hf%-Z4PrXG}u{ z^{g=)0^+lVS>{0*NjXNV8&_q+Y)FC5rw3J)qxWAWsHWI1Q7czoL5fLjuNaLok>pJ0 zQivnSZfgD;R3V$T#E<_`Og=^fL87?6@mL~$cPHC8+zk`RkkHzqC2ee!6OOT25}?Au z8lo5|NxX-eBv?+_Jl(h9D~;e6g@3JwzU4b}rUS0FtbaUHZZ$m{NtvL!ESZJHISL z#$q3276qW>>e0K9BC6Lm!PDcC*mJ>96;}jV-`)zxB`?jOs*Xw=t0)s{mG?QRw~8qt zfu=rKWTTDPq=!y;1b*tE3H@nBXu_aSH~}ouMp}xlRsiQy|?8 z+=eFuOFpAznJa$ z9HP}Oq&hZZjUr$CB~(eAM!iJ*;=b?Yrx6h>^|H)MP==A9VPv1#j0hS{CaVQ1a0U*_ zOPt|Q3|tBH4>cTq2$K@~xI!3~L_nbiL8%UpJy?`vZOB>f8|q^o(U}ch?lcb}gFn9* z1|~O!l8`0`5O(Y2Oh~*GnI51ZmY26LDazLJ5qc&Ez{Mb8VGH2izKeuw*Z=?k00000 E0QL`y%>V!Z literal 0 HcmV?d00001 diff --git a/assets/web/default/font-awesome/fonts/fontawesome-webfont.svg b/assets/web/default/font-awesome/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..45fdf3383 --- /dev/null +++ b/assets/web/default/font-awesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/web/default/font-awesome/fonts/fontawesome-webfont.ttf b/assets/web/default/font-awesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e89738de5eaf8fca33a2f2cdc5cb4929caa62b71 GIT binary patch literal 80652 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 qx{Kk=rVu5YQ9XR<GPS>b$X_& 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 z zk;~TA673(NkVaj(KBc!w@05^onf3r){p@)dSXW+z5Lp53b?WLjJ5O4}&eE6r=G3#l zy9na&jq-~fNu=eZP^F3@M#1VeV%Q;f01*?feWPUTUCiQz{OtlxQ)i&@(#7sf8_RFn z_zl(qN&8!`sG8}DRNz9@oyZ(9k0j>gd*tGkRe2Q9bZcMCsT=#ykBxk8cCY4Gdpwh0 zy*~CL>-Yx0fm$;?pN@TKAG7GRipAf5#Ct~Cv$1(>jow@A%?Hzd978^HCH=@W`nU%) z=`da;>@~y%Ys6noaF$BJ1F^cNy>H*x^%%cTvmR3HCGw~F(nf>cj$+TE&m+X8ZH>5w zj_*JJ5geh<&LG^&-3>MYy%*rG^(k7ws@ z*_b@N#vePW%*V5wbBnJ{$8pss)61p$TJkZ175bmw=WhhQp5(Ib+)Sf5pivxQ6zlO6_a z7r&o1Wltfm8fboXwM*@ zalz;j)vkuSndmtIF_CJE`<2E-gZiOYt@q>xMD!(Jvbu1Sx=WwA z+IJPe(23K1LI1ChdzPLb+7YUrTh|UD7TbSc@KLI|%C=5xH=IrpE}O*9w5la8YxEcv zeV4%MfIM-lweSDZN}B#iA|}#o+Oyfopn2|)Z#cSB_!yEau@Ar{XjGwJSbJMrd(RH* zAS%aCl37VG!#y5G2!6MZW&nf_F#W~qK{Oc_V4Mvrb7rR zaD`}!x$m4bqEVR%Kr?fL zq~QKRCFhO|PIXCZy;8|fbQPb;0^ECu@y=7uu3o+kH$<#({Lu|yC37Xi_2_&M#UP_vB*vzllRG-w1(FRoe6UqPn$t=7S42cMJGFvl+IRP=vyce0b_H5T?##eWt=$YhyyWe?nneKNYaUvqieyUY8aa+3$I)Ln>|D*~Jl z<4Ewq^?;t%9c#%ZRkJOfdR#GGrmDn)lZPgl@3BQD-x5QuuO@^qO-Ns^AG7mEQ3$gEkR)fL~Y3alDY;Pl&n}w-3HeGCb3d2QZUKx?qr>rf; z#Mg1qkMigkZBD4a+RR%=l<)8--dW2Ay=cvslI70vs?8_vtv%oGOZ za4iqRHSUYxDXJ{^+AIq+nny0%+*4Va-JLEbOgR(EEVz*Kn7CJIWsW$3PvO~GMqkz{ZqoU~wYPiMoO9t$Le-2q60_uwD`;<&V<9s)7P^2IFSOJ!r$Yj5Ci>kRS? zPk+I@I?EQ?J*F!&@WN_3l@|$AMNNKAHmq#klK$c#K#A762^-MdahNGs8T4H5k4hfJ zRWPh_TyaB(Dt@~o)m@mw-E$A4opDDRKp5)UbktNSHf;wal=;EX)RVithHKI5U~dv5 zEML6jw9DXf&g^HeIX?T}A-YbjHweU^tM5+J@7g2bmDlz3R~UO)12l!)NlQ-yRiGMp zl-KgM(YRCBbT&Tc8~|79hF07`a5K_oQXg^~Jc#OAq%MpdrgVS?BsR+;jG5TP5jf3Ffl+ zOXvV|59xBeeytPE*WLESN^7lfpZl;gQiB5O_KeD~>}Xn}3brqixTGo$F-0t~XP>gN zT4z2ra&~LS;HK_HtZg-6rY82HZlf}7Xl+%L`{MrxHbBY0^g>0um3@>UI$m$`q@GtQ z1M9?AoyS`1oT4wqQ?;v&4Oc}-Q&;G8d4V-+oJ|s{&pAoYoorN2Zr8bEvpfk5a3?-Y zAI${6CN&fE53C?}^pxyAdgGKG(F;;M;gVBvDN!bDDU};%#^hwAisVc@kz`Ra(m-wx zJt1h6gu9)UP&0G%Op)o2rtX0>y|#;ZnEX8+yPizK!%|4zxD{v(VOnH{7RazY4>epT zd1OjsQbH@v*pgIaMb-=PWg=C<7$xkuwZKq3!ZyaZ8cC_?Ak{6+n+1 zmLiOwlFjG_tUCf&5sQsb!!4BSLZ5VJqMxA3>T#5y^<*ZZxi;_VGUc$qbH}N*RA{lvE1e=RDr0^|+ z#V_zaUX*15k|^*dRgjHdNsQKpBuO^&gg1g&<|8)IA{Z4_wDLx?QRK}wg8~k_0gR%- z!21=oPOg(gFew&dm54>b8b#5-%Rxn`afpHdykO;9+a*b~ldwUwN-}mxCW6gsuuBKe zkVS#;icx|VmGBm@124I|FmJqhwX%+;tfp`IU;A?pxf<$~aij@!p=HeBri%52Z z(IbfxAr`ZX7wZg)*&*8ea#SUvNhYFC#Dp$`wZSR!ga}3=0U)mL5qS%a69J<{OlDOE zdPN?VEh@cyHw%O|9)}U+7Re@yM6BU!MIL)5D#T=v4M6|dWJLk1LvTy7065%6SrkR1 zS(d~GUM9TYAr78*S`<5PHu4T)^Ei&abT_Z^P6=eAohOQ5l4Lqn1l%^!Y&1zC!Nnx< zHltOr5S%-r5`mZ1IwIKZaFU{s_B=R1F@tQ7B!fykfMDSPy9Ggt;Lsauc+n&xc#Dcc z0B~Fhh>`$;T@s82A{qtBsPd9klpPj>T`;&MBG54sJ+@lWV6<3_B3Ny_{0WR%2+B>9cFnbADN)m$rx zZh^K{V75zTOrBBf^dB6bv=IksuT! z1R$;iU*co2wurxSoZ5~0cGcYX$_X)RjEu)*_yl>)+xFJ&x>C-p>!#W5+N<9Y z@4d=sbCm8C{)owA7cyDrBbz<}wg#xCq>Bz`7e*HohSN$zcUDmP=PuJN< zy@b*sDF06J4cCc&fupFumKV5D`cW=wLjNOKW@P61@ozL&W^++96mL%Dq4c+i^!HUF z$9R+;xng#XD*m!>M0JQ)IT|#TS(`h-shUbZ{v>kE!f%@DHMQtthUPfc2XDe(>YEZ{ zb}8A+Q8~pn_MMWdF$lTKHlQNz5c~eX#Op{xzZ}2`rEjXxYis&Z^q~`2_6OX?J{Zzj zb}-bpQRMPPP7CVnlVRGmVH^Ug0Fv+9s2c;{SZxz$A;%dBWfi!`z6fMwCs3Kul%dKw za{1#$x(zEE1|{_Ipcz@L$ZHS4Id@^F%O485OM5_j;4V5qrH=sJ1?OOZ>NA@g>3tMS z1Lt5S_64niFU~A-@qd^+Um!6d7d6O5bI}y6ZkB@9EvmX4BFF5TJGdF#Ol}Uhl3UNX z;*>zK>)eDaB0@0v*Q-n1xbj!5nF$9b-@^oMF)t~lAj=;)fB%Z@S4;g@%%0mP3gbU_ zt@JJ1fAjujeM;$b*Q2_fJbraanv@T1U$OuEN0y6yb7x=CFI}w*3lfCFN|;-$6h5Gdlcr2mJ|5RM#**QStS6R~}q>`hTvx z;;Pka*J8=zy(OEIl+Rqp?*9-jxU|j)Pylo zE%X=&K_cylINahtJLhjbp5HpZ6aJYio4Shoa@yP4yW|JjyRQ7&Gp@Vt489ibED3S# zn5V6TFE+&BPHjg_-*%uR%P4b8xeeS_?h0-{ciWh)e-Rjuk?nB|Ik%RUI>XtMOpuky zG=|x?W7yR$!?vkVZE4aegE6CH`|iGZ^*WQhX~n*SE9V(4d-hn2^Hv_*w_=kl zHnp67;O>1ZH_4dNa54F+)nT{f10wG~zM-{a`G#|sB=lG7@{ZQTl5;ocFR%`Utf%>S ztB82guZGA7?wG^WyuDTM@k9CIzrI3DL_Z{b+NG{&#GXTxZ*QLfGuj7lPp?|K>Z*Y| z(yJOQ#>I<`mWEa7I|gQ7m^f`!>W;zo86fn*UW1&oN20D=hWRfz3j1W@kAyWD@XDU?i4Dj{SYjDa{@DC8QM1+f1&+?d|vy7_8I7+x;*r26~HwPjs8o>>psTU7EbIF zuNJRnR+(L8ttj1sMoFN(q~!pmFC2{d-4oJ_S3kJxrgKOCx#P8m9=wd4sdU>dO7W4? z&f9u$fH(B6$gS!vKI045$7|t!rN?eowDWo|U9q;C%s=-NyB<83H(d7Vhkm!C_=sY* zcPr$q!9!aw7#RI$@2cF2UNXNXULUN}&cnDK1@7-&yW&zTY|}V-II1f>U;nlTlYwL3 zjTzIgcO=U!uZg;#;w0Z11^OW%j?d>^iuNa^-KO8b<#D)q9BwUNrJ;*q$Jp&0&xXIo z-^e~nl()`MpjL5}73`05y2S>VM+9 z)i-O$@{JBlctA1ya=wX+^l$o1MpKKUBluo87wkgSpY|?ScLAd6k za)Hk-`!)q@yFCn>yqR!;1RLeAP zZQZQd$(bt`cC2j8)^=&%(Z|f{RQb!#Ij8B7MzbR}aGiFcc1!npEP`a)^?eHEA> z5E#>yNiw>TR;s;W1FC$&4z|kW03WLQf(pZam;wmJo6}ic>c?BMxke?aB&IO@0h9cL z@A|#%`)>rHV^`lLipeUPS6MsKYxi6_Z*E`TFXnHV6?+>#B{zB7V~dt8UUt=`%Ws=$ zGf=wmJX^pfMy9v)%wC-9ADrH{JWTRq-`vYZrk}n3sr+@SIT~MfRhP34Y0CRL*Uz4{ zcJbV~J+4-N%?U1%zGQQDMx?df>Gn3-%?7LG!uCKsHjRXr#0@iJQMaeg*VR35)#Cap zzUVph)=7=G>4s@ppE|O#*DdJ-;&GS0#-sOE?{TX>WHvz1@_MpkpPQlSJ*sDHcLaLYENxz%vX zxmL33#epl3)}NkOEZKO2RdU;W@g@D+E;{(cuH9YT9=oGfTjOz^}1 zuzzBGC+j?x?dUNn;wty}7>%1c?xUxyc2jbf$sUMQw5(!V5bmfrwJ|4eoh(PQ3u7U^g09FvhQlnW z*h8Qj5hd-ZN)9s?#8Z7){Su<|^-CS4q~FdC00Yso9XCTU3-p0cu6Z;@m$XM zw81kMhQE@SdEnhcm;T_|Swq+CpS$J3pgAbFOI}y^x=;M(GkZVx&YJGXt}`0`Z*%Vf zA4hTbjql91>t*+v?xfT8Q$1Na-JQBl#g^qNcN-g7*v6I%xMPFcVH=E1GX{)lu^Bd2)ZIb^@v#%vMgOaynb(GPq9+38qe!&#@{i%qyEt z{B6RvCs*~K*l}L@^r>1iqhdK@&8zp_eBZuRO}KKFNOkiZ+Y+1cDSR2pOF)v~W%E6c z1nWTXzh>WgX?K0!wkz6~-{E3ax(cIJY?*)ft-CM3|C4!5p3U=$tJ~JknpiC@S$3N& zJyQ9(C03-@gsBx+w&5`@4NlduI+cLqiLV)zT$GIy>0BN;Qx{J%3}HgWvHQVr3`a&~ zjb((z(~X31_#>6Hck!(b+j$rF$6Q9P+E^+2j0GyC^rw$+S@EDNVE$y@1>r^Uan=>* zx36k((QiDkMXCr^bWH822(`C`BGsHhsb=@>lO`W{Ys%d_ap_M}IO&^8)Cb(_7gn}; zbdd3AJVsA}&m9Dl_-WwBm$1zR9pLz~OKWHK_gD2Dn7Q*xXUetZf$rJu>$}I-G&+6p z#tEAa-4NnbtWFi5x_IZq4{Yhf5kln789oYmz9^(B(Hy)M%@MUB1r|f_+r~uQEs(BF zhb-Wb<0$Rsy*Ry&9B1*2>n5#+=?&zV>~x5BEQ+K*+(Z%FMD!Y^s=(+ID~;8h(H-qy zH#^$3ac8`7b#H8|yLol{`OB^2;)}u;%-aJ_?AzBhE!5r~a!2Cvi2Ir&(tkHzx~;d# z?@HW#)08;FsbGoo=C^)&buY6f(@I_Dpxak~nn&Ydpw3s<+tj(b*;x?jrSELow{zx! zzN-HIS+$qK*6EdZ&!4n$LSw7XUK6Tm?pj(uaM>PH)%c4#nkU82ueQQj?Ha4Wp6&+oO_}@SR?FH~F>ZtgwO9qwk_nwFZ;j%lB_9%lJt2r%p$6$&MtO9@X+UOo?Woxf zbG#-t+%&aJi*2rDQ+FQTIkik)z_L|`PbKh}#3T-X9I$^&tT8+WJx=t20|x1Sls1!fLogOlF&Ije;uujhE)rrV`aH5O zf}~iR!6ip3HATneYi0g(Ihg>1qzn-pge1m6NCFZ^BFcgP^0jd)0WpS%Hp@1ghFic^ zkKBWpc>aCF499c=#+ke_%V39A0OO?0^0RO{Pp0sJ^mB*j>J(8_*iGU@{g@+jwA?WO z`%(#!y(pD{eKMVRRu*6qrv|j5i|IR+7y+SxW!EGl5Wb|V{y{LYzI;iybk!nNTX}QTibR)ab9tL;q4c1q z<>FaW*<{;dx?$)866tTR4*Y9rSygp)RoS*b2f^Iw2gA~-IA2xd69ivT6(9f9R(50S zwEkZ5&L2f%{Th--Se{1Qu*hM{IJS~_J4h@R#yb}bRlsfbl9WwwzVswm3|7pBGncLS z(K68TlWTj!Y7(o;w!0^QJ5*0rMb*lYClLvH#npr(7tlI}?tTrl)*>IEpQ+%i7w z45!`(*Ml#{jXUTXS6BSk;amWTm%Spr zf5$`8Z!hA3V!ujn;Je@4(*Nv%88Z$%+rQ+A3H$TB7Q0si@y0tq;VX2Z^n&#ME0^7{ zS5=@mpoFT${pj@9&{bXS2lBicmtVN{vR6s4{XUsMCQ(W1R|)jB)BtK$T+)-fDluzsBze*lSo0(6e;V z#G#W6ssOq`ZBZ(T6;X?BrFNj3D$vc%5IqJxYxJq8RAZdF^E6eC>Jp@~cp!3YHDAXT+0O7|gHi8*xS^S`Zj`*(YYKmBEw+AY%&wwY>QHLe5bW;xBCK zHJEyCJ76+Yz$N5JN(LW->GQ6>R`h;%rB}QbBW{5;V9FQQ0U2osrYWP3f}QqCox?8e zW~VkyJy6m!wP}M+KI28Q*esuylurG*sOVk5J&A8}-51gmnQ=kJ1+(D!k3vE$k_$0x zJ|C44^L&G|01eU)3I+&4%BgX1& zqkzP|0C#{7!5vKE>QDBsdvQ`t-@+NKYXY3&>Q8|1$**(ZVrJtQ*kTWZ;IU&l`wSWr z(b%>uzZTg#)CTZdI13^JI6D>t5{>Bv(ks%x?p)P(f!9-55t%mmR-n4`&eRVu2E)m7 zAT_WJ-wUDPIwsNo*z%c2>gr~j#A21M|FM@I`*8m!=YVZE_072v8@6qI9gPp*G(~Sm zW0+g^QOnMmn8?bGn{;9T8YO5y`sC@&f;#oSwun&~jm-1XDn=n_1@X8fcJ>&! zM!|^mZ%wvS+X^6CXrN0j1ZusFuGa|#MukeMUIO!ZO6Cl=6(fbvZ4Qqlj2?3zacX;q z6Md8;aWsu|$WwJCa_VBAL=kKCm|Ih7p}b8J983BjMi(rp%TIeuCNpP`u~j=InYkA4 zO-`vz*5zcAB+~S!Qw!2^Q6~H!qwpA`HL?X3tCU>EO@<@wz=%yUnaMZ@Q3}r**j)z9 z0S`}ZM<A*)YFa zqt=R`k~$6M{PY^29lX~KQdC(*84innE_Jg1$dP_5!qiNgRs%cL0j;PCg(fwre4Nq9 z`BY7l^4CKlm8fOmQ^0st&y9aQ0O1=;AY6ilQYPzjQcyM|LB)`6=9c|T?ooy$cQz-y zc{qU!@odmYvc*0LDS??JQ^e8>lc)|9D3{)XRL&7qSHhq*vmVa{3GC(o1HhHVvrS!u z&YzPa?|eXZVPLnDR*&X`zN}nHcxwz)3AKp$ZAqHC>{rFfm}pAJ`DG^JxwM9(#1;@U z;po3C&IZ<+Nun5ebD2LJYab!11B8R3U0hR(%T=><^1%4D`wr||JHAs@s!C|z*Cx=i zGqIwwv5BcFD5%u7hD<%ZJ*H5rwz8n0ifL-BT(RJWr+)g>4GU;ul@8UQySb*+PTW4d zvU2+Ni5E^+SEz5j;f7n$V)})*udkl6v8FKUcR2jDMOIs=rlPjCq9$as7S-Z?(ZZUI zQ>xeBzVz7owzl=h$oMbg{if`s|q06`+|laVe#AF2iVuR`ZxcE~tJu@s>@187Oi?pfH%3~nLeQHqdU zTv1q`(U3= z0DZ&ux?;oSAD@= zFkx@Os>80jo;uf*{wZWRz7YUMrReN$@T;X{I>hCV#J#`c(gO!B?c8~I<3fFH=ZmIg z%{}YZ^)xRtz1ULR-(TDkKfG!|Q5pWY%Ze6Y{EggJ=N6But+=*K)Gyq4cqje)bg)Y{ zhh1)qsX0k6hSVRUiE;TbsY;p-mAJ&n7lGcTD=OzH5PO;Y_HatFSw2D}iJELmM_0WJ zaedD_0XwHMHhFPMfV=o4P@F7w<8^P7QN`H<@7#lT)pw!Rq2+*#c*_#AwE5_J?;YK1 z`u#xy(c$zVDNc|sCYH@Z0^0C7A?7kW_c}IM~;r4Gd1p9>2R_<7*EUd9`bfc1%X@c=%|yHkKlvl66<>6@t$wL z;Hkr_PEo54^YQnN#`iA5sGHdEa+Dr7uue*(lIYQl67?e&ZX-B|*~4-e?Uhu!ECKM@ z3|qMyk#1s<@mq$kv)MDf`Mj`Q^@Nb1zAGQ10cZ74WIq}jPVU8_hio#HK%c_USGeQT zYV>hH8Md~M1SbxRT>qAEc|bH`)2_WI19FZoo8i(cp{ml@yu%#1k&%ww?9A@QEUrN? zMtlM$Qc4lOOa_T2vp$68Tr$7oh|H}jjr40x5uVjg$r;269HUTISOWU8uCOn&YpFvt zg{OHbQKSL&8kN*Pl*o%uc!5mpraa92(SEZ>sGm`PGtG)!IgD^Bw|+Wroj$|<)BhLGhiBM7 zyv!hRDuL@pfU~H4=J~;FP5(K%;(7a0{~TlIKmQM&DE;%SCHwA13`jaC3uJkr&)A}P zmT%@M>QB^H|M$O=|4A>+4pn*mwE$!|4!n`!kyXtgY#xoNA9iOolK&&U`}_93(^#`b zBb$sD3^IrE%9BXnFVi}+5KnYe z_Csf2 zV}<-LHLBEc84TPt>OOcChOj#)~X?ZxcahJn+Xc+XZU}Fz!PCkY1%zy1>AoE9p|$5;g@|4uS!f5^HvGSA&U0700
    V$fDV|Iw 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 li { position: relative; } +} +.@{fa-css-prefix}-li { + position: absolute; + left: -@fa-li-width; + width: @fa-li-width; + top: (2em / 14); + text-align: center; + &.@{fa-css-prefix}-lg { + left: -@fa-li-width + (4em / 14); + } +} diff --git a/assets/web/default/font-awesome/less/mixins.less b/assets/web/default/font-awesome/less/mixins.less new file mode 100644 index 000000000..19e5a6457 --- /dev/null +++ b/assets/web/default/font-awesome/less/mixins.less @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +.fa-icon-rotate(@degrees, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} + +.fa-icon-flip(@horiz, @vert, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); + -webkit-transform: scale(@horiz, @vert); + -moz-transform: scale(@horiz, @vert); + -ms-transform: scale(@horiz, @vert); + -o-transform: scale(@horiz, @vert); + transform: scale(@horiz, @vert); +} diff --git a/assets/web/default/font-awesome/less/path.less b/assets/web/default/font-awesome/less/path.less new file mode 100644 index 000000000..c5a691246 --- /dev/null +++ b/assets/web/default/font-awesome/less/path.less @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); + src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), + url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), + url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), + url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); +// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/assets/web/default/font-awesome/less/rotated-flipped.less b/assets/web/default/font-awesome/less/rotated-flipped.less new file mode 100644 index 000000000..8fff3a6c4 --- /dev/null +++ b/assets/web/default/font-awesome/less/rotated-flipped.less @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } diff --git a/assets/web/default/font-awesome/less/spinning.less b/assets/web/default/font-awesome/less/spinning.less new file mode 100644 index 000000000..60828fe5c --- /dev/null +++ b/assets/web/default/font-awesome/less/spinning.less @@ -0,0 +1,30 @@ +// Spinning Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@-ms-keyframes spin { + 0% { -ms-transform: rotate(0deg); } + 100% { -ms-transform: rotate(359deg); } +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} diff --git a/assets/web/default/font-awesome/less/stacked.less b/assets/web/default/font-awesome/less/stacked.less new file mode 100644 index 000000000..fc53fb0e7 --- /dev/null +++ b/assets/web/default/font-awesome/less/stacked.less @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/assets/web/default/font-awesome/less/variables.less b/assets/web/default/font-awesome/less/variables.less new file mode 100644 index 000000000..f40a555f0 --- /dev/null +++ b/assets/web/default/font-awesome/less/variables.less @@ -0,0 +1,381 @@ +// Variables +// -------------------------- + +@fa-font-path: "../fonts"; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts"; // for referencing Bootstrap CDN font files directly +@fa-css-prefix: fa; +@fa-version: "4.0.3"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: (30em / 14); + +@fa-var-glass: "\f000"; +@fa-var-music: "\f001"; +@fa-var-search: "\f002"; +@fa-var-envelope-o: "\f003"; +@fa-var-heart: "\f004"; +@fa-var-star: "\f005"; +@fa-var-star-o: "\f006"; +@fa-var-user: "\f007"; +@fa-var-film: "\f008"; +@fa-var-th-large: "\f009"; +@fa-var-th: "\f00a"; +@fa-var-th-list: "\f00b"; +@fa-var-check: "\f00c"; +@fa-var-times: "\f00d"; +@fa-var-search-plus: "\f00e"; +@fa-var-search-minus: "\f010"; +@fa-var-power-off: "\f011"; +@fa-var-signal: "\f012"; +@fa-var-cog: "\f013"; +@fa-var-trash-o: "\f014"; +@fa-var-home: "\f015"; +@fa-var-file-o: "\f016"; +@fa-var-clock-o: "\f017"; +@fa-var-road: "\f018"; +@fa-var-download: "\f019"; +@fa-var-arrow-circle-o-down: "\f01a"; +@fa-var-arrow-circle-o-up: "\f01b"; +@fa-var-inbox: "\f01c"; +@fa-var-play-circle-o: "\f01d"; +@fa-var-repeat: "\f01e"; +@fa-var-refresh: "\f021"; +@fa-var-list-alt: "\f022"; +@fa-var-lock: "\f023"; +@fa-var-flag: "\f024"; +@fa-var-headphones: "\f025"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-up: "\f028"; +@fa-var-qrcode: "\f029"; +@fa-var-barcode: "\f02a"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-print: "\f02f"; +@fa-var-camera: "\f030"; +@fa-var-font: "\f031"; +@fa-var-bold: "\f032"; +@fa-var-italic: "\f033"; +@fa-var-text-height: "\f034"; +@fa-var-text-width: "\f035"; +@fa-var-align-left: "\f036"; +@fa-var-align-center: "\f037"; +@fa-var-align-right: "\f038"; +@fa-var-align-justify: "\f039"; +@fa-var-list: "\f03a"; +@fa-var-outdent: "\f03b"; +@fa-var-indent: "\f03c"; +@fa-var-video-camera: "\f03d"; +@fa-var-picture-o: "\f03e"; +@fa-var-pencil: "\f040"; +@fa-var-map-marker: "\f041"; +@fa-var-adjust: "\f042"; +@fa-var-tint: "\f043"; +@fa-var-pencil-square-o: "\f044"; +@fa-var-share-square-o: "\f045"; +@fa-var-check-square-o: "\f046"; +@fa-var-arrows: "\f047"; +@fa-var-step-backward: "\f048"; +@fa-var-fast-backward: "\f049"; +@fa-var-backward: "\f04a"; +@fa-var-play: "\f04b"; +@fa-var-pause: "\f04c"; +@fa-var-stop: "\f04d"; +@fa-var-forward: "\f04e"; +@fa-var-fast-forward: "\f050"; +@fa-var-step-forward: "\f051"; +@fa-var-eject: "\f052"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-plus-circle: "\f055"; +@fa-var-minus-circle: "\f056"; +@fa-var-times-circle: "\f057"; +@fa-var-check-circle: "\f058"; +@fa-var-question-circle: "\f059"; +@fa-var-info-circle: "\f05a"; +@fa-var-crosshairs: "\f05b"; +@fa-var-times-circle-o: "\f05c"; +@fa-var-check-circle-o: "\f05d"; +@fa-var-ban: "\f05e"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrow-down: "\f063"; +@fa-var-share: "\f064"; +@fa-var-expand: "\f065"; +@fa-var-compress: "\f066"; +@fa-var-plus: "\f067"; +@fa-var-minus: "\f068"; +@fa-var-asterisk: "\f069"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-gift: "\f06b"; +@fa-var-leaf: "\f06c"; +@fa-var-fire: "\f06d"; +@fa-var-eye: "\f06e"; +@fa-var-eye-slash: "\f070"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-plane: "\f072"; +@fa-var-calendar: "\f073"; +@fa-var-random: "\f074"; +@fa-var-comment: "\f075"; +@fa-var-magnet: "\f076"; +@fa-var-chevron-up: "\f077"; +@fa-var-chevron-down: "\f078"; +@fa-var-retweet: "\f079"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-folder: "\f07b"; +@fa-var-folder-open: "\f07c"; +@fa-var-arrows-v: "\f07d"; +@fa-var-arrows-h: "\f07e"; +@fa-var-bar-chart-o: "\f080"; +@fa-var-twitter-square: "\f081"; +@fa-var-facebook-square: "\f082"; +@fa-var-camera-retro: "\f083"; +@fa-var-key: "\f084"; +@fa-var-cogs: "\f085"; +@fa-var-comments: "\f086"; +@fa-var-thumbs-o-up: "\f087"; +@fa-var-thumbs-o-down: "\f088"; +@fa-var-star-half: "\f089"; +@fa-var-heart-o: "\f08a"; +@fa-var-sign-out: "\f08b"; +@fa-var-linkedin-square: "\f08c"; +@fa-var-thumb-tack: "\f08d"; +@fa-var-external-link: "\f08e"; +@fa-var-sign-in: "\f090"; +@fa-var-trophy: "\f091"; +@fa-var-github-square: "\f092"; +@fa-var-upload: "\f093"; +@fa-var-lemon-o: "\f094"; +@fa-var-phone: "\f095"; +@fa-var-square-o: "\f096"; +@fa-var-bookmark-o: "\f097"; +@fa-var-phone-square: "\f098"; +@fa-var-twitter: "\f099"; +@fa-var-facebook: "\f09a"; +@fa-var-github: "\f09b"; +@fa-var-unlock: "\f09c"; +@fa-var-credit-card: "\f09d"; +@fa-var-rss: "\f09e"; +@fa-var-hdd-o: "\f0a0"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bell: "\f0f3"; +@fa-var-certificate: "\f0a3"; +@fa-var-hand-o-right: "\f0a4"; +@fa-var-hand-o-left: "\f0a5"; +@fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-o-down: "\f0a7"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-globe: "\f0ac"; +@fa-var-wrench: "\f0ad"; +@fa-var-tasks: "\f0ae"; +@fa-var-filter: "\f0b0"; +@fa-var-briefcase: "\f0b1"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-users: "\f0c0"; +@fa-var-link: "\f0c1"; +@fa-var-cloud: "\f0c2"; +@fa-var-flask: "\f0c3"; +@fa-var-scissors: "\f0c4"; +@fa-var-files-o: "\f0c5"; +@fa-var-paperclip: "\f0c6"; +@fa-var-floppy-o: "\f0c7"; +@fa-var-square: "\f0c8"; +@fa-var-bars: "\f0c9"; +@fa-var-list-ul: "\f0ca"; +@fa-var-list-ol: "\f0cb"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-underline: "\f0cd"; +@fa-var-table: "\f0ce"; +@fa-var-magic: "\f0d0"; +@fa-var-truck: "\f0d1"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-google-plus: "\f0d5"; +@fa-var-money: "\f0d6"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-up: "\f0d8"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-columns: "\f0db"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-asc: "\f0dd"; +@fa-var-sort-desc: "\f0de"; +@fa-var-envelope: "\f0e0"; +@fa-var-linkedin: "\f0e1"; +@fa-var-undo: "\f0e2"; +@fa-var-gavel: "\f0e3"; +@fa-var-tachometer: "\f0e4"; +@fa-var-comment-o: "\f0e5"; +@fa-var-comments-o: "\f0e6"; +@fa-var-bolt: "\f0e7"; +@fa-var-sitemap: "\f0e8"; +@fa-var-umbrella: "\f0e9"; +@fa-var-clipboard: "\f0ea"; +@fa-var-lightbulb-o: "\f0eb"; +@fa-var-exchange: "\f0ec"; +@fa-var-cloud-download: "\f0ed"; +@fa-var-cloud-upload: "\f0ee"; +@fa-var-user-md: "\f0f0"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-suitcase: "\f0f2"; +@fa-var-bell-o: "\f0a2"; +@fa-var-coffee: "\f0f4"; +@fa-var-cutlery: "\f0f5"; +@fa-var-file-text-o: "\f0f6"; +@fa-var-building-o: "\f0f7"; +@fa-var-hospital-o: "\f0f8"; +@fa-var-ambulance: "\f0f9"; +@fa-var-medkit: "\f0fa"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-beer: "\f0fc"; +@fa-var-h-square: "\f0fd"; +@fa-var-plus-square: "\f0fe"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-angle-down: "\f107"; +@fa-var-desktop: "\f108"; +@fa-var-laptop: "\f109"; +@fa-var-tablet: "\f10a"; +@fa-var-mobile: "\f10b"; +@fa-var-circle-o: "\f10c"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-spinner: "\f110"; +@fa-var-circle: "\f111"; +@fa-var-reply: "\f112"; +@fa-var-github-alt: "\f113"; +@fa-var-folder-o: "\f114"; +@fa-var-folder-open-o: "\f115"; +@fa-var-smile-o: "\f118"; +@fa-var-frown-o: "\f119"; +@fa-var-meh-o: "\f11a"; +@fa-var-gamepad: "\f11b"; +@fa-var-keyboard-o: "\f11c"; +@fa-var-flag-o: "\f11d"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-terminal: "\f120"; +@fa-var-code: "\f121"; +@fa-var-reply-all: "\f122"; +@fa-var-mail-reply-all: "\f122"; +@fa-var-star-half-o: "\f123"; +@fa-var-location-arrow: "\f124"; +@fa-var-crop: "\f125"; +@fa-var-code-fork: "\f126"; +@fa-var-chain-broken: "\f127"; +@fa-var-question: "\f128"; +@fa-var-info: "\f129"; +@fa-var-exclamation: "\f12a"; +@fa-var-superscript: "\f12b"; +@fa-var-subscript: "\f12c"; +@fa-var-eraser: "\f12d"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-shield: "\f132"; +@fa-var-calendar-o: "\f133"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-rocket: "\f135"; +@fa-var-maxcdn: "\f136"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-html5: "\f13b"; +@fa-var-css3: "\f13c"; +@fa-var-anchor: "\f13d"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-bullseye: "\f140"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-rss-square: "\f143"; +@fa-var-play-circle: "\f144"; +@fa-var-ticket: "\f145"; +@fa-var-minus-square: "\f146"; +@fa-var-minus-square-o: "\f147"; +@fa-var-level-up: "\f148"; +@fa-var-level-down: "\f149"; +@fa-var-check-square: "\f14a"; +@fa-var-pencil-square: "\f14b"; +@fa-var-external-link-square: "\f14c"; +@fa-var-share-square: "\f14d"; +@fa-var-compass: "\f14e"; +@fa-var-caret-square-o-down: "\f150"; +@fa-var-caret-square-o-up: "\f151"; +@fa-var-caret-square-o-right: "\f152"; +@fa-var-eur: "\f153"; +@fa-var-gbp: "\f154"; +@fa-var-usd: "\f155"; +@fa-var-inr: "\f156"; +@fa-var-jpy: "\f157"; +@fa-var-rub: "\f158"; +@fa-var-krw: "\f159"; +@fa-var-btc: "\f15a"; +@fa-var-file: "\f15b"; +@fa-var-file-text: "\f15c"; +@fa-var-sort-alpha-asc: "\f15d"; +@fa-var-sort-alpha-desc: "\f15e"; +@fa-var-sort-amount-asc: "\f160"; +@fa-var-sort-amount-desc: "\f161"; +@fa-var-sort-numeric-asc: "\f162"; +@fa-var-sort-numeric-desc: "\f163"; +@fa-var-thumbs-up: "\f164"; +@fa-var-thumbs-down: "\f165"; +@fa-var-youtube-square: "\f166"; +@fa-var-youtube: "\f167"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-youtube-play: "\f16a"; +@fa-var-dropbox: "\f16b"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-instagram: "\f16d"; +@fa-var-flickr: "\f16e"; +@fa-var-adn: "\f170"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitbucket-square: "\f172"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-long-arrow-down: "\f175"; +@fa-var-long-arrow-up: "\f176"; +@fa-var-long-arrow-left: "\f177"; +@fa-var-long-arrow-right: "\f178"; +@fa-var-apple: "\f179"; +@fa-var-windows: "\f17a"; +@fa-var-android: "\f17b"; +@fa-var-linux: "\f17c"; +@fa-var-dribbble: "\f17d"; +@fa-var-skype: "\f17e"; +@fa-var-foursquare: "\f180"; +@fa-var-trello: "\f181"; +@fa-var-female: "\f182"; +@fa-var-male: "\f183"; +@fa-var-gittip: "\f184"; +@fa-var-sun-o: "\f185"; +@fa-var-moon-o: "\f186"; +@fa-var-archive: "\f187"; +@fa-var-bug: "\f188"; +@fa-var-vk: "\f189"; +@fa-var-weibo: "\f18a"; +@fa-var-renren: "\f18b"; +@fa-var-pagelines: "\f18c"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-arrow-circle-o-right: "\f18e"; +@fa-var-arrow-circle-o-left: "\f190"; +@fa-var-caret-square-o-left: "\f191"; +@fa-var-dot-circle-o: "\f192"; +@fa-var-wheelchair: "\f193"; +@fa-var-vimeo-square: "\f194"; +@fa-var-try: "\f195"; +@fa-var-plus-square-o: "\f196"; + diff --git a/assets/web/default/font-awesome/scss/_bordered-pulled.scss b/assets/web/default/font-awesome/scss/_bordered-pulled.scss new file mode 100644 index 000000000..9d3fdf3a0 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_bordered-pulled.scss @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/assets/web/default/font-awesome/scss/_core.scss b/assets/web/default/font-awesome/scss/_core.scss new file mode 100644 index 000000000..861ccd9dc --- /dev/null +++ b/assets/web/default/font-awesome/scss/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/assets/web/default/font-awesome/scss/_fixed-width.scss b/assets/web/default/font-awesome/scss/_fixed-width.scss new file mode 100644 index 000000000..b221c9813 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/assets/web/default/font-awesome/scss/_icons.scss b/assets/web/default/font-awesome/scss/_icons.scss new file mode 100644 index 000000000..7490cf361 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_icons.scss @@ -0,0 +1,412 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before { content: $fa-var-bar-chart-o; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-mail-reply-all:before { content: $fa-var-mail-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } diff --git a/assets/web/default/font-awesome/scss/_larger.scss b/assets/web/default/font-awesome/scss/_larger.scss new file mode 100644 index 000000000..41e9a8184 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/assets/web/default/font-awesome/scss/_list.scss b/assets/web/default/font-awesome/scss/_list.scss new file mode 100644 index 000000000..7d1e4d54d --- /dev/null +++ b/assets/web/default/font-awesome/scss/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/assets/web/default/font-awesome/scss/_mixins.scss b/assets/web/default/font-awesome/scss/_mixins.scss new file mode 100644 index 000000000..9f555963f --- /dev/null +++ b/assets/web/default/font-awesome/scss/_mixins.scss @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +@mixin fa-icon-rotate($degrees, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation); + -webkit-transform: rotate($degrees); + -moz-transform: rotate($degrees); + -ms-transform: rotate($degrees); + -o-transform: rotate($degrees); + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation); + -webkit-transform: scale($horiz, $vert); + -moz-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + -o-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} diff --git a/assets/web/default/font-awesome/scss/_path.scss b/assets/web/default/font-awesome/scss/_path.scss new file mode 100644 index 000000000..fd21c3515 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_path.scss @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); + //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/assets/web/default/font-awesome/scss/_rotated-flipped.scss b/assets/web/default/font-awesome/scss/_rotated-flipped.scss new file mode 100644 index 000000000..343fa5507 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_rotated-flipped.scss @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } diff --git a/assets/web/default/font-awesome/scss/_spinning.scss b/assets/web/default/font-awesome/scss/_spinning.scss new file mode 100644 index 000000000..ba1e4f162 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_spinning.scss @@ -0,0 +1,30 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@-ms-keyframes spin { + 0% { -ms-transform: rotate(0deg); } + 100% { -ms-transform: rotate(359deg); } +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} diff --git a/assets/web/default/font-awesome/scss/_stacked.scss b/assets/web/default/font-awesome/scss/_stacked.scss new file mode 100644 index 000000000..aef740366 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/assets/web/default/font-awesome/scss/_variables.scss b/assets/web/default/font-awesome/scss/_variables.scss new file mode 100644 index 000000000..2d6e076a7 --- /dev/null +++ b/assets/web/default/font-awesome/scss/_variables.scss @@ -0,0 +1,381 @@ +// Variables +// -------------------------- + +$fa-font-path: "../fonts" !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.0.3" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-glass: "\f000"; +$fa-var-music: "\f001"; +$fa-var-search: "\f002"; +$fa-var-envelope-o: "\f003"; +$fa-var-heart: "\f004"; +$fa-var-star: "\f005"; +$fa-var-star-o: "\f006"; +$fa-var-user: "\f007"; +$fa-var-film: "\f008"; +$fa-var-th-large: "\f009"; +$fa-var-th: "\f00a"; +$fa-var-th-list: "\f00b"; +$fa-var-check: "\f00c"; +$fa-var-times: "\f00d"; +$fa-var-search-plus: "\f00e"; +$fa-var-search-minus: "\f010"; +$fa-var-power-off: "\f011"; +$fa-var-signal: "\f012"; +$fa-var-cog: "\f013"; +$fa-var-trash-o: "\f014"; +$fa-var-home: "\f015"; +$fa-var-file-o: "\f016"; +$fa-var-clock-o: "\f017"; +$fa-var-road: "\f018"; +$fa-var-download: "\f019"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-inbox: "\f01c"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-repeat: "\f01e"; +$fa-var-refresh: "\f021"; +$fa-var-list-alt: "\f022"; +$fa-var-lock: "\f023"; +$fa-var-flag: "\f024"; +$fa-var-headphones: "\f025"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-up: "\f028"; +$fa-var-qrcode: "\f029"; +$fa-var-barcode: "\f02a"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-print: "\f02f"; +$fa-var-camera: "\f030"; +$fa-var-font: "\f031"; +$fa-var-bold: "\f032"; +$fa-var-italic: "\f033"; +$fa-var-text-height: "\f034"; +$fa-var-text-width: "\f035"; +$fa-var-align-left: "\f036"; +$fa-var-align-center: "\f037"; +$fa-var-align-right: "\f038"; +$fa-var-align-justify: "\f039"; +$fa-var-list: "\f03a"; +$fa-var-outdent: "\f03b"; +$fa-var-indent: "\f03c"; +$fa-var-video-camera: "\f03d"; +$fa-var-picture-o: "\f03e"; +$fa-var-pencil: "\f040"; +$fa-var-map-marker: "\f041"; +$fa-var-adjust: "\f042"; +$fa-var-tint: "\f043"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-share-square-o: "\f045"; +$fa-var-check-square-o: "\f046"; +$fa-var-arrows: "\f047"; +$fa-var-step-backward: "\f048"; +$fa-var-fast-backward: "\f049"; +$fa-var-backward: "\f04a"; +$fa-var-play: "\f04b"; +$fa-var-pause: "\f04c"; +$fa-var-stop: "\f04d"; +$fa-var-forward: "\f04e"; +$fa-var-fast-forward: "\f050"; +$fa-var-step-forward: "\f051"; +$fa-var-eject: "\f052"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-plus-circle: "\f055"; +$fa-var-minus-circle: "\f056"; +$fa-var-times-circle: "\f057"; +$fa-var-check-circle: "\f058"; +$fa-var-question-circle: "\f059"; +$fa-var-info-circle: "\f05a"; +$fa-var-crosshairs: "\f05b"; +$fa-var-times-circle-o: "\f05c"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-ban: "\f05e"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrow-down: "\f063"; +$fa-var-share: "\f064"; +$fa-var-expand: "\f065"; +$fa-var-compress: "\f066"; +$fa-var-plus: "\f067"; +$fa-var-minus: "\f068"; +$fa-var-asterisk: "\f069"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-gift: "\f06b"; +$fa-var-leaf: "\f06c"; +$fa-var-fire: "\f06d"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-plane: "\f072"; +$fa-var-calendar: "\f073"; +$fa-var-random: "\f074"; +$fa-var-comment: "\f075"; +$fa-var-magnet: "\f076"; +$fa-var-chevron-up: "\f077"; +$fa-var-chevron-down: "\f078"; +$fa-var-retweet: "\f079"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-folder: "\f07b"; +$fa-var-folder-open: "\f07c"; +$fa-var-arrows-v: "\f07d"; +$fa-var-arrows-h: "\f07e"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-twitter-square: "\f081"; +$fa-var-facebook-square: "\f082"; +$fa-var-camera-retro: "\f083"; +$fa-var-key: "\f084"; +$fa-var-cogs: "\f085"; +$fa-var-comments: "\f086"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-o-down: "\f088"; +$fa-var-star-half: "\f089"; +$fa-var-heart-o: "\f08a"; +$fa-var-sign-out: "\f08b"; +$fa-var-linkedin-square: "\f08c"; +$fa-var-thumb-tack: "\f08d"; +$fa-var-external-link: "\f08e"; +$fa-var-sign-in: "\f090"; +$fa-var-trophy: "\f091"; +$fa-var-github-square: "\f092"; +$fa-var-upload: "\f093"; +$fa-var-lemon-o: "\f094"; +$fa-var-phone: "\f095"; +$fa-var-square-o: "\f096"; +$fa-var-bookmark-o: "\f097"; +$fa-var-phone-square: "\f098"; +$fa-var-twitter: "\f099"; +$fa-var-facebook: "\f09a"; +$fa-var-github: "\f09b"; +$fa-var-unlock: "\f09c"; +$fa-var-credit-card: "\f09d"; +$fa-var-rss: "\f09e"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bell: "\f0f3"; +$fa-var-certificate: "\f0a3"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-globe: "\f0ac"; +$fa-var-wrench: "\f0ad"; +$fa-var-tasks: "\f0ae"; +$fa-var-filter: "\f0b0"; +$fa-var-briefcase: "\f0b1"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-users: "\f0c0"; +$fa-var-link: "\f0c1"; +$fa-var-cloud: "\f0c2"; +$fa-var-flask: "\f0c3"; +$fa-var-scissors: "\f0c4"; +$fa-var-files-o: "\f0c5"; +$fa-var-paperclip: "\f0c6"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-square: "\f0c8"; +$fa-var-bars: "\f0c9"; +$fa-var-list-ul: "\f0ca"; +$fa-var-list-ol: "\f0cb"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-underline: "\f0cd"; +$fa-var-table: "\f0ce"; +$fa-var-magic: "\f0d0"; +$fa-var-truck: "\f0d1"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-google-plus: "\f0d5"; +$fa-var-money: "\f0d6"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-up: "\f0d8"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-columns: "\f0db"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-asc: "\f0dd"; +$fa-var-sort-desc: "\f0de"; +$fa-var-envelope: "\f0e0"; +$fa-var-linkedin: "\f0e1"; +$fa-var-undo: "\f0e2"; +$fa-var-gavel: "\f0e3"; +$fa-var-tachometer: "\f0e4"; +$fa-var-comment-o: "\f0e5"; +$fa-var-comments-o: "\f0e6"; +$fa-var-bolt: "\f0e7"; +$fa-var-sitemap: "\f0e8"; +$fa-var-umbrella: "\f0e9"; +$fa-var-clipboard: "\f0ea"; +$fa-var-lightbulb-o: "\f0eb"; +$fa-var-exchange: "\f0ec"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-user-md: "\f0f0"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-suitcase: "\f0f2"; +$fa-var-bell-o: "\f0a2"; +$fa-var-coffee: "\f0f4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-building-o: "\f0f7"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-ambulance: "\f0f9"; +$fa-var-medkit: "\f0fa"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-beer: "\f0fc"; +$fa-var-h-square: "\f0fd"; +$fa-var-plus-square: "\f0fe"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-angle-down: "\f107"; +$fa-var-desktop: "\f108"; +$fa-var-laptop: "\f109"; +$fa-var-tablet: "\f10a"; +$fa-var-mobile: "\f10b"; +$fa-var-circle-o: "\f10c"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-spinner: "\f110"; +$fa-var-circle: "\f111"; +$fa-var-reply: "\f112"; +$fa-var-github-alt: "\f113"; +$fa-var-folder-o: "\f114"; +$fa-var-folder-open-o: "\f115"; +$fa-var-smile-o: "\f118"; +$fa-var-frown-o: "\f119"; +$fa-var-meh-o: "\f11a"; +$fa-var-gamepad: "\f11b"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-flag-o: "\f11d"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-terminal: "\f120"; +$fa-var-code: "\f121"; +$fa-var-reply-all: "\f122"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-star-half-o: "\f123"; +$fa-var-location-arrow: "\f124"; +$fa-var-crop: "\f125"; +$fa-var-code-fork: "\f126"; +$fa-var-chain-broken: "\f127"; +$fa-var-question: "\f128"; +$fa-var-info: "\f129"; +$fa-var-exclamation: "\f12a"; +$fa-var-superscript: "\f12b"; +$fa-var-subscript: "\f12c"; +$fa-var-eraser: "\f12d"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-shield: "\f132"; +$fa-var-calendar-o: "\f133"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-rocket: "\f135"; +$fa-var-maxcdn: "\f136"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-html5: "\f13b"; +$fa-var-css3: "\f13c"; +$fa-var-anchor: "\f13d"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-bullseye: "\f140"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-rss-square: "\f143"; +$fa-var-play-circle: "\f144"; +$fa-var-ticket: "\f145"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-level-up: "\f148"; +$fa-var-level-down: "\f149"; +$fa-var-check-square: "\f14a"; +$fa-var-pencil-square: "\f14b"; +$fa-var-external-link-square: "\f14c"; +$fa-var-share-square: "\f14d"; +$fa-var-compass: "\f14e"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-eur: "\f153"; +$fa-var-gbp: "\f154"; +$fa-var-usd: "\f155"; +$fa-var-inr: "\f156"; +$fa-var-jpy: "\f157"; +$fa-var-rub: "\f158"; +$fa-var-krw: "\f159"; +$fa-var-btc: "\f15a"; +$fa-var-file: "\f15b"; +$fa-var-file-text: "\f15c"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-thumbs-up: "\f164"; +$fa-var-thumbs-down: "\f165"; +$fa-var-youtube-square: "\f166"; +$fa-var-youtube: "\f167"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-youtube-play: "\f16a"; +$fa-var-dropbox: "\f16b"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-instagram: "\f16d"; +$fa-var-flickr: "\f16e"; +$fa-var-adn: "\f170"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-apple: "\f179"; +$fa-var-windows: "\f17a"; +$fa-var-android: "\f17b"; +$fa-var-linux: "\f17c"; +$fa-var-dribbble: "\f17d"; +$fa-var-skype: "\f17e"; +$fa-var-foursquare: "\f180"; +$fa-var-trello: "\f181"; +$fa-var-female: "\f182"; +$fa-var-male: "\f183"; +$fa-var-gittip: "\f184"; +$fa-var-sun-o: "\f185"; +$fa-var-moon-o: "\f186"; +$fa-var-archive: "\f187"; +$fa-var-bug: "\f188"; +$fa-var-vk: "\f189"; +$fa-var-weibo: "\f18a"; +$fa-var-renren: "\f18b"; +$fa-var-pagelines: "\f18c"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-wheelchair: "\f193"; +$fa-var-vimeo-square: "\f194"; +$fa-var-try: "\f195"; +$fa-var-plus-square-o: "\f196"; + diff --git a/assets/web/default/font-awesome/scss/font-awesome.scss b/assets/web/default/font-awesome/scss/font-awesome.scss new file mode 100644 index 000000000..96d2f2225 --- /dev/null +++ b/assets/web/default/font-awesome/scss/font-awesome.scss @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "spinning"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; diff --git a/assets/web/default/forms.html b/assets/web/default/forms.html new file mode 100644 index 000000000..2b1807b3b --- /dev/null +++ b/assets/web/default/forms.html @@ -0,0 +1,365 @@ + + + + + + + + + Forms - SB Admin + + + + + + + + + + + +
    + + + + +
    + +
    +
    +

    Forms Enter Your Data

    + +
    + + Visit Bootstrap's Form Documentation for more information. +
    +
    +
    + +
    +
    + +
    + +
    + + +

    Example block-level help text here.

    +
    + +
    + + +
    + +
    + +

    email@example.com

    +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + + + +
    + +
    + +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + + + +
    + +
    + + +
    + +
    + + +
    + + + + +
    + +
    +
    +

    Disabled Form States

    + +
    + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    + + + +
    + +
    + +

    Form Validation

    + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +

    Input Groups

    + +
    + +
    + @ + +
    + +
    + + .00 +
    + +
    + + +
    + +
    + $ + + .00 +
    + +
    + + + + +
    + +
    + +

    For complete documentation, please visit Bootstrap's Form Documentation.

    + +
    +
    + +
    + +
    + + + + + + + \ No newline at end of file diff --git a/assets/web/default/index.html b/assets/web/default/index.html new file mode 100644 index 000000000..9da9cd4bc --- /dev/null +++ b/assets/web/default/index.html @@ -0,0 +1,421 @@ + + + + + + + + + Dashboard - SB Admin + + + + + + + + + + + + + +
    + + + + +
    + +
    +
    +

    Dashboard Statistics Overview

    + +
    + + Welcome to SB Admin by Start Bootstrap! Feel free to use this template for your admin needs! We are using a few different plugins to handle the dynamic tables and charts, so make sure you check out the necessary documentation links provided. +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +

    456

    +

    New Mentions!

    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +

    12

    +

    To-Do Items

    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +

    18

    +

    Crawl Errors

    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +

    56

    +

    New Orders!

    +
    +
    +
    + + + +
    +
    +
    + +
    +
    +
    +
    +

    Traffic Statistics: October 1, 2013 - October 31, 2013

    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Traffic Sources: October 1, 2013 - October 31, 2013

    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +

    Recent Transactions

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Order # Order Date Order Time Amount (USD)
    332610/21/20133:29 PM$321.33
    332510/21/20133:20 PM$234.34
    332410/21/20133:03 PM$724.17
    332310/21/20133:00 PM$23.71
    332210/21/20132:49 PM$8345.23
    332110/21/20132:23 PM$245.12
    332010/21/20132:15 PM$5663.54
    331910/21/20132:13 PM$943.45
    +
    + +
    +
    +
    +
    + +
    + + + +
    + + + + + + + + + + + + + + diff --git a/assets/web/default/js/bootstrap.js b/assets/web/default/js/bootstrap.js new file mode 100644 index 000000000..39ec4710e --- /dev/null +++ b/assets/web/default/js/bootstrap.js @@ -0,0 +1,1951 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap requires jQuery') } + +/* ======================================================================== + * Bootstrap: transition.js v3.1.0 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd otransitionend', + 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.1.0 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.1.0 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.1.0 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + if ($next.hasClass('active')) return this.sliding = false + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) + }) + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.1.0 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.1.0 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $(' + + + + +@EndSection \ No newline at end of file From fd4f5d6743a2a107c0efcb6298be04b59059acd6 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 15:00:27 +0300 Subject: [PATCH 043/230] Updated packages. --- src/CoiniumServ/App.config | 2 +- src/CoiniumServ/CoiniumServ.csproj | 12 +- src/CoiniumServ/packages.config | 6 +- .../default/{index.sshtml => index.2sshtml} | 0 src/Tests/Mining/Pools/PoolTests.cs | 270 ++---------------- src/Tests/Tests.csproj | 2 +- src/Tests/packages.config | 2 +- 7 files changed, 28 insertions(+), 266 deletions(-) rename src/CoiniumServ/web/default/{index.sshtml => index.2sshtml} (100%) diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index 2776765a8..5949be067 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -1,6 +1,6 @@  - + diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 45a2df2de..7299b7458 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -62,13 +62,13 @@ False ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll - + False - ..\..\build\packages\Nancy.0.23.0\lib\net40\Nancy.dll + ..\..\build\packages\Nancy.0.23.1\lib\net40\Nancy.dll - + False - ..\..\build\packages\Nancy.Hosting.Self.0.23.0\lib\net40\Nancy.Hosting.Self.dll + ..\..\build\packages\Nancy.Hosting.Self.0.23.1\lib\net40\Nancy.Hosting.Self.dll False @@ -84,7 +84,7 @@ False - ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net45\StackExchange.Redis.dll + ..\..\build\packages\StackExchange.Redis.1.0.322\lib\net45\StackExchange.Redis.dll @@ -1055,7 +1055,7 @@ PreserveNewest - + PreserveNewest diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index f7ce10dae..528c488b1 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,9 +4,9 @@ - - + + - + \ No newline at end of file diff --git a/src/CoiniumServ/web/default/index.sshtml b/src/CoiniumServ/web/default/index.2sshtml similarity index 100% rename from src/CoiniumServ/web/default/index.sshtml rename to src/CoiniumServ/web/default/index.2sshtml diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index e5472c109..8c4e8e5ea 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -27,13 +27,13 @@ using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; using Coinium.Mining.Pools.Config; +using Coinium.Mining.Pools.Statistics; using Coinium.Mining.Shares; using Coinium.Payments; using Coinium.Persistance; using Coinium.Server; using Coinium.Server.Mining; using Coinium.Service; -using Coinium.Utils.Configuration; using NSubstitute; using Should.Fluent; using Xunit; @@ -52,6 +52,8 @@ public class PoolTests private readonly IMinerManagerFactory _minerManagerFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; + private readonly IPoolStatisticsFactory _poolStatisticsFactory; + private readonly IBlockStatisticsFactory _blockStatisticsFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -63,6 +65,8 @@ public class PoolTests private readonly IMiningServer _miningServer; private readonly IRpcService _rpcService; private readonly IPaymentProcessor _paymentProcessor; + private readonly IPoolStatistics _poolStatistics; + private readonly IBlockStatistics _blockStatistics; /// /// Initialize mock objects. @@ -78,6 +82,8 @@ public PoolTests() _serviceFactory = Substitute.For(); _storageFactory = Substitute.For(); _paymentProcessorFactory = Substitute.For(); + _poolStatisticsFactory = Substitute.For(); + _blockStatisticsFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -88,6 +94,8 @@ public PoolTests() _rpcService = Substitute.For(); _storage = Substitute.For(); _paymentProcessor = Substitute.For(); + _poolStatistics = Substitute.For(); + _blockStatistics = Substitute.For(); } /// @@ -106,263 +114,15 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _jobManagerFactory, _shareManagerFactory, _storageFactory, - _paymentProcessorFactory + _paymentProcessorFactory, + _poolStatisticsFactory, + _blockStatisticsFactory ); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); } - - /// - /// Tests pool constructor with null HashAlgorithm, should trow exception. - /// - [Fact] - public void ConstructorTest_NullHashAlgorithmFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - null, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IHashAlgorithmFactory"); - } - - /// - /// Tests pool constructor with null ServerFactory, should trow exception. - /// - [Fact] - public void ConstructorTest_NullServerFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - null, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IServerFactory"); - } - - /// - /// Tests pool constructor with null ServiceFactory, should trow exception. - /// - [Fact] - public void ConstructorTest_NullServiceFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - null, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IServiceFactory"); - } - - /// - /// Tests pool constructor with null DaemonClient, should trow exception. - /// - [Fact] - public void ConstructorTest_NullDaemonClient_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - null, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IDaemonClient"); - } - - /// - /// Tests pool constructor with null IMinerManagerFactory, should trow exception. - /// - [Fact] - public void ConstructorTest_NullMinerManagerFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - null, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IMinerManagerFactory"); - } - - /// - /// Tests pool constructor with null JobManager, should trow exception. - /// - [Fact] - public void ConstructorTest_NullJobTrackerFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - null, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IJobTrackerFactory"); - } - - /// - /// Tests pool constructor with null JobManager, should trow exception. - /// - [Fact] - public void ConstructorTest_NullJobManagerFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - null, - _shareManagerFactory, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IJobManagerFactory"); - } - - /// - /// Tests pool constructor with null ShareManager, should trow exception. - /// - [Fact] - public void ConstructorTest_NullShareManagerFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - null, - _storageFactory, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IShareManagerFactory"); - } - - /// - /// Tests pool constructor with null StorageFactory, should trow exception. - /// - [Fact] - public void ConstructorTest_NullStorageFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - null, - _paymentProcessorFactory - ); - }); - - ex.Message.Should().Contain("IStorageFactory"); - } - - /// - /// Tests pool constructor with null StorageFactory, should trow exception. - /// - [Fact] - public void ConstructorTest_NullPaymentProcessorFactory_ShouldThrow() - { - Exception ex = Assert.Throws(() => - { - var pool = new Coinium.Mining.Pools.Pool( - _hashAlgorithmFactory, - _serverFactory, - _serviceFactory, - _daemonClient, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, - _storageFactory, - null - ); - }); - - ex.Message.Should().Contain("IPaymentProcessorFactory"); - } - + /// /// Initializes pool with all valid parameters, should succeed. /// @@ -379,7 +139,9 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _jobManagerFactory, _shareManagerFactory, _storageFactory, - _paymentProcessorFactory + _paymentProcessorFactory, + _poolStatisticsFactory, + _blockStatisticsFactory ); pool.Should().Not.Be.Null(); diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index e62d876b8..a6c06f26d 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -53,7 +53,7 @@ False - ..\..\build\packages\StackExchange.Redis.1.0.320\lib\net45\StackExchange.Redis.dll + ..\..\build\packages\StackExchange.Redis.1.0.322\lib\net45\StackExchange.Redis.dll diff --git a/src/Tests/packages.config b/src/Tests/packages.config index 232b2251b..fdf0604c7 100644 --- a/src/Tests/packages.config +++ b/src/Tests/packages.config @@ -4,6 +4,6 @@ - + \ No newline at end of file From 397bace89d79fa971dec2c3da50e3577dc3a8463 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 15:45:32 +0300 Subject: [PATCH 044/230] Added nancy.viewengines.razor. --- src/CoiniumServ/App.config | 19 ++++++++++++++++++- src/CoiniumServ/CoiniumServ.csproj | 21 ++++++++++++++++----- src/CoiniumServ/packages.config | 6 ++++-- src/CoiniumServ/web.config | 25 +++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 src/CoiniumServ/web.config diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index 5949be067..d396d43fa 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -1,5 +1,14 @@  + + +
    + + + + + + @@ -20,4 +29,12 @@ - + + + + + + + + + diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 7299b7458..a750f3414 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -62,13 +62,16 @@ False ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll - + False - ..\..\build\packages\Nancy.0.23.1\lib\net40\Nancy.dll + ..\..\build\packages\Nancy.0.23.0\lib\net40\Nancy.dll - + False - ..\..\build\packages\Nancy.Hosting.Self.0.23.1\lib\net40\Nancy.Hosting.Self.dll + ..\..\build\packages\Nancy.Hosting.Self.0.23.0\lib\net40\Nancy.Hosting.Self.dll + + + ..\..\build\packages\Nancy.Viewengines.Razor.0.23.0\lib\net40\Nancy.ViewEngines.Razor.dll False @@ -90,6 +93,10 @@ + + False + ..\..\build\packages\Microsoft.AspNet.Razor.3.2.0\lib\net45\System.Web.Razor.dll + @@ -870,6 +877,7 @@ + PreserveNewest @@ -1072,7 +1080,10 @@ - +if $(ConfigurationName) == Debug ( +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" +) + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CoiniumServ/web/default/layout.sshtml b/src/CoiniumServ/web/default/layout2.sshtml similarity index 100% rename from src/CoiniumServ/web/default/layout.sshtml rename to src/CoiniumServ/web/default/layout2.sshtml From f607cde530f626875589f2b0790ddfc789342821 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 16:22:45 +0300 Subject: [PATCH 046/230] Testing a fix for nancy & razor over mono: https://github.com/NancyFx/Nancy/issues/1082 --- src/CoiniumServ/CoiniumServ.csproj | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index ac0368e73..0723ca9a1 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -1084,7 +1084,16 @@ - + + + + + + + + + + if $(ConfigurationName) == Debug ( xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" From 47a84371dd1881830cec22ab2a496334c1bfc677 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 16:27:07 +0300 Subject: [PATCH 047/230] yet another nancy & razor for mono fix. --- src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs b/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs index bfb14f805..86713dc97 100644 --- a/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs +++ b/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs @@ -31,7 +31,7 @@ public class CustomRootPathProvider : IRootPathProvider { public string GetRootPath() { - var path = string.Format("{0}\\web\\default", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); + var path = string.Format("{0}/web/default", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); return path; } } From 797ed00c4debbd5311e194bbf220c32a4eaf8686 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 19:41:26 +0300 Subject: [PATCH 048/230] Added global & per algorithm stats. Added web-tests project and configuration for jmeter & httprider. --- build/CoiniumServ.sln | 22 + build/Local.testsettings | 11 + contrib/capture/fastcoin.pcapng | Bin 404236 -> 0 bytes contrib/capture/litecoin-testnet-mini.pcapng | Bin 57352 -> 0 bytes contrib/capture/litecoin-testnet.pcapng | Bin 440024 -> 0 bytes .../sample-config.conf => coin/sample.conf} | 4 +- contrib/performance-tests/Readme.md | 4 + contrib/performance-tests/web.jmx | 153 ++++++ contrib/performance-tests/web.rider | Bin 0 -> 44451 bytes src/CoiniumServ/CoiniumServ.csproj | 35 +- src/CoiniumServ/Mining/Pools/IPoolManager.cs | 3 + src/CoiniumServ/Mining/Pools/PoolManager.cs | 10 +- .../Pools/Statistics/GlobalStatistics.cs | 91 ++++ .../Statistics/GlobalStatisticsFactory.cs | 49 ++ .../Pools/Statistics/IGlobalStatistics.cs | 39 ++ .../Statistics/IGlobalStatisticsFactory.cs | 30 ++ .../Statistics/IPerAlgorithmStatistics.cs | 40 ++ .../Statistics/PerAlgorithmStatistics.cs | 44 ++ .../Net/Server/Http/Web/ErrorConfiguration.cs | 39 ++ .../Server/Http/{Nancy => Web}/HttpServer.cs | 2 +- .../Http/{Nancy => Web}/NancyBootstrapper.cs | 7 +- .../Http/{Nancy => Web}/RootPathProvider.cs | 7 +- .../Repository/Registries/ClassRegistry.cs | 1 + .../Repository/Registries/FactoryRegistry.cs | 1 + .../Repository/Registries/Registry.cs | 2 +- src/CoiniumServ/Server/Web/Modules/Index.cs | 18 +- src/CoiniumServ/Server/Web/Modules/Pool.cs | 6 - src/CoiniumServ/Server/Web/WebServer.cs | 2 +- src/CoiniumServ/packages.config | 3 + src/CoiniumServ/web/default/index.2sshtml | 62 --- src/CoiniumServ/web/default/index.cshtml | 99 +++- src/CoiniumServ/web/default/layout2.sshtml | 161 ------- src/CoiniumServ/web/default/notfound.cshtml | 13 + .../web/default/{pool.sshtml => pool.cshtml} | 42 +- src/WebTests/LoadTest1.loadtest | 440 ++++++++++++++++++ src/WebTests/WebTest1.webtest | 2 + src/WebTests/WebTest1Coded.cs | 34 ++ src/WebTests/WebTests.csproj | 92 ++++ 38 files changed, 1297 insertions(+), 271 deletions(-) create mode 100644 build/Local.testsettings delete mode 100644 contrib/capture/fastcoin.pcapng delete mode 100644 contrib/capture/litecoin-testnet-mini.pcapng delete mode 100644 contrib/capture/litecoin-testnet.pcapng rename contrib/{coin-daemon/sample-config.conf => coin/sample.conf} (51%) create mode 100644 contrib/performance-tests/Readme.md create mode 100644 contrib/performance-tests/web.jmx create mode 100644 contrib/performance-tests/web.rider create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs create mode 100644 src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs rename src/CoiniumServ/Net/Server/Http/{Nancy => Web}/HttpServer.cs (98%) rename src/CoiniumServ/Net/Server/Http/{Nancy => Web}/NancyBootstrapper.cs (95%) rename src/CoiniumServ/Net/Server/Http/{Nancy => Web}/RootPathProvider.cs (82%) delete mode 100644 src/CoiniumServ/web/default/index.2sshtml delete mode 100644 src/CoiniumServ/web/default/layout2.sshtml create mode 100644 src/CoiniumServ/web/default/notfound.cshtml rename src/CoiniumServ/web/default/{pool.sshtml => pool.cshtml} (61%) create mode 100644 src/WebTests/LoadTest1.loadtest create mode 100644 src/WebTests/WebTest1.webtest create mode 100644 src/WebTests/WebTest1Coded.cs create mode 100644 src/WebTests/WebTests.csproj diff --git a/build/CoiniumServ.sln b/build/CoiniumServ.sln index 9b5c4441e..7ee8faf8f 100644 --- a/build/CoiniumServ.sln +++ b/build/CoiniumServ.sln @@ -20,6 +20,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonConfig", "..\deps\jsonc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoiniumServGui", "..\src\CoiniumServGui\CoiniumServGui.csproj", "{1E2AF218-156A-40A0-8DA3-95DD13D93810}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DB1BE05-DEC0-43D6-8CD8-908F5C44B09A}" + ProjectSection(SolutionItems) = preProject + Local.testsettings = Local.testsettings + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebTests", "..\src\WebTests\WebTests.csproj", "{A23B4A18-B8F5-43A2-84B1-3181C80CCD50}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -120,6 +127,21 @@ Global {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|Mixed Platforms.ActiveCfg = Release|Any CPU {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|Mixed Platforms.Build.0 = Release|Any CPU {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|x86.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|x86.ActiveCfg = Debug|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Any CPU.Build.0 = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|x86.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Any CPU.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Any CPU.Build.0 = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Mixed Platforms.ActiveCfg = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Mixed Platforms.Build.0 = Release|Any CPU + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/Local.testsettings b/build/Local.testsettings new file mode 100644 index 000000000..f661ad601 --- /dev/null +++ b/build/Local.testsettings @@ -0,0 +1,11 @@ + + + These are default test settings for a local test run. + + + + + + + + \ No newline at end of file diff --git a/contrib/capture/fastcoin.pcapng b/contrib/capture/fastcoin.pcapng deleted file mode 100644 index 041cf93175d81ca18c986743bea1d9f2adb3ff60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404236 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 Or&kjLMqw6EWBvjBBI?)x diff --git a/contrib/coin-daemon/sample-config.conf b/contrib/coin/sample.conf similarity index 51% rename from contrib/coin-daemon/sample-config.conf rename to contrib/coin/sample.conf index 9ea23e680..0fb663bf2 100644 --- a/contrib/coin-daemon/sample-config.conf +++ b/contrib/coin/sample.conf @@ -7,4 +7,6 @@ rpcport=9333 #testnet=1 # testnet block explorers: -# litecoin: http://testnet.litecointools.com/ \ No newline at end of file +# bitcoin https://chain.so/testnet/btc +# litecoin: https://chain.so/testnet/ltc +# dogecoin: https://chain.so/testnet/doge diff --git a/contrib/performance-tests/Readme.md b/contrib/performance-tests/Readme.md new file mode 100644 index 000000000..c74dfa347 --- /dev/null +++ b/contrib/performance-tests/Readme.md @@ -0,0 +1,4 @@ +This folder contains configuration for performance tests; + +* *.rider tests: [HttpRider](https://httprider.codeplex.com/) +* *.jmx tests: [Apacha JMeter](http://jmeter.apache.org/download_jmeter.cgi) \ No newline at end of file diff --git a/contrib/performance-tests/web.jmx b/contrib/performance-tests/web.jmx new file mode 100644 index 000000000..652de6b1a --- /dev/null +++ b/contrib/performance-tests/web.jmx @@ -0,0 +1,153 @@ + + + + + + false + false + + + + + + + + continue + + false + 2 + + 1000 + 1 + 1373789594000 + 1373789594000 + false + + + + + + + + + 127.0.0.1 + 91 + + + + + + 4 + + + + + + + + + + + + + / + GET + true + false + true + false + false + + + + + + + + + + + + + + /changes.html + GET + true + false + true + false + false + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + + + + + + + + + + true + johndoe + = + true + username + + + true + secret + = + true + password + + + + www.example.com + + + + + + /loginform.html + POST + true + false + true + false + false + + + + + + + diff --git a/contrib/performance-tests/web.rider b/contrib/performance-tests/web.rider new file mode 100644 index 0000000000000000000000000000000000000000..8dcdee06a63dd4f9fc4301a91782e221ae8bd0be GIT binary patch literal 44451 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 ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll + + ..\..\build\packages\Metrics.NET.0.1.9\lib\net45\Metrics.dll + False ..\..\build\packages\Nancy.0.23.0\lib\net40\Nancy.dll + + False + ..\..\build\packages\Nancy.CustomErrors.1.0.4.0\lib\net40\Nancy.CustomErrors.dll + False ..\..\build\packages\Nancy.Hosting.Self.0.23.0\lib\net40\Nancy.Hosting.Self.dll + + ..\..\build\packages\NancyFx.Metrics.0.1.9\lib\net45\Nancy.Metrics.dll + ..\..\build\packages\Nancy.Viewengines.Razor.0.23.0\lib\net40\Nancy.ViewEngines.Razor.dll @@ -100,6 +110,10 @@ + + + + @@ -112,15 +126,18 @@ + + - - + + + @@ -318,7 +335,7 @@ - + @@ -974,10 +991,10 @@ PreserveNewest - + PreserveNewest - + PreserveNewest @@ -1069,9 +1086,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -1080,11 +1094,12 @@ + - + @@ -1092,7 +1107,7 @@ - + if $(ConfigurationName) == Debug ( diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index ce66c4534..4454290e9 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -22,11 +22,14 @@ #endregion using System.Collections.Generic; using Coinium.Mining.Pools.Config; +using Coinium.Mining.Pools.Statistics; namespace Coinium.Mining.Pools { public interface IPoolManager { + IGlobalStatistics Statistics { get; } + IList GetPools(); IPool GetBySymbol(string symbol); diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 25ac47e2b..48b00236e 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.Linq; using Coinium.Mining.Pools.Config; +using Coinium.Mining.Pools.Statistics; using Coinium.Utils.Configuration; using Coinium.Utils.Helpers.IO; using Serilog; @@ -33,20 +34,27 @@ namespace Coinium.Mining.Pools { public class PoolManager : IPoolManager { + public IGlobalStatistics Statistics { get; private set; } + private readonly List _pools = new List(); private readonly IPoolFactory _poolFactory; private readonly IPoolConfigFactory _poolConfigFactory; - public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory) + private readonly IGlobalStatisticsFactory _algorithmStatisticsFactory; + + public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IGlobalStatisticsFactory algorithmStatisticsFactory) { _poolFactory = poolFactory; _poolConfigFactory = poolConfigFactory; + _algorithmStatisticsFactory = algorithmStatisticsFactory; } public void Run() { + Statistics = _algorithmStatisticsFactory.Get(this); + LoadConfigs(); } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs new file mode 100644 index 000000000..581e34b19 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs @@ -0,0 +1,91 @@ +#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.Collections.Generic; +using System.Linq; +using System.Threading; +using Coinium.Coin.Helpers; + +namespace Coinium.Mining.Pools.Statistics +{ + public class GlobalStatistics:IGlobalStatistics + { + public Int32 Workers { get; private set; } + public UInt64 Hashrate { get; private set; } + public string ReadableHashrate { get; private set; } + public IList Algorithms { get; private set; } + + private readonly IDictionary _algorithms; + + private readonly IPoolManager _poolManager; + + private readonly Timer _timer; + private const int TimerExpiration = 10; + + public GlobalStatistics(IPoolManager poolManager) + { + _poolManager = poolManager; + + _algorithms = new Dictionary(); + + _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + Recache(null); // recache data initially. + } + + private void Recache(object state) + { + Hashrate = 0; + Workers = 0; + + foreach (var pair in _algorithms) + { + pair.Value.Reset(); + } + + foreach (var pool in _poolManager.GetPools()) + { + Hashrate += pool.Statistics.Hashrate; + Workers += pool.Statistics.Miners.Count; + + if (!_algorithms.ContainsKey(pool.Config.Coin.Algorithm)) + _algorithms.Add(pool.Config.Coin.Algorithm, new PerAlgorithmStatistics(pool.Config.Coin.Algorithm)); + + _algorithms[pool.Config.Coin.Algorithm].Hashrate += pool.Statistics.Hashrate; + _algorithms[pool.Config.Coin.Algorithm].Workers += pool.Statistics.Miners.Count; + } + + foreach (var pair in _algorithms) + { + pair.Value.ReadableHashrate = pair.Value.Hashrate.GetReadableHashrate(); + } + + ReadableHashrate = Hashrate.GetReadableHashrate(); + + Algorithms = _algorithms.Values.ToList(); + + // reset the recache timer. + _timer.Change(TimerExpiration * 1000, Timeout.Infinite); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs new file mode 100644 index 000000000..c2043049a --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs @@ -0,0 +1,49 @@ +#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 Coinium.Repository.Context; + +namespace Coinium.Mining.Pools.Statistics +{ + public class GlobalStatisticsFactory:IGlobalStatisticsFactory + { + /// + /// The _kernel + /// + private readonly IApplicationContext _applicationContext; + + /// + /// Initializes a new instance of the class. + /// + /// The application context. + public GlobalStatisticsFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public IGlobalStatistics Get(IPoolManager poolManager) + { + return _applicationContext.Container.Resolve(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs new file mode 100644 index 000000000..d1b48a911 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs @@ -0,0 +1,39 @@ +#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.Collections.Generic; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IGlobalStatistics + { + Int32 Workers { get; } + + UInt64 Hashrate { get; } + + string ReadableHashrate { get; } + + IList Algorithms { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs new file mode 100644 index 000000000..55dccbbea --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs @@ -0,0 +1,30 @@ +#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 Coinium.Mining.Pools.Statistics +{ + public interface IGlobalStatisticsFactory + { + IGlobalStatistics Get(IPoolManager poolManager); + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs new file mode 100644 index 000000000..79d7d0778 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs @@ -0,0 +1,40 @@ +#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; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IPerAlgorithmStatistics + { + string Name { get; } + + Int32 Workers { get; set; } + + UInt64 Hashrate { get; set; } + + string ReadableHashrate { get; set; } + + void Reset(); + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs new file mode 100644 index 000000000..e834d330c --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs @@ -0,0 +1,44 @@ +#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 Coinium.Mining.Pools.Statistics +{ + public class PerAlgorithmStatistics:IPerAlgorithmStatistics + { + public string Name { get; private set; } + public int Workers { get; set; } + public ulong Hashrate { get; set; } + public string ReadableHashrate { get; set; } + + public PerAlgorithmStatistics(string algorithm) + { + Name = algorithm; + } + + public void Reset() + { + Hashrate = 0; + Workers = 0; + } + } +} diff --git a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs new file mode 100644 index 000000000..4722275fd --- /dev/null +++ b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs @@ -0,0 +1,39 @@ +#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 Nancy; +using Nancy.CustomErrors; + +namespace Coinium.Net.Server.Http.Web +{ + public class ErrorConfiguration : CustomErrorsConfiguration + { + public ErrorConfiguration() + { + // Map error status codes to custom view names + ErrorViews[HttpStatusCode.NotFound] = "notfound"; + ErrorViews[HttpStatusCode.InternalServerError] = "error"; + ErrorViews[HttpStatusCode.Forbidden] = "forbidden"; + } + } +} diff --git a/src/CoiniumServ/Net/Server/Http/Nancy/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs similarity index 98% rename from src/CoiniumServ/Net/Server/Http/Nancy/HttpServer.cs rename to src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index fb26ef11c..024f4dbcc 100644 --- a/src/CoiniumServ/Net/Server/Http/Nancy/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -27,7 +27,7 @@ using Nancy.Hosting.Self; using Serilog; -namespace Coinium.Net.Server.Http.Nancy +namespace Coinium.Net.Server.Http.Web { public class HttpServer : IServer, IDisposable { diff --git a/src/CoiniumServ/Net/Server/Http/Nancy/NancyBootstrapper.cs b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs similarity index 95% rename from src/CoiniumServ/Net/Server/Http/Nancy/NancyBootstrapper.cs rename to src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs index a8fa30c14..e5ab9a101 100644 --- a/src/CoiniumServ/Net/Server/Http/Nancy/NancyBootstrapper.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs @@ -25,11 +25,11 @@ using Nancy; using Nancy.Bootstrapper; using Nancy.Conventions; +using Nancy.CustomErrors; using Nancy.Diagnostics; using Nancy.TinyIoc; -using Newtonsoft.Json.Serialization; -namespace Coinium.Net.Server.Http.Nancy +namespace Coinium.Net.Server.Http.Web { public class NancyBootstrapper : DefaultNancyBootstrapper { @@ -49,8 +49,9 @@ protected override DiagnosticsConfiguration DiagnosticsConfiguration } protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) - { + { StaticConfiguration.EnableRequestTracing = true; + CustomErrors.Enable(pipelines, new ErrorConfiguration()); } protected override IRootPathProvider RootPathProvider diff --git a/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs similarity index 82% rename from src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs rename to src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs index 86713dc97..0f179b7ee 100644 --- a/src/CoiniumServ/Net/Server/Http/Nancy/RootPathProvider.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs @@ -23,16 +23,17 @@ using System.IO; using System.Reflection; +using Coinium.Utils.Platform; using Nancy; -namespace Coinium.Net.Server.Http.Nancy +namespace Coinium.Net.Server.Http.Web { public class CustomRootPathProvider : IRootPathProvider { public string GetRootPath() { - var path = string.Format("{0}/web/default", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); - return path; + return string.Format(PlatformManager.IsRunningOnMono() ? "{0}/web/default" : "{0}\\web\\default", + Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); } } } diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 66c5b206c..dcca215cb 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -49,6 +49,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 63f18e5ca..bf89cd507 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -65,6 +65,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index 667fa20c4..f53147a29 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -22,7 +22,7 @@ #endregion using System; using System.Collections.Generic; -using Coinium.Net.Server.Http.Nancy; +using Coinium.Net.Server.Http.Web; using Coinium.Repository.Context; using Nancy.Bootstrapper; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index 3f6e60fb5..f3225f110 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -23,20 +23,26 @@ using System.Collections.Generic; using Coinium.Mining.Pools; +using Coinium.Mining.Pools.Statistics; using Nancy; namespace Coinium.Server.Web.Modules { public class IndexModule : NancyModule { - public class Model + public IndexModule(IPoolManager poolManager) { - public IList Pools { get; set; } + Get["/"] = _ => View["index", new IndexModel + { + Global = poolManager.Statistics, + Pools = poolManager.GetPools() + }]; } + } - public IndexModule(IPoolManager poolManager) - { - Get["/"] = _ => View["index", poolManager.GetPools()]; - } + public class IndexModel + { + public IGlobalStatistics Global { get; set; } + public IList Pools { get; set; } } } diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index 45e08d8cd..bd81ba503 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -21,7 +21,6 @@ // #endregion -using System.Collections.Generic; using Coinium.Mining.Pools; using Nancy; @@ -29,11 +28,6 @@ namespace Coinium.Server.Web.Modules { public class PoolModule : NancyModule { - public class Model - { - public IList Pools { get; set; } - } - public PoolModule(IPoolManager poolManager) { Get["/pool/{slug}"] = _ => diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 749145a12..382f4e4f6 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -22,7 +22,7 @@ #endregion using Coinium.Mining.Pools; -using Coinium.Net.Server.Http.Nancy; +using Coinium.Net.Server.Http.Web; using Coinium.Repository.Context; using Coinium.Utils.Configuration; diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 30f67101c..0f7bdbf95 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,10 +4,13 @@ + + + diff --git a/src/CoiniumServ/web/default/index.2sshtml b/src/CoiniumServ/web/default/index.2sshtml deleted file mode 100644 index a5c950a9b..000000000 --- a/src/CoiniumServ/web/default/index.2sshtml +++ /dev/null @@ -1,62 +0,0 @@ -@Master['layout.sshtml'] - -@Section['Content'] - -
    - -
    -
    -
    -

    Per Algorithm Statistics

    -
    -
    -
    - - - - - - - - - - -
    Algorithm Workers Hashrate
    -
    -
    -
    -
    - -
    -
    -
    -

    Per Pool Statistics

    -
    -
    -
    - - - - - - - - - - - @Each.Model - - - - - - - @EndEach - -
    Pool Algorithm Workers Hashrate
    @Current.Config.Coin.Name@Current.Config.Coin.Algorithm@Current.Statistics.Miners.Count@Current.Statistics.ReadableHashrate
    -
    -
    -
    -
    - -@EndSection \ No newline at end of file diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index 22a6f8015..676239f0d 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -1,5 +1,100 @@ -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } -test \ No newline at end of file +
    + + +
    +
    +
    +

    Overall Statistics

    +
    +
    +
    + + + + + + + + + + + + + +
    Workers Hashrate
    @Model.Global.Workers@Model.Global.ReadableHashrate
    +
    +
    +
    +
    + + +
    +
    +
    +

    Per Algorithm Statistics

    +
    +
    +
    + + + + + + + + + + @foreach (var algorithm in Model.Global.Algorithms) + { + + + + + + } + +
    Algorithm Workers Hashrate
    @algorithm.Name@algorithm.Workers@algorithm.ReadableHashrate
    +
    +
    +
    +
    + + +
    +
    +
    +

    Per Pool Statistics

    +
    +
    +
    + + + + + + + + + + + @foreach (var pool in Model.Pools) + { + + + + + + + } + +
    Pool Algorithm Workers Hashrate
    @pool.Config.Coin.Name@pool.Config.Coin.Algorithm@pool.Statistics.Miners.Count@pool.Statistics.ReadableHashrate
    +
    +
    +
    +
    + +
    \ No newline at end of file diff --git a/src/CoiniumServ/web/default/layout2.sshtml b/src/CoiniumServ/web/default/layout2.sshtml deleted file mode 100644 index c03b75e7f..000000000 --- a/src/CoiniumServ/web/default/layout2.sshtml +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - CoiniumServ - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - diff --git a/src/CoiniumServ/web/default/notfound.cshtml b/src/CoiniumServ/web/default/notfound.cshtml new file mode 100644 index 000000000..d837dfd93 --- /dev/null +++ b/src/CoiniumServ/web/default/notfound.cshtml @@ -0,0 +1,13 @@ +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase + +@{ Layout = "layout.cshtml"; } + +
    +
    +
    + Oh snap! Page not found! +

    @Model.Summary

    +

    @Model.Details

    +
    +
    +
    \ No newline at end of file diff --git a/src/CoiniumServ/web/default/pool.sshtml b/src/CoiniumServ/web/default/pool.cshtml similarity index 61% rename from src/CoiniumServ/web/default/pool.sshtml rename to src/CoiniumServ/web/default/pool.cshtml index e8fdc3541..957f36129 100644 --- a/src/CoiniumServ/web/default/pool.sshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -1,6 +1,9 @@ -@Master['layout.sshtml'] +@using System +@using System.Linq +@using Coinium.Persistance +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase -@Section['Content'] +@{ Layout = "layout.cshtml"; }
    @@ -56,7 +59,7 @@
    -
    +

    Latest Blocks

    @@ -74,15 +77,29 @@ - @Each.Model.Statistics.Blocks.Latest - - @Current.Height - @Current.Status - @Current.OutstandingHashes.Total - @Current.OutstandingHashes.BlockHash - @Current.OutstandingHashes.TransactionHash - - @EndEach + @foreach (var block in Model.Statistics.Blocks.Latest) + { + + @block.Height + + @switch (block.Status) + { + case PersistedBlockStatus.Pending: + @block.Status + break; + case PersistedBlockStatus.Orphan: + @block.Status + break; + case PersistedBlockStatus.Confirmed: + @block.Status + break; + } + + @block.OutstandingHashes.Total + @block.OutstandingHashes.BlockHash.Substring(0,10).. + @block.OutstandingHashes.TransactionHash.Substring(0, 10).. + + }
    @@ -92,4 +109,3 @@
    -@EndSection \ No newline at end of file diff --git a/src/WebTests/LoadTest1.loadtest b/src/WebTests/LoadTest1.loadtest new file mode 100644 index 000000000..0e010d6f5 --- /dev/null +++ b/src/WebTests/LoadTest1.loadtest @@ -0,0 +1,440 @@ + + + + + + + + + + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WebTests/WebTest1.webtest b/src/WebTests/WebTest1.webtest new file mode 100644 index 000000000..eaca08922 --- /dev/null +++ b/src/WebTests/WebTest1.webtest @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/WebTests/WebTest1Coded.cs b/src/WebTests/WebTest1Coded.cs new file mode 100644 index 000000000..1a8f3936e --- /dev/null +++ b/src/WebTests/WebTest1Coded.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WebTests +{ + using System; + using System.Collections.Generic; + using System.Text; + using Microsoft.VisualStudio.TestTools.WebTesting; + + + public class WebTest1Coded : WebTest + { + + public WebTest1Coded() + { + this.PreAuthenticate = true; + this.Proxy = "default"; + } + + public override IEnumerator GetRequestEnumerator() + { + WebTestRequest customRequest = new WebTestRequest("http://127.0.0.1:91"); + yield return customRequest; + } + } +} diff --git a/src/WebTests/WebTests.csproj b/src/WebTests/WebTests.csproj new file mode 100644 index 000000000..b6b270839 --- /dev/null +++ b/src/WebTests/WebTests.csproj @@ -0,0 +1,92 @@ + + + + Debug + AnyCPU + + + 2.0 + {A23B4A18-B8F5-43A2-84B1-3181C80CCD50} + Library + Properties + WebTests + WebTests + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + WebTest + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + 3.5 + + + + + False + + + + + + + + + Always + + + PreserveNewest + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file From 5becd353718990160f9828565fc42a1a00112d5c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 11 Jul 2014 19:44:12 +0300 Subject: [PATCH 049/230] Tiny fix. --- src/WebTests/Properties/AssemblyInfo.cs | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/WebTests/Properties/AssemblyInfo.cs diff --git a/src/WebTests/Properties/AssemblyInfo.cs b/src/WebTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e24fcd09d --- /dev/null +++ b/src/WebTests/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WebTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WebTests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("244b8558-80f9-41c0-bde6-7c64e8114520")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] From 7383f3144b1845204bb2411a52f0f8fc67479a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 11 Jul 2014 20:27:04 +0300 Subject: [PATCH 050/230] Removed web-tests project. --- build/CoiniumServ.sln | 22 -- build/Local.testsettings | 11 - src/WebTests/LoadTest1.loadtest | 440 ------------------------ src/WebTests/Properties/AssemblyInfo.cs | 35 -- src/WebTests/WebTest1.webtest | 2 - src/WebTests/WebTest1Coded.cs | 34 -- src/WebTests/WebTests.csproj | 92 ----- 7 files changed, 636 deletions(-) delete mode 100644 build/Local.testsettings delete mode 100644 src/WebTests/LoadTest1.loadtest delete mode 100644 src/WebTests/Properties/AssemblyInfo.cs delete mode 100644 src/WebTests/WebTest1.webtest delete mode 100644 src/WebTests/WebTest1Coded.cs delete mode 100644 src/WebTests/WebTests.csproj diff --git a/build/CoiniumServ.sln b/build/CoiniumServ.sln index 7ee8faf8f..9b5c4441e 100644 --- a/build/CoiniumServ.sln +++ b/build/CoiniumServ.sln @@ -20,13 +20,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonConfig", "..\deps\jsonc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoiniumServGui", "..\src\CoiniumServGui\CoiniumServGui.csproj", "{1E2AF218-156A-40A0-8DA3-95DD13D93810}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DB1BE05-DEC0-43D6-8CD8-908F5C44B09A}" - ProjectSection(SolutionItems) = preProject - Local.testsettings = Local.testsettings - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebTests", "..\src\WebTests\WebTests.csproj", "{A23B4A18-B8F5-43A2-84B1-3181C80CCD50}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -127,21 +120,6 @@ Global {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|Mixed Platforms.ActiveCfg = Release|Any CPU {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|Mixed Platforms.Build.0 = Release|Any CPU {1E2AF218-156A-40A0-8DA3-95DD13D93810}.Testing|x86.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Debug|x86.ActiveCfg = Debug|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Any CPU.Build.0 = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Release|x86.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Any CPU.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Any CPU.Build.0 = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Mixed Platforms.ActiveCfg = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|Mixed Platforms.Build.0 = Release|Any CPU - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50}.Testing|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/Local.testsettings b/build/Local.testsettings deleted file mode 100644 index f661ad601..000000000 --- a/build/Local.testsettings +++ /dev/null @@ -1,11 +0,0 @@ - - - These are default test settings for a local test run. - - - - - - - - \ No newline at end of file diff --git a/src/WebTests/LoadTest1.loadtest b/src/WebTests/LoadTest1.loadtest deleted file mode 100644 index 0e010d6f5..000000000 --- a/src/WebTests/LoadTest1.loadtest +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - - - - - -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/WebTests/Properties/AssemblyInfo.cs b/src/WebTests/Properties/AssemblyInfo.cs deleted file mode 100644 index e24fcd09d..000000000 --- a/src/WebTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("WebTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("WebTests")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("244b8558-80f9-41c0-bde6-7c64e8114520")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/WebTests/WebTest1.webtest b/src/WebTests/WebTest1.webtest deleted file mode 100644 index eaca08922..000000000 --- a/src/WebTests/WebTest1.webtest +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/WebTests/WebTest1Coded.cs b/src/WebTests/WebTest1Coded.cs deleted file mode 100644 index 1a8f3936e..000000000 --- a/src/WebTests/WebTest1Coded.cs +++ /dev/null @@ -1,34 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34014 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace WebTests -{ - using System; - using System.Collections.Generic; - using System.Text; - using Microsoft.VisualStudio.TestTools.WebTesting; - - - public class WebTest1Coded : WebTest - { - - public WebTest1Coded() - { - this.PreAuthenticate = true; - this.Proxy = "default"; - } - - public override IEnumerator GetRequestEnumerator() - { - WebTestRequest customRequest = new WebTestRequest("http://127.0.0.1:91"); - yield return customRequest; - } - } -} diff --git a/src/WebTests/WebTests.csproj b/src/WebTests/WebTests.csproj deleted file mode 100644 index b6b270839..000000000 --- a/src/WebTests/WebTests.csproj +++ /dev/null @@ -1,92 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {A23B4A18-B8F5-43A2-84B1-3181C80CCD50} - Library - Properties - WebTests - WebTests - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - WebTest - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - 3.5 - - - - - False - - - - - - - - - Always - - - PreserveNewest - - - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file From e617cee30e04b80ec772319c78dc4de9c05336f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 11 Jul 2014 20:38:02 +0300 Subject: [PATCH 051/230] Moved all configs to /config. Removed assets folder. Moved ubuntu installer to contrib/installers. --- README.md | 2 +- assets/Coinium.ico | Bin 140206 -> 0 bytes .../installers}/ubuntu.sh | 0 .../Readme.md | 0 .../web.jmx | 0 .../web.rider | Bin src/CoiniumServ/CoiniumServ.csproj | 413 ++++++------------ src/CoiniumServ/Program.cs | 3 +- .../Configuration/GlobalConfigFactory.cs | 2 +- .../CoiniumServ}/config/coins/21coin.json | 0 .../CoiniumServ}/config/coins/365coin.json | 0 .../CoiniumServ}/config/coins/README.md | 0 .../CoiniumServ}/config/coins/alphacoin.json | 0 .../CoiniumServ}/config/coins/anoncoin.json | 0 .../CoiniumServ}/config/coins/applecoin.json | 0 .../CoiniumServ}/config/coins/arkenstone.json | 0 .../CoiniumServ}/config/coins/arkhash.json | 0 .../CoiniumServ}/config/coins/asiccoin.json | 0 .../CoiniumServ}/config/coins/auroracoin.json | 0 .../CoiniumServ}/config/coins/battlecoin.json | 0 .../CoiniumServ}/config/coins/benjamins.json | 0 .../CoiniumServ}/config/coins/betacoin.json | 0 .../CoiniumServ}/config/coins/bitcoin.json | 0 .../CoiniumServ}/config/coins/bitraam.json | 0 .../CoiniumServ}/config/coins/bitstar.json | 0 .../CoiniumServ}/config/coins/bluecoin.json | 0 .../CoiniumServ}/config/coins/bottlecaps.json | 0 .../CoiniumServ}/config/coins/bunnycoin.json | 0 .../CoiniumServ}/config/coins/bytecoin.json | 0 .../CoiniumServ}/config/coins/cachecoin.json | 0 .../CoiniumServ}/config/coins/casinocoin.json | 0 .../CoiniumServ}/config/coins/catcoin.json | 0 .../CoiniumServ}/config/coins/coino.json | 0 .../config/coins/continuumcoin.json | 0 .../CoiniumServ}/config/coins/copperbars.json | 0 .../CoiniumServ}/config/coins/copperlark.json | 0 .../config/coins/cryptogenicbullion.json | 0 .../config/coins/cryptographicanomaly.json | 0 .../CoiniumServ}/config/coins/cryptometh.json | 0 .../CoiniumServ}/config/coins/darkcoin.json | 0 .../CoiniumServ}/config/coins/defcoin.json | 0 .../CoiniumServ}/config/coins/devcoin.json | 0 .../config/coins/diamondcoin.json | 0 .../CoiniumServ}/config/coins/digibyte.json | 0 .../CoiniumServ}/config/coins/dogecoin.json | 0 .../CoiniumServ}/config/coins/earthcoin.json | 0 .../config/coins/einsteinium.json | 0 .../config/coins/elephantcoin.json | 0 .../CoiniumServ}/config/coins/emark.json | 0 .../CoiniumServ}/config/coins/emerald.json | 0 .../CoiniumServ}/config/coins/execoin.json | 0 .../CoiniumServ}/config/coins/ezcoin.json | 0 .../CoiniumServ}/config/coins/fastcoin.json | 0 .../config/coins/fastcoinsha.json | 0 .../config/coins/feathercoin.json | 0 .../CoiniumServ}/config/coins/fedoracoin.json | 0 .../config/coins/fireflycoin.json | 0 .../CoiniumServ}/config/coins/flappycoin.json | 0 .../CoiniumServ}/config/coins/florincoin.json | 0 .../CoiniumServ}/config/coins/frankocoin.json | 0 .../CoiniumServ}/config/coins/freecoin.json | 0 .../CoiniumServ}/config/coins/freicoin.json | 0 .../CoiniumServ}/config/coins/galaxycoin.json | 0 .../CoiniumServ}/config/coins/galleon.json | 0 .../CoiniumServ}/config/coins/gamecoin.json | 0 .../CoiniumServ}/config/coins/giarcoin.json | 0 .../config/coins/globalboost.json | 0 .../CoiniumServ}/config/coins/globalcoin.json | 0 .../config/coins/globaldenomination.json | 0 .../config/coins/goldpressedlatinum.json | 0 .../CoiniumServ}/config/coins/grandcoin.json | 0 .../config/coins/groestlcoin.json | 0 .../config/coins/guarantcoin.json | 0 .../CoiniumServ}/config/coins/helixcoin.json | 0 .../CoiniumServ}/config/coins/hirocoin.json | 0 .../config/coins/hobonickels.json | 0 .../config/coins/internetcoin.json | 0 .../CoiniumServ}/config/coins/ixcoin.json | 0 .../CoiniumServ}/config/coins/jennycoin.json | 0 .../CoiniumServ}/config/coins/joulecoin.json | 0 .../CoiniumServ}/config/coins/junkcoin.json | 0 .../CoiniumServ}/config/coins/kittehcoin.json | 0 .../config/coins/klondikecoin.json | 0 .../CoiniumServ}/config/coins/krugercoin.json | 0 .../CoiniumServ}/config/coins/kumacoin.json | 0 .../CoiniumServ}/config/coins/litecoin.json | 0 .../CoiniumServ}/config/coins/lottocoin.json | 0 .../CoiniumServ}/config/coins/luckycoin.json | 0 .../CoiniumServ}/config/coins/maxcoin.json | 0 .../CoiniumServ}/config/coins/mazacoin.json | 0 .../CoiniumServ}/config/coins/memecoin.json | 0 .../CoiniumServ}/config/coins/microcoin.json | 0 .../CoiniumServ}/config/coins/mintcoin.json | 0 .../CoiniumServ}/config/coins/monacoin.json | 0 .../CoiniumServ}/config/coins/muniti.json | 0 .../CoiniumServ}/config/coins/myriadcoin.json | 0 .../CoiniumServ}/config/coins/neocoin.json | 0 .../CoiniumServ}/config/coins/netcoin.json | 0 .../CoiniumServ}/config/coins/noirbits.json | 0 .../CoiniumServ}/config/coins/octocoin.json | 0 .../CoiniumServ}/config/coins/onecoin.json | 0 .../config/coins/opensourcecoin.json | 0 .../CoiniumServ}/config/coins/pawncoin.json | 0 .../CoiniumServ}/config/coins/peercoin.json | 0 .../config/coins/phoenixcoin.json | 0 .../CoiniumServ}/config/coins/plncoin.json | 0 .../CoiniumServ}/config/coins/potcoin.json | 0 .../CoiniumServ}/config/coins/procoin.json | 0 .../CoiniumServ}/config/coins/quarkcoin.json | 0 .../config/coins/radioactivecoin.json | 0 .../CoiniumServ}/config/coins/reddcoin.json | 0 .../config/coins/ronpaulcoin.json | 0 .../CoiniumServ}/config/coins/rubycoin.json | 0 .../config/coins/saffroncoin.json | 0 .../CoiniumServ}/config/coins/sayacoin.json | 0 .../CoiniumServ}/config/coins/sexcoin.json | 0 .../CoiniumServ}/config/coins/sha1coin.json | 0 .../CoiniumServ}/config/coins/skeincoin.json | 0 .../config/coins/spartancoin.json | 0 .../CoiniumServ}/config/coins/spots.json | 0 .../CoiniumServ}/config/coins/stablecoin.json | 0 .../CoiniumServ}/config/coins/starcoin.json | 0 .../CoiniumServ}/config/coins/stashcoin.json | 0 .../config/coins/stoopidcoin.json | 0 .../CoiniumServ}/config/coins/suncoin.json | 0 .../CoiniumServ}/config/coins/takcoin.json | 0 .../CoiniumServ}/config/coins/teacoin.json | 0 .../CoiniumServ}/config/coins/tekcoin.json | 0 .../CoiniumServ}/config/coins/terracoin.json | 0 .../CoiniumServ}/config/coins/tigercoin.json | 0 .../config/coins/ultimatecoin.json | 0 .../CoiniumServ}/config/coins/ultracoin.json | 0 .../CoiniumServ}/config/coins/unobtanium.json | 0 .../config/coins/velocitycoin.json | 0 .../CoiniumServ}/config/coins/vertcoin.json | 0 .../config/coins/wearesatoshi.json | 0 .../CoiniumServ}/config/coins/wecoin.json | 0 .../CoiniumServ}/config/coins/whitecoin.json | 0 .../CoiniumServ}/config/coins/xencoin.json | 0 .../CoiniumServ}/config/coins/yacoin.json | 0 .../CoiniumServ}/config/coins/ybcoin.json | 0 .../CoiniumServ}/config/coins/zedcoin.json | 0 .../CoiniumServ}/config/coins/zetacoin.json | 0 .../CoiniumServ}/config/coins/zzcoin.json | 0 .../CoiniumServ}/config/config-sample.json | 0 .../CoiniumServ}/config/pools/sample.json | 0 146 files changed, 142 insertions(+), 278 deletions(-) delete mode 100644 assets/Coinium.ico rename {assets/installer => contrib/installers}/ubuntu.sh (100%) rename contrib/{performance-tests => performance}/Readme.md (100%) rename contrib/{performance-tests => performance}/web.jmx (100%) rename contrib/{performance-tests => performance}/web.rider (100%) rename {assets => src/CoiniumServ}/config/coins/21coin.json (100%) rename {assets => src/CoiniumServ}/config/coins/365coin.json (100%) rename {assets => src/CoiniumServ}/config/coins/README.md (100%) rename {assets => src/CoiniumServ}/config/coins/alphacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/anoncoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/applecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/arkenstone.json (100%) rename {assets => src/CoiniumServ}/config/coins/arkhash.json (100%) rename {assets => src/CoiniumServ}/config/coins/asiccoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/auroracoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/battlecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/benjamins.json (100%) rename {assets => src/CoiniumServ}/config/coins/betacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/bitcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/bitraam.json (100%) rename {assets => src/CoiniumServ}/config/coins/bitstar.json (100%) rename {assets => src/CoiniumServ}/config/coins/bluecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/bottlecaps.json (100%) rename {assets => src/CoiniumServ}/config/coins/bunnycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/bytecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/cachecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/casinocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/catcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/coino.json (100%) rename {assets => src/CoiniumServ}/config/coins/continuumcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/copperbars.json (100%) rename {assets => src/CoiniumServ}/config/coins/copperlark.json (100%) rename {assets => src/CoiniumServ}/config/coins/cryptogenicbullion.json (100%) rename {assets => src/CoiniumServ}/config/coins/cryptographicanomaly.json (100%) rename {assets => src/CoiniumServ}/config/coins/cryptometh.json (100%) rename {assets => src/CoiniumServ}/config/coins/darkcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/defcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/devcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/diamondcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/digibyte.json (100%) rename {assets => src/CoiniumServ}/config/coins/dogecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/earthcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/einsteinium.json (100%) rename {assets => src/CoiniumServ}/config/coins/elephantcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/emark.json (100%) rename {assets => src/CoiniumServ}/config/coins/emerald.json (100%) rename {assets => src/CoiniumServ}/config/coins/execoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ezcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/fastcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/fastcoinsha.json (100%) rename {assets => src/CoiniumServ}/config/coins/feathercoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/fedoracoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/fireflycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/flappycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/florincoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/frankocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/freecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/freicoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/galaxycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/galleon.json (100%) rename {assets => src/CoiniumServ}/config/coins/gamecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/giarcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/globalboost.json (100%) rename {assets => src/CoiniumServ}/config/coins/globalcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/globaldenomination.json (100%) rename {assets => src/CoiniumServ}/config/coins/goldpressedlatinum.json (100%) rename {assets => src/CoiniumServ}/config/coins/grandcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/groestlcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/guarantcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/helixcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/hirocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/hobonickels.json (100%) rename {assets => src/CoiniumServ}/config/coins/internetcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ixcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/jennycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/joulecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/junkcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/kittehcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/klondikecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/krugercoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/kumacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/litecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/lottocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/luckycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/maxcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/mazacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/memecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/microcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/mintcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/monacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/muniti.json (100%) rename {assets => src/CoiniumServ}/config/coins/myriadcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/neocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/netcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/noirbits.json (100%) rename {assets => src/CoiniumServ}/config/coins/octocoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/onecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/opensourcecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/pawncoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/peercoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/phoenixcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/plncoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/potcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/procoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/quarkcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/radioactivecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/reddcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ronpaulcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/rubycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/saffroncoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/sayacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/sexcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/sha1coin.json (100%) rename {assets => src/CoiniumServ}/config/coins/skeincoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/spartancoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/spots.json (100%) rename {assets => src/CoiniumServ}/config/coins/stablecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/starcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/stashcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/stoopidcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/suncoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/takcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/teacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/tekcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/terracoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/tigercoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ultimatecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ultracoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/unobtanium.json (100%) rename {assets => src/CoiniumServ}/config/coins/velocitycoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/vertcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/wearesatoshi.json (100%) rename {assets => src/CoiniumServ}/config/coins/wecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/whitecoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/xencoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/yacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/ybcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/zedcoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/zetacoin.json (100%) rename {assets => src/CoiniumServ}/config/coins/zzcoin.json (100%) rename {assets => src/CoiniumServ}/config/config-sample.json (100%) rename {assets => src/CoiniumServ}/config/pools/sample.json (100%) diff --git a/README.md b/README.md index 536816ac2..8d16c63ec 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Make sure you check our [Getting Started](https://github.com/CoiniumServ/Coinium For Ubuntu, you can simply use our installer script; ``` -wget -O - https://raw.githubusercontent.com/CoiniumServ/CoiniumServ/develop/assets/installer/ubuntu.sh | bash +wget -O - https://raw.githubusercontent.com/CoiniumServ/CoiniumServ/develop/contrib/installers/ubuntu.sh | bash ``` ### Documentation diff --git a/assets/Coinium.ico b/assets/Coinium.ico deleted file mode 100644 index fa82f09bf0b281a3abec7cdb70c730392e7b2485..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140206 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 O2mh`(pyXRM-u)jCGCMQ? diff --git a/assets/installer/ubuntu.sh b/contrib/installers/ubuntu.sh similarity index 100% rename from assets/installer/ubuntu.sh rename to contrib/installers/ubuntu.sh diff --git a/contrib/performance-tests/Readme.md b/contrib/performance/Readme.md similarity index 100% rename from contrib/performance-tests/Readme.md rename to contrib/performance/Readme.md diff --git a/contrib/performance-tests/web.jmx b/contrib/performance/web.jmx similarity index 100% rename from contrib/performance-tests/web.jmx rename to contrib/performance/web.jmx diff --git a/contrib/performance-tests/web.rider b/contrib/performance/web.rider similarity index 100% rename from contrib/performance-tests/web.rider rename to contrib/performance/web.rider diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 0f103891c..fa4301415 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -344,555 +344,418 @@ - - config\coins\21coin.json + + PreserveNewest - - config\coins\365coin.json + PreserveNewest - - config\coins\alphacoin.json + PreserveNewest - - config\coins\anoncoin.json + PreserveNewest - - config\coins\applecoin.json + PreserveNewest - - config\coins\arkenstone.json + PreserveNewest - - config\coins\arkhash.json + PreserveNewest - - config\coins\asiccoin.json + PreserveNewest - - config\coins\auroracoin.json + PreserveNewest - - config\coins\battlecoin.json + PreserveNewest - - config\coins\benjamins.json + PreserveNewest - - config\coins\betacoin.json + PreserveNewest - - config\coins\bitcoin.json + PreserveNewest - - config\coins\bitraam.json + PreserveNewest - - config\coins\bitstar.json + PreserveNewest - - config\coins\bluecoin.json + PreserveNewest - - config\coins\bottlecaps.json + PreserveNewest - - config\coins\bunnycoin.json + PreserveNewest - - config\coins\bytecoin.json + PreserveNewest - - config\coins\cachecoin.json + PreserveNewest - - config\coins\casinocoin.json + PreserveNewest - - config\coins\catcoin.json + PreserveNewest - - config\coins\coino.json + PreserveNewest - - config\coins\continuumcoin.json + PreserveNewest - - config\coins\copperbars.json + PreserveNewest - - config\coins\copperlark.json + PreserveNewest - - config\coins\cryptogenicbullion.json + PreserveNewest - - config\coins\cryptographicanomaly.json + PreserveNewest - - config\coins\cryptometh.json + PreserveNewest - - config\coins\darkcoin.json + PreserveNewest - - config\coins\defcoin.json + PreserveNewest - - config\coins\devcoin.json + PreserveNewest - - config\coins\diamondcoin.json + PreserveNewest - - config\coins\digibyte.json + PreserveNewest - - config\coins\dogecoin.json + PreserveNewest - - config\coins\earthcoin.json + PreserveNewest - - config\coins\einsteinium.json + PreserveNewest - - config\coins\elephantcoin.json + PreserveNewest - - config\coins\emark.json + PreserveNewest - - config\coins\emerald.json + PreserveNewest - - config\coins\execoin.json + PreserveNewest - - config\coins\ezcoin.json + PreserveNewest - - config\coins\fastcoin.json + PreserveNewest - - config\coins\fastcoinsha.json + PreserveNewest - - config\coins\feathercoin.json + PreserveNewest - - config\coins\fedoracoin.json + PreserveNewest - - config\coins\fireflycoin.json + PreserveNewest - - config\coins\flappycoin.json + PreserveNewest - - config\coins\florincoin.json + PreserveNewest - - config\coins\frankocoin.json + PreserveNewest - - config\coins\freecoin.json + PreserveNewest - - config\coins\freicoin.json + PreserveNewest - - config\coins\galaxycoin.json + PreserveNewest - - config\coins\galleon.json + PreserveNewest - - config\coins\gamecoin.json + PreserveNewest - - config\coins\giarcoin.json + PreserveNewest - - config\coins\globalboost.json + PreserveNewest - - config\coins\globalcoin.json + PreserveNewest - - config\coins\globaldenomination.json + PreserveNewest - - config\coins\goldpressedlatinum.json + PreserveNewest - - config\coins\grandcoin.json + PreserveNewest - - config\coins\groestlcoin.json + PreserveNewest - - config\coins\guarantcoin.json + PreserveNewest - - config\coins\helixcoin.json + PreserveNewest - - config\coins\hirocoin.json + PreserveNewest - - config\coins\hobonickels.json + PreserveNewest - - config\coins\internetcoin.json + PreserveNewest - - config\coins\ixcoin.json + PreserveNewest - - config\coins\jennycoin.json + PreserveNewest - - config\coins\joulecoin.json + PreserveNewest - - config\coins\junkcoin.json + PreserveNewest - - config\coins\kittehcoin.json + PreserveNewest - - config\coins\klondikecoin.json + PreserveNewest - - config\coins\krugercoin.json + PreserveNewest - - config\coins\kumacoin.json + PreserveNewest - - config\coins\litecoin.json + PreserveNewest - - config\coins\lottocoin.json + PreserveNewest - - config\coins\luckycoin.json + PreserveNewest - - config\coins\maxcoin.json + PreserveNewest - - config\coins\mazacoin.json + PreserveNewest - - config\coins\memecoin.json + PreserveNewest - - config\coins\microcoin.json + PreserveNewest - - config\coins\mintcoin.json + PreserveNewest - - config\coins\monacoin.json + PreserveNewest - - config\coins\muniti.json + PreserveNewest - - config\coins\myriadcoin.json + PreserveNewest - - config\coins\neocoin.json + PreserveNewest - - config\coins\netcoin.json + PreserveNewest - - config\coins\noirbits.json + PreserveNewest - - config\coins\octocoin.json + PreserveNewest - - config\coins\onecoin.json + PreserveNewest - - config\coins\opensourcecoin.json + PreserveNewest - - config\coins\pawncoin.json + PreserveNewest - - config\coins\peercoin.json + PreserveNewest - - config\coins\phoenixcoin.json + PreserveNewest - - config\coins\plncoin.json + PreserveNewest - - config\coins\potcoin.json + PreserveNewest - - config\coins\procoin.json + PreserveNewest - - config\coins\quarkcoin.json + PreserveNewest - - config\coins\radioactivecoin.json + PreserveNewest - - config\coins\README.md + PreserveNewest - - config\coins\reddcoin.json + PreserveNewest - - config\coins\ronpaulcoin.json + PreserveNewest - - config\coins\rubycoin.json + PreserveNewest - - config\coins\saffroncoin.json + PreserveNewest - - config\coins\sayacoin.json + PreserveNewest - - config\coins\sexcoin.json + PreserveNewest - - config\coins\sha1coin.json + PreserveNewest - - config\coins\skeincoin.json + PreserveNewest - - config\coins\spartancoin.json + PreserveNewest - - config\coins\spots.json + PreserveNewest - - config\coins\stablecoin.json + PreserveNewest - - config\coins\starcoin.json + PreserveNewest - - config\coins\stashcoin.json + PreserveNewest - - config\coins\stoopidcoin.json + PreserveNewest - - config\coins\suncoin.json + PreserveNewest - - config\coins\takcoin.json + PreserveNewest - - config\coins\teacoin.json + PreserveNewest - - config\coins\tekcoin.json + PreserveNewest - - config\coins\terracoin.json + PreserveNewest - - config\coins\tigercoin.json + PreserveNewest - - config\coins\ultimatecoin.json + PreserveNewest - - config\coins\ultracoin.json + PreserveNewest - - config\coins\unobtanium.json + PreserveNewest - - config\coins\velocitycoin.json + PreserveNewest - - config\coins\vertcoin.json + PreserveNewest - - config\coins\wearesatoshi.json + PreserveNewest - - config\coins\wecoin.json + PreserveNewest - - config\coins\whitecoin.json + PreserveNewest - - config\coins\xencoin.json + PreserveNewest - - config\coins\yacoin.json + PreserveNewest - - config\coins\ybcoin.json + PreserveNewest - - config\coins\zedcoin.json + PreserveNewest - - config\coins\zetacoin.json + PreserveNewest - - config\coins\zzcoin.json + PreserveNewest - - config-sample.json + PreserveNewest - - config\pools\sample.json + PreserveNewest - diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index aaa7a7d66..4e291d25c 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -65,10 +65,11 @@ static void Main(string[] args) // check if we have a valid config file. var globalConfig = kernel.Resolve().Get(); + if (globalConfig == null) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Couldn't read config.json! Make sure you rename config-sample.json as config.json."); + Console.WriteLine("Couldn't read config/config.json! Make sure you rename config/config-sample.json as config/config.json."); Console.ResetColor(); return; } diff --git a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs index b9717333f..3c2276df7 100644 --- a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs @@ -28,7 +28,7 @@ namespace Coinium.Utils.Configuration { public class GlobalConfigFactory : IGlobalConfigFactory { - private const string FileName = "config.json"; + private const string FileName = "config/config.json"; private dynamic _data; private IRedisConfig _redisConfig; diff --git a/assets/config/coins/21coin.json b/src/CoiniumServ/config/coins/21coin.json similarity index 100% rename from assets/config/coins/21coin.json rename to src/CoiniumServ/config/coins/21coin.json diff --git a/assets/config/coins/365coin.json b/src/CoiniumServ/config/coins/365coin.json similarity index 100% rename from assets/config/coins/365coin.json rename to src/CoiniumServ/config/coins/365coin.json diff --git a/assets/config/coins/README.md b/src/CoiniumServ/config/coins/README.md similarity index 100% rename from assets/config/coins/README.md rename to src/CoiniumServ/config/coins/README.md diff --git a/assets/config/coins/alphacoin.json b/src/CoiniumServ/config/coins/alphacoin.json similarity index 100% rename from assets/config/coins/alphacoin.json rename to src/CoiniumServ/config/coins/alphacoin.json diff --git a/assets/config/coins/anoncoin.json b/src/CoiniumServ/config/coins/anoncoin.json similarity index 100% rename from assets/config/coins/anoncoin.json rename to src/CoiniumServ/config/coins/anoncoin.json diff --git a/assets/config/coins/applecoin.json b/src/CoiniumServ/config/coins/applecoin.json similarity index 100% rename from assets/config/coins/applecoin.json rename to src/CoiniumServ/config/coins/applecoin.json diff --git a/assets/config/coins/arkenstone.json b/src/CoiniumServ/config/coins/arkenstone.json similarity index 100% rename from assets/config/coins/arkenstone.json rename to src/CoiniumServ/config/coins/arkenstone.json diff --git a/assets/config/coins/arkhash.json b/src/CoiniumServ/config/coins/arkhash.json similarity index 100% rename from assets/config/coins/arkhash.json rename to src/CoiniumServ/config/coins/arkhash.json diff --git a/assets/config/coins/asiccoin.json b/src/CoiniumServ/config/coins/asiccoin.json similarity index 100% rename from assets/config/coins/asiccoin.json rename to src/CoiniumServ/config/coins/asiccoin.json diff --git a/assets/config/coins/auroracoin.json b/src/CoiniumServ/config/coins/auroracoin.json similarity index 100% rename from assets/config/coins/auroracoin.json rename to src/CoiniumServ/config/coins/auroracoin.json diff --git a/assets/config/coins/battlecoin.json b/src/CoiniumServ/config/coins/battlecoin.json similarity index 100% rename from assets/config/coins/battlecoin.json rename to src/CoiniumServ/config/coins/battlecoin.json diff --git a/assets/config/coins/benjamins.json b/src/CoiniumServ/config/coins/benjamins.json similarity index 100% rename from assets/config/coins/benjamins.json rename to src/CoiniumServ/config/coins/benjamins.json diff --git a/assets/config/coins/betacoin.json b/src/CoiniumServ/config/coins/betacoin.json similarity index 100% rename from assets/config/coins/betacoin.json rename to src/CoiniumServ/config/coins/betacoin.json diff --git a/assets/config/coins/bitcoin.json b/src/CoiniumServ/config/coins/bitcoin.json similarity index 100% rename from assets/config/coins/bitcoin.json rename to src/CoiniumServ/config/coins/bitcoin.json diff --git a/assets/config/coins/bitraam.json b/src/CoiniumServ/config/coins/bitraam.json similarity index 100% rename from assets/config/coins/bitraam.json rename to src/CoiniumServ/config/coins/bitraam.json diff --git a/assets/config/coins/bitstar.json b/src/CoiniumServ/config/coins/bitstar.json similarity index 100% rename from assets/config/coins/bitstar.json rename to src/CoiniumServ/config/coins/bitstar.json diff --git a/assets/config/coins/bluecoin.json b/src/CoiniumServ/config/coins/bluecoin.json similarity index 100% rename from assets/config/coins/bluecoin.json rename to src/CoiniumServ/config/coins/bluecoin.json diff --git a/assets/config/coins/bottlecaps.json b/src/CoiniumServ/config/coins/bottlecaps.json similarity index 100% rename from assets/config/coins/bottlecaps.json rename to src/CoiniumServ/config/coins/bottlecaps.json diff --git a/assets/config/coins/bunnycoin.json b/src/CoiniumServ/config/coins/bunnycoin.json similarity index 100% rename from assets/config/coins/bunnycoin.json rename to src/CoiniumServ/config/coins/bunnycoin.json diff --git a/assets/config/coins/bytecoin.json b/src/CoiniumServ/config/coins/bytecoin.json similarity index 100% rename from assets/config/coins/bytecoin.json rename to src/CoiniumServ/config/coins/bytecoin.json diff --git a/assets/config/coins/cachecoin.json b/src/CoiniumServ/config/coins/cachecoin.json similarity index 100% rename from assets/config/coins/cachecoin.json rename to src/CoiniumServ/config/coins/cachecoin.json diff --git a/assets/config/coins/casinocoin.json b/src/CoiniumServ/config/coins/casinocoin.json similarity index 100% rename from assets/config/coins/casinocoin.json rename to src/CoiniumServ/config/coins/casinocoin.json diff --git a/assets/config/coins/catcoin.json b/src/CoiniumServ/config/coins/catcoin.json similarity index 100% rename from assets/config/coins/catcoin.json rename to src/CoiniumServ/config/coins/catcoin.json diff --git a/assets/config/coins/coino.json b/src/CoiniumServ/config/coins/coino.json similarity index 100% rename from assets/config/coins/coino.json rename to src/CoiniumServ/config/coins/coino.json diff --git a/assets/config/coins/continuumcoin.json b/src/CoiniumServ/config/coins/continuumcoin.json similarity index 100% rename from assets/config/coins/continuumcoin.json rename to src/CoiniumServ/config/coins/continuumcoin.json diff --git a/assets/config/coins/copperbars.json b/src/CoiniumServ/config/coins/copperbars.json similarity index 100% rename from assets/config/coins/copperbars.json rename to src/CoiniumServ/config/coins/copperbars.json diff --git a/assets/config/coins/copperlark.json b/src/CoiniumServ/config/coins/copperlark.json similarity index 100% rename from assets/config/coins/copperlark.json rename to src/CoiniumServ/config/coins/copperlark.json diff --git a/assets/config/coins/cryptogenicbullion.json b/src/CoiniumServ/config/coins/cryptogenicbullion.json similarity index 100% rename from assets/config/coins/cryptogenicbullion.json rename to src/CoiniumServ/config/coins/cryptogenicbullion.json diff --git a/assets/config/coins/cryptographicanomaly.json b/src/CoiniumServ/config/coins/cryptographicanomaly.json similarity index 100% rename from assets/config/coins/cryptographicanomaly.json rename to src/CoiniumServ/config/coins/cryptographicanomaly.json diff --git a/assets/config/coins/cryptometh.json b/src/CoiniumServ/config/coins/cryptometh.json similarity index 100% rename from assets/config/coins/cryptometh.json rename to src/CoiniumServ/config/coins/cryptometh.json diff --git a/assets/config/coins/darkcoin.json b/src/CoiniumServ/config/coins/darkcoin.json similarity index 100% rename from assets/config/coins/darkcoin.json rename to src/CoiniumServ/config/coins/darkcoin.json diff --git a/assets/config/coins/defcoin.json b/src/CoiniumServ/config/coins/defcoin.json similarity index 100% rename from assets/config/coins/defcoin.json rename to src/CoiniumServ/config/coins/defcoin.json diff --git a/assets/config/coins/devcoin.json b/src/CoiniumServ/config/coins/devcoin.json similarity index 100% rename from assets/config/coins/devcoin.json rename to src/CoiniumServ/config/coins/devcoin.json diff --git a/assets/config/coins/diamondcoin.json b/src/CoiniumServ/config/coins/diamondcoin.json similarity index 100% rename from assets/config/coins/diamondcoin.json rename to src/CoiniumServ/config/coins/diamondcoin.json diff --git a/assets/config/coins/digibyte.json b/src/CoiniumServ/config/coins/digibyte.json similarity index 100% rename from assets/config/coins/digibyte.json rename to src/CoiniumServ/config/coins/digibyte.json diff --git a/assets/config/coins/dogecoin.json b/src/CoiniumServ/config/coins/dogecoin.json similarity index 100% rename from assets/config/coins/dogecoin.json rename to src/CoiniumServ/config/coins/dogecoin.json diff --git a/assets/config/coins/earthcoin.json b/src/CoiniumServ/config/coins/earthcoin.json similarity index 100% rename from assets/config/coins/earthcoin.json rename to src/CoiniumServ/config/coins/earthcoin.json diff --git a/assets/config/coins/einsteinium.json b/src/CoiniumServ/config/coins/einsteinium.json similarity index 100% rename from assets/config/coins/einsteinium.json rename to src/CoiniumServ/config/coins/einsteinium.json diff --git a/assets/config/coins/elephantcoin.json b/src/CoiniumServ/config/coins/elephantcoin.json similarity index 100% rename from assets/config/coins/elephantcoin.json rename to src/CoiniumServ/config/coins/elephantcoin.json diff --git a/assets/config/coins/emark.json b/src/CoiniumServ/config/coins/emark.json similarity index 100% rename from assets/config/coins/emark.json rename to src/CoiniumServ/config/coins/emark.json diff --git a/assets/config/coins/emerald.json b/src/CoiniumServ/config/coins/emerald.json similarity index 100% rename from assets/config/coins/emerald.json rename to src/CoiniumServ/config/coins/emerald.json diff --git a/assets/config/coins/execoin.json b/src/CoiniumServ/config/coins/execoin.json similarity index 100% rename from assets/config/coins/execoin.json rename to src/CoiniumServ/config/coins/execoin.json diff --git a/assets/config/coins/ezcoin.json b/src/CoiniumServ/config/coins/ezcoin.json similarity index 100% rename from assets/config/coins/ezcoin.json rename to src/CoiniumServ/config/coins/ezcoin.json diff --git a/assets/config/coins/fastcoin.json b/src/CoiniumServ/config/coins/fastcoin.json similarity index 100% rename from assets/config/coins/fastcoin.json rename to src/CoiniumServ/config/coins/fastcoin.json diff --git a/assets/config/coins/fastcoinsha.json b/src/CoiniumServ/config/coins/fastcoinsha.json similarity index 100% rename from assets/config/coins/fastcoinsha.json rename to src/CoiniumServ/config/coins/fastcoinsha.json diff --git a/assets/config/coins/feathercoin.json b/src/CoiniumServ/config/coins/feathercoin.json similarity index 100% rename from assets/config/coins/feathercoin.json rename to src/CoiniumServ/config/coins/feathercoin.json diff --git a/assets/config/coins/fedoracoin.json b/src/CoiniumServ/config/coins/fedoracoin.json similarity index 100% rename from assets/config/coins/fedoracoin.json rename to src/CoiniumServ/config/coins/fedoracoin.json diff --git a/assets/config/coins/fireflycoin.json b/src/CoiniumServ/config/coins/fireflycoin.json similarity index 100% rename from assets/config/coins/fireflycoin.json rename to src/CoiniumServ/config/coins/fireflycoin.json diff --git a/assets/config/coins/flappycoin.json b/src/CoiniumServ/config/coins/flappycoin.json similarity index 100% rename from assets/config/coins/flappycoin.json rename to src/CoiniumServ/config/coins/flappycoin.json diff --git a/assets/config/coins/florincoin.json b/src/CoiniumServ/config/coins/florincoin.json similarity index 100% rename from assets/config/coins/florincoin.json rename to src/CoiniumServ/config/coins/florincoin.json diff --git a/assets/config/coins/frankocoin.json b/src/CoiniumServ/config/coins/frankocoin.json similarity index 100% rename from assets/config/coins/frankocoin.json rename to src/CoiniumServ/config/coins/frankocoin.json diff --git a/assets/config/coins/freecoin.json b/src/CoiniumServ/config/coins/freecoin.json similarity index 100% rename from assets/config/coins/freecoin.json rename to src/CoiniumServ/config/coins/freecoin.json diff --git a/assets/config/coins/freicoin.json b/src/CoiniumServ/config/coins/freicoin.json similarity index 100% rename from assets/config/coins/freicoin.json rename to src/CoiniumServ/config/coins/freicoin.json diff --git a/assets/config/coins/galaxycoin.json b/src/CoiniumServ/config/coins/galaxycoin.json similarity index 100% rename from assets/config/coins/galaxycoin.json rename to src/CoiniumServ/config/coins/galaxycoin.json diff --git a/assets/config/coins/galleon.json b/src/CoiniumServ/config/coins/galleon.json similarity index 100% rename from assets/config/coins/galleon.json rename to src/CoiniumServ/config/coins/galleon.json diff --git a/assets/config/coins/gamecoin.json b/src/CoiniumServ/config/coins/gamecoin.json similarity index 100% rename from assets/config/coins/gamecoin.json rename to src/CoiniumServ/config/coins/gamecoin.json diff --git a/assets/config/coins/giarcoin.json b/src/CoiniumServ/config/coins/giarcoin.json similarity index 100% rename from assets/config/coins/giarcoin.json rename to src/CoiniumServ/config/coins/giarcoin.json diff --git a/assets/config/coins/globalboost.json b/src/CoiniumServ/config/coins/globalboost.json similarity index 100% rename from assets/config/coins/globalboost.json rename to src/CoiniumServ/config/coins/globalboost.json diff --git a/assets/config/coins/globalcoin.json b/src/CoiniumServ/config/coins/globalcoin.json similarity index 100% rename from assets/config/coins/globalcoin.json rename to src/CoiniumServ/config/coins/globalcoin.json diff --git a/assets/config/coins/globaldenomination.json b/src/CoiniumServ/config/coins/globaldenomination.json similarity index 100% rename from assets/config/coins/globaldenomination.json rename to src/CoiniumServ/config/coins/globaldenomination.json diff --git a/assets/config/coins/goldpressedlatinum.json b/src/CoiniumServ/config/coins/goldpressedlatinum.json similarity index 100% rename from assets/config/coins/goldpressedlatinum.json rename to src/CoiniumServ/config/coins/goldpressedlatinum.json diff --git a/assets/config/coins/grandcoin.json b/src/CoiniumServ/config/coins/grandcoin.json similarity index 100% rename from assets/config/coins/grandcoin.json rename to src/CoiniumServ/config/coins/grandcoin.json diff --git a/assets/config/coins/groestlcoin.json b/src/CoiniumServ/config/coins/groestlcoin.json similarity index 100% rename from assets/config/coins/groestlcoin.json rename to src/CoiniumServ/config/coins/groestlcoin.json diff --git a/assets/config/coins/guarantcoin.json b/src/CoiniumServ/config/coins/guarantcoin.json similarity index 100% rename from assets/config/coins/guarantcoin.json rename to src/CoiniumServ/config/coins/guarantcoin.json diff --git a/assets/config/coins/helixcoin.json b/src/CoiniumServ/config/coins/helixcoin.json similarity index 100% rename from assets/config/coins/helixcoin.json rename to src/CoiniumServ/config/coins/helixcoin.json diff --git a/assets/config/coins/hirocoin.json b/src/CoiniumServ/config/coins/hirocoin.json similarity index 100% rename from assets/config/coins/hirocoin.json rename to src/CoiniumServ/config/coins/hirocoin.json diff --git a/assets/config/coins/hobonickels.json b/src/CoiniumServ/config/coins/hobonickels.json similarity index 100% rename from assets/config/coins/hobonickels.json rename to src/CoiniumServ/config/coins/hobonickels.json diff --git a/assets/config/coins/internetcoin.json b/src/CoiniumServ/config/coins/internetcoin.json similarity index 100% rename from assets/config/coins/internetcoin.json rename to src/CoiniumServ/config/coins/internetcoin.json diff --git a/assets/config/coins/ixcoin.json b/src/CoiniumServ/config/coins/ixcoin.json similarity index 100% rename from assets/config/coins/ixcoin.json rename to src/CoiniumServ/config/coins/ixcoin.json diff --git a/assets/config/coins/jennycoin.json b/src/CoiniumServ/config/coins/jennycoin.json similarity index 100% rename from assets/config/coins/jennycoin.json rename to src/CoiniumServ/config/coins/jennycoin.json diff --git a/assets/config/coins/joulecoin.json b/src/CoiniumServ/config/coins/joulecoin.json similarity index 100% rename from assets/config/coins/joulecoin.json rename to src/CoiniumServ/config/coins/joulecoin.json diff --git a/assets/config/coins/junkcoin.json b/src/CoiniumServ/config/coins/junkcoin.json similarity index 100% rename from assets/config/coins/junkcoin.json rename to src/CoiniumServ/config/coins/junkcoin.json diff --git a/assets/config/coins/kittehcoin.json b/src/CoiniumServ/config/coins/kittehcoin.json similarity index 100% rename from assets/config/coins/kittehcoin.json rename to src/CoiniumServ/config/coins/kittehcoin.json diff --git a/assets/config/coins/klondikecoin.json b/src/CoiniumServ/config/coins/klondikecoin.json similarity index 100% rename from assets/config/coins/klondikecoin.json rename to src/CoiniumServ/config/coins/klondikecoin.json diff --git a/assets/config/coins/krugercoin.json b/src/CoiniumServ/config/coins/krugercoin.json similarity index 100% rename from assets/config/coins/krugercoin.json rename to src/CoiniumServ/config/coins/krugercoin.json diff --git a/assets/config/coins/kumacoin.json b/src/CoiniumServ/config/coins/kumacoin.json similarity index 100% rename from assets/config/coins/kumacoin.json rename to src/CoiniumServ/config/coins/kumacoin.json diff --git a/assets/config/coins/litecoin.json b/src/CoiniumServ/config/coins/litecoin.json similarity index 100% rename from assets/config/coins/litecoin.json rename to src/CoiniumServ/config/coins/litecoin.json diff --git a/assets/config/coins/lottocoin.json b/src/CoiniumServ/config/coins/lottocoin.json similarity index 100% rename from assets/config/coins/lottocoin.json rename to src/CoiniumServ/config/coins/lottocoin.json diff --git a/assets/config/coins/luckycoin.json b/src/CoiniumServ/config/coins/luckycoin.json similarity index 100% rename from assets/config/coins/luckycoin.json rename to src/CoiniumServ/config/coins/luckycoin.json diff --git a/assets/config/coins/maxcoin.json b/src/CoiniumServ/config/coins/maxcoin.json similarity index 100% rename from assets/config/coins/maxcoin.json rename to src/CoiniumServ/config/coins/maxcoin.json diff --git a/assets/config/coins/mazacoin.json b/src/CoiniumServ/config/coins/mazacoin.json similarity index 100% rename from assets/config/coins/mazacoin.json rename to src/CoiniumServ/config/coins/mazacoin.json diff --git a/assets/config/coins/memecoin.json b/src/CoiniumServ/config/coins/memecoin.json similarity index 100% rename from assets/config/coins/memecoin.json rename to src/CoiniumServ/config/coins/memecoin.json diff --git a/assets/config/coins/microcoin.json b/src/CoiniumServ/config/coins/microcoin.json similarity index 100% rename from assets/config/coins/microcoin.json rename to src/CoiniumServ/config/coins/microcoin.json diff --git a/assets/config/coins/mintcoin.json b/src/CoiniumServ/config/coins/mintcoin.json similarity index 100% rename from assets/config/coins/mintcoin.json rename to src/CoiniumServ/config/coins/mintcoin.json diff --git a/assets/config/coins/monacoin.json b/src/CoiniumServ/config/coins/monacoin.json similarity index 100% rename from assets/config/coins/monacoin.json rename to src/CoiniumServ/config/coins/monacoin.json diff --git a/assets/config/coins/muniti.json b/src/CoiniumServ/config/coins/muniti.json similarity index 100% rename from assets/config/coins/muniti.json rename to src/CoiniumServ/config/coins/muniti.json diff --git a/assets/config/coins/myriadcoin.json b/src/CoiniumServ/config/coins/myriadcoin.json similarity index 100% rename from assets/config/coins/myriadcoin.json rename to src/CoiniumServ/config/coins/myriadcoin.json diff --git a/assets/config/coins/neocoin.json b/src/CoiniumServ/config/coins/neocoin.json similarity index 100% rename from assets/config/coins/neocoin.json rename to src/CoiniumServ/config/coins/neocoin.json diff --git a/assets/config/coins/netcoin.json b/src/CoiniumServ/config/coins/netcoin.json similarity index 100% rename from assets/config/coins/netcoin.json rename to src/CoiniumServ/config/coins/netcoin.json diff --git a/assets/config/coins/noirbits.json b/src/CoiniumServ/config/coins/noirbits.json similarity index 100% rename from assets/config/coins/noirbits.json rename to src/CoiniumServ/config/coins/noirbits.json diff --git a/assets/config/coins/octocoin.json b/src/CoiniumServ/config/coins/octocoin.json similarity index 100% rename from assets/config/coins/octocoin.json rename to src/CoiniumServ/config/coins/octocoin.json diff --git a/assets/config/coins/onecoin.json b/src/CoiniumServ/config/coins/onecoin.json similarity index 100% rename from assets/config/coins/onecoin.json rename to src/CoiniumServ/config/coins/onecoin.json diff --git a/assets/config/coins/opensourcecoin.json b/src/CoiniumServ/config/coins/opensourcecoin.json similarity index 100% rename from assets/config/coins/opensourcecoin.json rename to src/CoiniumServ/config/coins/opensourcecoin.json diff --git a/assets/config/coins/pawncoin.json b/src/CoiniumServ/config/coins/pawncoin.json similarity index 100% rename from assets/config/coins/pawncoin.json rename to src/CoiniumServ/config/coins/pawncoin.json diff --git a/assets/config/coins/peercoin.json b/src/CoiniumServ/config/coins/peercoin.json similarity index 100% rename from assets/config/coins/peercoin.json rename to src/CoiniumServ/config/coins/peercoin.json diff --git a/assets/config/coins/phoenixcoin.json b/src/CoiniumServ/config/coins/phoenixcoin.json similarity index 100% rename from assets/config/coins/phoenixcoin.json rename to src/CoiniumServ/config/coins/phoenixcoin.json diff --git a/assets/config/coins/plncoin.json b/src/CoiniumServ/config/coins/plncoin.json similarity index 100% rename from assets/config/coins/plncoin.json rename to src/CoiniumServ/config/coins/plncoin.json diff --git a/assets/config/coins/potcoin.json b/src/CoiniumServ/config/coins/potcoin.json similarity index 100% rename from assets/config/coins/potcoin.json rename to src/CoiniumServ/config/coins/potcoin.json diff --git a/assets/config/coins/procoin.json b/src/CoiniumServ/config/coins/procoin.json similarity index 100% rename from assets/config/coins/procoin.json rename to src/CoiniumServ/config/coins/procoin.json diff --git a/assets/config/coins/quarkcoin.json b/src/CoiniumServ/config/coins/quarkcoin.json similarity index 100% rename from assets/config/coins/quarkcoin.json rename to src/CoiniumServ/config/coins/quarkcoin.json diff --git a/assets/config/coins/radioactivecoin.json b/src/CoiniumServ/config/coins/radioactivecoin.json similarity index 100% rename from assets/config/coins/radioactivecoin.json rename to src/CoiniumServ/config/coins/radioactivecoin.json diff --git a/assets/config/coins/reddcoin.json b/src/CoiniumServ/config/coins/reddcoin.json similarity index 100% rename from assets/config/coins/reddcoin.json rename to src/CoiniumServ/config/coins/reddcoin.json diff --git a/assets/config/coins/ronpaulcoin.json b/src/CoiniumServ/config/coins/ronpaulcoin.json similarity index 100% rename from assets/config/coins/ronpaulcoin.json rename to src/CoiniumServ/config/coins/ronpaulcoin.json diff --git a/assets/config/coins/rubycoin.json b/src/CoiniumServ/config/coins/rubycoin.json similarity index 100% rename from assets/config/coins/rubycoin.json rename to src/CoiniumServ/config/coins/rubycoin.json diff --git a/assets/config/coins/saffroncoin.json b/src/CoiniumServ/config/coins/saffroncoin.json similarity index 100% rename from assets/config/coins/saffroncoin.json rename to src/CoiniumServ/config/coins/saffroncoin.json diff --git a/assets/config/coins/sayacoin.json b/src/CoiniumServ/config/coins/sayacoin.json similarity index 100% rename from assets/config/coins/sayacoin.json rename to src/CoiniumServ/config/coins/sayacoin.json diff --git a/assets/config/coins/sexcoin.json b/src/CoiniumServ/config/coins/sexcoin.json similarity index 100% rename from assets/config/coins/sexcoin.json rename to src/CoiniumServ/config/coins/sexcoin.json diff --git a/assets/config/coins/sha1coin.json b/src/CoiniumServ/config/coins/sha1coin.json similarity index 100% rename from assets/config/coins/sha1coin.json rename to src/CoiniumServ/config/coins/sha1coin.json diff --git a/assets/config/coins/skeincoin.json b/src/CoiniumServ/config/coins/skeincoin.json similarity index 100% rename from assets/config/coins/skeincoin.json rename to src/CoiniumServ/config/coins/skeincoin.json diff --git a/assets/config/coins/spartancoin.json b/src/CoiniumServ/config/coins/spartancoin.json similarity index 100% rename from assets/config/coins/spartancoin.json rename to src/CoiniumServ/config/coins/spartancoin.json diff --git a/assets/config/coins/spots.json b/src/CoiniumServ/config/coins/spots.json similarity index 100% rename from assets/config/coins/spots.json rename to src/CoiniumServ/config/coins/spots.json diff --git a/assets/config/coins/stablecoin.json b/src/CoiniumServ/config/coins/stablecoin.json similarity index 100% rename from assets/config/coins/stablecoin.json rename to src/CoiniumServ/config/coins/stablecoin.json diff --git a/assets/config/coins/starcoin.json b/src/CoiniumServ/config/coins/starcoin.json similarity index 100% rename from assets/config/coins/starcoin.json rename to src/CoiniumServ/config/coins/starcoin.json diff --git a/assets/config/coins/stashcoin.json b/src/CoiniumServ/config/coins/stashcoin.json similarity index 100% rename from assets/config/coins/stashcoin.json rename to src/CoiniumServ/config/coins/stashcoin.json diff --git a/assets/config/coins/stoopidcoin.json b/src/CoiniumServ/config/coins/stoopidcoin.json similarity index 100% rename from assets/config/coins/stoopidcoin.json rename to src/CoiniumServ/config/coins/stoopidcoin.json diff --git a/assets/config/coins/suncoin.json b/src/CoiniumServ/config/coins/suncoin.json similarity index 100% rename from assets/config/coins/suncoin.json rename to src/CoiniumServ/config/coins/suncoin.json diff --git a/assets/config/coins/takcoin.json b/src/CoiniumServ/config/coins/takcoin.json similarity index 100% rename from assets/config/coins/takcoin.json rename to src/CoiniumServ/config/coins/takcoin.json diff --git a/assets/config/coins/teacoin.json b/src/CoiniumServ/config/coins/teacoin.json similarity index 100% rename from assets/config/coins/teacoin.json rename to src/CoiniumServ/config/coins/teacoin.json diff --git a/assets/config/coins/tekcoin.json b/src/CoiniumServ/config/coins/tekcoin.json similarity index 100% rename from assets/config/coins/tekcoin.json rename to src/CoiniumServ/config/coins/tekcoin.json diff --git a/assets/config/coins/terracoin.json b/src/CoiniumServ/config/coins/terracoin.json similarity index 100% rename from assets/config/coins/terracoin.json rename to src/CoiniumServ/config/coins/terracoin.json diff --git a/assets/config/coins/tigercoin.json b/src/CoiniumServ/config/coins/tigercoin.json similarity index 100% rename from assets/config/coins/tigercoin.json rename to src/CoiniumServ/config/coins/tigercoin.json diff --git a/assets/config/coins/ultimatecoin.json b/src/CoiniumServ/config/coins/ultimatecoin.json similarity index 100% rename from assets/config/coins/ultimatecoin.json rename to src/CoiniumServ/config/coins/ultimatecoin.json diff --git a/assets/config/coins/ultracoin.json b/src/CoiniumServ/config/coins/ultracoin.json similarity index 100% rename from assets/config/coins/ultracoin.json rename to src/CoiniumServ/config/coins/ultracoin.json diff --git a/assets/config/coins/unobtanium.json b/src/CoiniumServ/config/coins/unobtanium.json similarity index 100% rename from assets/config/coins/unobtanium.json rename to src/CoiniumServ/config/coins/unobtanium.json diff --git a/assets/config/coins/velocitycoin.json b/src/CoiniumServ/config/coins/velocitycoin.json similarity index 100% rename from assets/config/coins/velocitycoin.json rename to src/CoiniumServ/config/coins/velocitycoin.json diff --git a/assets/config/coins/vertcoin.json b/src/CoiniumServ/config/coins/vertcoin.json similarity index 100% rename from assets/config/coins/vertcoin.json rename to src/CoiniumServ/config/coins/vertcoin.json diff --git a/assets/config/coins/wearesatoshi.json b/src/CoiniumServ/config/coins/wearesatoshi.json similarity index 100% rename from assets/config/coins/wearesatoshi.json rename to src/CoiniumServ/config/coins/wearesatoshi.json diff --git a/assets/config/coins/wecoin.json b/src/CoiniumServ/config/coins/wecoin.json similarity index 100% rename from assets/config/coins/wecoin.json rename to src/CoiniumServ/config/coins/wecoin.json diff --git a/assets/config/coins/whitecoin.json b/src/CoiniumServ/config/coins/whitecoin.json similarity index 100% rename from assets/config/coins/whitecoin.json rename to src/CoiniumServ/config/coins/whitecoin.json diff --git a/assets/config/coins/xencoin.json b/src/CoiniumServ/config/coins/xencoin.json similarity index 100% rename from assets/config/coins/xencoin.json rename to src/CoiniumServ/config/coins/xencoin.json diff --git a/assets/config/coins/yacoin.json b/src/CoiniumServ/config/coins/yacoin.json similarity index 100% rename from assets/config/coins/yacoin.json rename to src/CoiniumServ/config/coins/yacoin.json diff --git a/assets/config/coins/ybcoin.json b/src/CoiniumServ/config/coins/ybcoin.json similarity index 100% rename from assets/config/coins/ybcoin.json rename to src/CoiniumServ/config/coins/ybcoin.json diff --git a/assets/config/coins/zedcoin.json b/src/CoiniumServ/config/coins/zedcoin.json similarity index 100% rename from assets/config/coins/zedcoin.json rename to src/CoiniumServ/config/coins/zedcoin.json diff --git a/assets/config/coins/zetacoin.json b/src/CoiniumServ/config/coins/zetacoin.json similarity index 100% rename from assets/config/coins/zetacoin.json rename to src/CoiniumServ/config/coins/zetacoin.json diff --git a/assets/config/coins/zzcoin.json b/src/CoiniumServ/config/coins/zzcoin.json similarity index 100% rename from assets/config/coins/zzcoin.json rename to src/CoiniumServ/config/coins/zzcoin.json diff --git a/assets/config/config-sample.json b/src/CoiniumServ/config/config-sample.json similarity index 100% rename from assets/config/config-sample.json rename to src/CoiniumServ/config/config-sample.json diff --git a/assets/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json similarity index 100% rename from assets/config/pools/sample.json rename to src/CoiniumServ/config/pools/sample.json From 12b4ae644cf97227b6461b610a32d8be5ef331f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 11 Jul 2014 20:47:58 +0300 Subject: [PATCH 052/230] Fixed error page. --- src/CoiniumServ/CoiniumServ.csproj | 3 +-- src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs | 4 ++-- src/CoiniumServ/Server/Web/Modules/Pool.cs | 2 +- src/CoiniumServ/web/default/{notfound.cshtml => error.cshtml} | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) rename src/CoiniumServ/web/default/{notfound.cshtml => error.cshtml} (84%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index fa4301415..2617a57fe 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -854,7 +854,7 @@ PreserveNewest - + PreserveNewest @@ -957,7 +957,6 @@ - diff --git a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs index 4722275fd..ade5e1411 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs @@ -31,9 +31,9 @@ public class ErrorConfiguration : CustomErrorsConfiguration public ErrorConfiguration() { // Map error status codes to custom view names - ErrorViews[HttpStatusCode.NotFound] = "notfound"; + ErrorViews[HttpStatusCode.NotFound] = "error"; ErrorViews[HttpStatusCode.InternalServerError] = "error"; - ErrorViews[HttpStatusCode.Forbidden] = "forbidden"; + ErrorViews[HttpStatusCode.Forbidden] = "error"; } } } diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index bd81ba503..c9cd160ee 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -35,7 +35,7 @@ public PoolModule(IPoolManager poolManager) var pool = poolManager.GetBySymbol(_.slug); if (pool == null) - return "Requested pool not found!"; + return View["error"]; return View["pool", pool]; }; diff --git a/src/CoiniumServ/web/default/notfound.cshtml b/src/CoiniumServ/web/default/error.cshtml similarity index 84% rename from src/CoiniumServ/web/default/notfound.cshtml rename to src/CoiniumServ/web/default/error.cshtml index d837dfd93..c4ead7086 100644 --- a/src/CoiniumServ/web/default/notfound.cshtml +++ b/src/CoiniumServ/web/default/error.cshtml @@ -5,7 +5,7 @@
    - Oh snap! Page not found! + Oh snap!

    @Model.Summary

    @Model.Details

    From 51e5fc02ecc4373dc8751904ebc60ee6ed0d5d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 11 Jul 2014 21:02:16 +0300 Subject: [PATCH 053/230] Fixed PoolModule error response. --- src/CoiniumServ/Server/Web/Modules/Pool.cs | 19 ++++++++++++++++--- src/CoiniumServ/web/default/error.cshtml | 3 +-- src/CoiniumServ/web/default/favicon.ico | Bin 140206 -> 1150 bytes 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index c9cd160ee..ef09ddd36 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -34,11 +34,24 @@ public PoolModule(IPoolManager poolManager) { var pool = poolManager.GetBySymbol(_.slug); - if (pool == null) - return View["error"]; + if (pool != null) + return View["pool", pool]; - return View["pool", pool]; + + var error = new ErrorModel + { + Summary = "Pool not found", + Details = string.Format("The request pool does not exist: {0}", _.slug) + }; + + return View["error", error]; }; } + + public class ErrorModel + { + public string Summary { get; set; } + public string Details { get; set; } + } } } diff --git a/src/CoiniumServ/web/default/error.cshtml b/src/CoiniumServ/web/default/error.cshtml index c4ead7086..bd133c0b0 100644 --- a/src/CoiniumServ/web/default/error.cshtml +++ b/src/CoiniumServ/web/default/error.cshtml @@ -5,8 +5,7 @@
    - Oh snap! -

    @Model.Summary

    + Oh snap! - @Model.Summary

    @Model.Details

    diff --git a/src/CoiniumServ/web/default/favicon.ico b/src/CoiniumServ/web/default/favicon.ico index fa82f09bf0b281a3abec7cdb70c730392e7b2485..23a28adfb668c70259133c8ebcf9590f3d8d4d72 100644 GIT binary patch literal 1150 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 O2mh`(pyXRM-u)jCGCMQ? From 377cb796604e110d0e3403aedc8146215c97b8c4 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 12 Jul 2014 13:31:24 +0300 Subject: [PATCH 054/230] Implemented a very basic /api/global response. --- src/CoiniumServ/CoiniumServ.csproj | 4 + src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- .../Pools/Statistics/BlockStatistics.cs | 1 - .../Pools/Statistics/GlobalStatistics.cs | 8 - .../Pools/Statistics/IGlobalStatistics.cs | 4 +- .../Statistics/IPerAlgorithmStatistics.cs | 2 - .../Pools/Statistics/IPoolStatistics.cs | 6 +- .../Statistics/IPoolStatisticsFactory.cs | 3 +- .../Statistics/PerAlgorithmStatistics.cs | 1 - .../Mining/Pools/Statistics/PoolStatistics.cs | 17 +- .../Pools/Statistics/PoolStatisticsFactory.cs | 4 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 64 +++++ src/CoiniumServ/web/default/api.cshtml | 7 + src/CoiniumServ/web/default/index.cshtml | 37 +-- src/CoiniumServ/web/default/pool.cshtml | 221 ++++++++++-------- 15 files changed, 242 insertions(+), 139 deletions(-) create mode 100644 src/CoiniumServ/Server/Web/Modules/Api.cs create mode 100644 src/CoiniumServ/web/default/api.cshtml diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 2617a57fe..851c426e6 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -158,6 +158,7 @@ + @@ -758,6 +759,9 @@ + + PreserveNewest + PreserveNewest diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 0358f1642..b4feb420f 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -184,7 +184,7 @@ private void InitManagers() var blockStatistics = _blockStatisticsFactory.Get(_daemonClient, _storage); - Statistics = _poolStatisticsFactory.Get(blockStatistics, _minerManager, _hashAlgorithm, _storage); + Statistics = _poolStatisticsFactory.Get(_daemonClient, blockStatistics, _minerManager, _hashAlgorithm, _storage); } private void InitServers() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs index 2028345e3..b54503116 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs @@ -24,7 +24,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Coinium.Coin.Helpers; using Coinium.Daemon; using Coinium.Daemon.Exceptions; using Coinium.Persistance; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs index 581e34b19..981b56f88 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs @@ -33,7 +33,6 @@ public class GlobalStatistics:IGlobalStatistics { public Int32 Workers { get; private set; } public UInt64 Hashrate { get; private set; } - public string ReadableHashrate { get; private set; } public IList Algorithms { get; private set; } private readonly IDictionary _algorithms; @@ -75,13 +74,6 @@ private void Recache(object state) _algorithms[pool.Config.Coin.Algorithm].Workers += pool.Statistics.Miners.Count; } - foreach (var pair in _algorithms) - { - pair.Value.ReadableHashrate = pair.Value.Hashrate.GetReadableHashrate(); - } - - ReadableHashrate = Hashrate.GetReadableHashrate(); - Algorithms = _algorithms.Values.ToList(); // reset the recache timer. diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs index d1b48a911..a90c364c6 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs @@ -28,11 +28,9 @@ namespace Coinium.Mining.Pools.Statistics { public interface IGlobalStatistics { - Int32 Workers { get; } - UInt64 Hashrate { get; } - string ReadableHashrate { get; } + Int32 Workers { get; } IList Algorithms { get; } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs index 79d7d0778..d730943ef 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs @@ -33,8 +33,6 @@ public interface IPerAlgorithmStatistics UInt64 Hashrate { get; set; } - string ReadableHashrate { get; set; } - void Reset(); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs index 0db73d0f8..1df5ab3c5 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs @@ -33,7 +33,11 @@ public interface IPoolStatistics UInt64 Hashrate { get; } - string ReadableHashrate { get; } + UInt64 NetworkHashrate { get; } + + double Difficulty { get; } + + int CurrentBlockHeight { get; } IList Miners { get; } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs index 8839f4927..f40d72d7c 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs @@ -22,6 +22,7 @@ #endregion using Coinium.Crypto.Algorithms; +using Coinium.Daemon; using Coinium.Mining.Miners; using Coinium.Persistance; @@ -29,6 +30,6 @@ namespace Coinium.Mining.Pools.Statistics { public interface IPoolStatisticsFactory { - IPoolStatistics Get(IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage); + IPoolStatistics Get(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs index e834d330c..6f9fc3016 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs @@ -28,7 +28,6 @@ public class PerAlgorithmStatistics:IPerAlgorithmStatistics public string Name { get; private set; } public int Workers { get; set; } public ulong Hashrate { get; set; } - public string ReadableHashrate { get; set; } public PerAlgorithmStatistics(string algorithm) { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs index 41cee56f4..f3d0ade11 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs @@ -25,8 +25,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Coinium.Coin.Helpers; using Coinium.Crypto.Algorithms; +using Coinium.Daemon; using Coinium.Mining.Miners; using Coinium.Persistance; using Coinium.Utils.Helpers.Time; @@ -38,13 +38,16 @@ public class PoolStatistics : IPoolStatistics public IBlockStatistics Blocks { get; private set; } public UInt64 Hashrate { get; private set; } - public string ReadableHashrate { get; private set; } + public UInt64 NetworkHashrate { get; private set; } + public double Difficulty { get; private set; } + public int CurrentBlockHeight { get; private set; } public IList Miners { get { return _minerManager.Miners; } } + private readonly IDaemonClient _daemonClient; private readonly IMinerManager _minerManager; private readonly IStorage _storage; private readonly IHashAlgorithm _hashAlgorithm; @@ -55,8 +58,9 @@ public IList Miners private readonly double _shareMultiplier; - public PoolStatistics(IBlockStatistics blockStatistics, IMinerManager minerManager, IStorage storage, IHashAlgorithm hashAlgorithm) + public PoolStatistics(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IStorage storage, IHashAlgorithm hashAlgorithm) { + _daemonClient = daemonClient; _minerManager = minerManager; _storage = storage; _hashAlgorithm = hashAlgorithm; @@ -78,7 +82,12 @@ private void Recache(object state) double total = hashrates.Sum(pair => pair.Value); Hashrate = Convert.ToUInt64(_shareMultiplier*total/HashrateWindow); - ReadableHashrate = Hashrate.GetReadableHashrate(); + + // read data from daemon + var miningInfo = _daemonClient.GetMiningInfo(); + NetworkHashrate = miningInfo.NetworkHashps; + Difficulty = miningInfo.Difficulty; + CurrentBlockHeight = miningInfo.Blocks; // reset the recache timer. _timer.Change(TimerExpiration * 1000, Timeout.Infinite); diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs index 8e0683592..571fa9cac 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs @@ -22,6 +22,7 @@ #endregion using Coinium.Crypto.Algorithms; +using Coinium.Daemon; using Coinium.Mining.Miners; using Coinium.Persistance; using Coinium.Repository.Context; @@ -45,10 +46,11 @@ public PoolStatisticsFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; } - public IPoolStatistics Get(IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage) + public IPoolStatistics Get(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage) { var @params = new NamedParameterOverloads { + {"daemonClient", daemonClient}, {"blockStatistics", blockStatistics}, {"minerManager", minerManager}, {"hashAlgorithm", hashAlgorithm}, diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs new file mode 100644 index 000000000..8dbe887a6 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -0,0 +1,64 @@ +#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.Dynamic; +using Coinium.Mining.Pools; +using Nancy; + +namespace Coinium.Server.Web.Modules +{ + public class ApiModule: NancyModule + { + public ApiModule(IPoolManager poolManager) + { + Get["/api"] = _ => View["api", new IndexModel + { + Global = poolManager.Statistics, + Pools = poolManager.GetPools() + }]; + + Get["/api/global"] = _ => + { + var algorithms = new Dictionary(); + + foreach (var algo in poolManager.Statistics.Algorithms) + { + dynamic @obj = new ExpandoObject(); + algorithms.Add(algo.Name, @obj); + @obj.hashrate = algo.Hashrate; + @obj.workers = algo.Workers; + } + + var globalStats = new + { + hashrate = poolManager.Statistics.Hashrate, + workers = poolManager.Statistics.Workers, + algorithms = algorithms, + }; + + return Response.AsJson(globalStats); + }; + } + } +} diff --git a/src/CoiniumServ/web/default/api.cshtml b/src/CoiniumServ/web/default/api.cshtml new file mode 100644 index 000000000..48ed858b1 --- /dev/null +++ b/src/CoiniumServ/web/default/api.cshtml @@ -0,0 +1,7 @@ +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase + +@{ Layout = "layout.cshtml"; } + +
    + test +
    diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index 676239f0d..e552367a8 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -1,11 +1,12 @@ -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@using Coinium.Coin.Helpers +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; }
    -
    +

    Overall Statistics

    @@ -20,10 +21,10 @@ - - @Model.Global.Workers - @Model.Global.ReadableHashrate - + + @Model.Global.Workers + @Model.Global.Hashrate.GetReadableHashrate() +
    @@ -32,7 +33,7 @@
    -
    +

    Per Algorithm Statistics

    @@ -53,7 +54,7 @@ @algorithm.Name @algorithm.Workers - @algorithm.ReadableHashrate + @algorithm.Hashrate.GetReadableHashrate() } @@ -62,9 +63,13 @@
    + +
    + +
    -
    +

    Per Pool Statistics

    @@ -75,9 +80,12 @@ Pool - Algorithm - Workers Hashrate + Network + Difficulty + Workers + Algorithm + Current Block @@ -85,9 +93,12 @@ { @pool.Config.Coin.Name - @pool.Config.Coin.Algorithm + @pool.Statistics.Hashrate.GetReadableHashrate() + @pool.Statistics.NetworkHashrate.GetReadableHashrate() + @pool.Statistics.Difficulty @pool.Statistics.Miners.Count - @pool.Statistics.ReadableHashrate + @pool.Config.Coin.Algorithm + @pool.Statistics.CurrentBlockHeight } diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 957f36129..1c3f29d38 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -1,111 +1,126 @@ @using System @using System.Linq +@using Coinium.Coin.Helpers @using Coinium.Persistance @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } - - -
    -
    -
    -
    -

    Latest Blocks

    -
    -
    -
    - - - - - - - - - - - - @foreach (var block in Model.Statistics.Blocks.Latest) - { - - - - - - - - } - -
    Block Status Amount Hash TxHash
    @block.Height - @switch (block.Status) - { - case PersistedBlockStatus.Pending: - @block.Status - break; - case PersistedBlockStatus.Orphan: - @block.Status - break; - case PersistedBlockStatus.Confirmed: - @block.Status - break; - } - @block.OutstandingHashes.Total@block.OutstandingHashes.BlockHash.Substring(0,10)..@block.OutstandingHashes.TransactionHash.Substring(0, 10)..
    -
    -
    -
    -
    -
    - + +
    +
    +
    +
    +

    Latest Blocks

    +
    +
    +
    + + + + + + + + + + + + @foreach (var block in Model.Statistics.Blocks.Latest) + { + + + + + + + + } + +
    Block Status Amount Hash TxHash
    @block.Height + @switch (block.Status) + { + case PersistedBlockStatus.Pending: + @block.Status + break; + case PersistedBlockStatus.Orphan: + @block.Status + break; + case PersistedBlockStatus.Confirmed: + @block.Status + break; + } + @block.OutstandingHashes.Total@block.OutstandingHashes.BlockHash.Substring(0, 10)..@block.OutstandingHashes.TransactionHash.Substring(0, 10)..
    +
    +
    +
    +
    +
    From f31fbf5d9d8b3c9633d2482c084ef9209dec043b Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 12 Jul 2014 17:33:13 +0300 Subject: [PATCH 055/230] Re-factored persisted blocks. Started re-factoring statistics objects. --- src/CoiniumServ/CoiniumServ.csproj | 34 +++++- src/CoiniumServ/Mining/Pools/IPool.cs | 2 + src/CoiniumServ/Mining/Pools/IPoolManager.cs | 2 + src/CoiniumServ/Mining/Pools/Pool.cs | 10 +- src/CoiniumServ/Mining/Pools/PoolManager.cs | 11 +- .../Mining/Pools/Statistics/AlgoStats.cs | 34 ++++++ .../Pools/Statistics/BlockStatistics.cs | 39 ++++--- .../Mining/Pools/Statistics/BlockStats.cs | 36 ++++++ .../Pools/Statistics/GlobalStatistics.cs | 1 - .../Mining/Pools/Statistics/GlobalStats.cs | 24 ++++ .../Mining/Pools/Statistics/IAlgoStats.cs | 12 ++ .../Pools/Statistics/IBlockStatistics.cs | 1 + .../Mining/Pools/Statistics/IBlockStats.cs | 13 +++ .../Mining/Pools/Statistics/IGlobalStats.cs | 15 +++ .../Pools/Statistics/IPerAlgorithmStats.cs | 12 ++ .../Mining/Pools/Statistics/IPerPoolStats.cs | 21 ++++ .../Mining/Pools/Statistics/IPoolStats.cs | 12 ++ .../Mining/Pools/Statistics/IStatistics.cs | 36 ++++++ .../Statistics/IStatisticsObjectFactory.cs | 40 +++++++ .../Pools/Statistics/IStatisticsProvider.cs | 30 +++++ .../Pools/Statistics/PerAlgorithmStats.cs | 12 ++ .../Mining/Pools/Statistics/PerPoolStats.cs | 66 +++++++++++ .../Mining/Pools/Statistics/PoolStats.cs | 31 +++++ .../Mining/Pools/Statistics/Statistics.cs | 46 ++++++++ .../Statistics/StatisticsObjectFactory.cs | 84 ++++++++++++++ src/CoiniumServ/Payments/IPaymentRound.cs | 4 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 69 ++++++----- src/CoiniumServ/Payments/PaymentRound.cs | 13 ++- .../Persistance/Blocks/BlockStatus.cs | 33 ++++++ .../Persistance/Blocks/ConfirmedBlock.cs | 31 +++++ .../HashCandidate.cs} | 12 +- .../Persistance/Blocks/IConfirmedBlock.cs | 12 ++ .../Persistance/Blocks/IFinalizedBlock.cs | 29 +++++ .../IHashCandidate.cs} | 9 +- .../Persistance/Blocks/IKickedBlock.cs | 12 ++ .../Persistance/Blocks/IOrphanedBlock.cs | 12 ++ .../Persistance/Blocks/IPendingBlock.cs | 40 +++++++ .../{ => Blocks}/IPersistedBlock.cs | 21 +--- .../Persistance/Blocks/KickedBlock.cs | 31 +++++ .../Persistance/Blocks/OrphanedBlock.cs | 31 +++++ .../Persistance/Blocks/PendingBlock.cs | 109 ++++++++++++++++++ src/CoiniumServ/Persistance/IStorage.cs | 3 +- src/CoiniumServ/Persistance/PersistedBlock.cs | 86 -------------- src/CoiniumServ/Persistance/Redis/Redis.cs | 107 +++++++++++++---- .../Repository/Registries/ClassRegistry.cs | 4 + .../Repository/Registries/FactoryRegistry.cs | 1 + src/CoiniumServ/Server/Web/Modules/Api.cs | 16 ++- src/CoiniumServ/web/default/pool.cshtml | 15 ++- src/Tests/Mining/Pools/PoolTests.cs | 10 +- 49 files changed, 1120 insertions(+), 214 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/BlockStatus.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs rename src/CoiniumServ/Persistance/{PersistedBlockHashes.cs => Blocks/HashCandidate.cs} (82%) create mode 100644 src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs rename src/CoiniumServ/Persistance/{IPersistedBlockHashes.cs => Blocks/IHashCandidate.cs} (87%) create mode 100644 src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs rename src/CoiniumServ/Persistance/{ => Blocks}/IPersistedBlock.cs (74%) create mode 100644 src/CoiniumServ/Persistance/Blocks/KickedBlock.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs create mode 100644 src/CoiniumServ/Persistance/Blocks/PendingBlock.cs delete mode 100644 src/CoiniumServ/Persistance/PersistedBlock.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 851c426e6..a841753f8 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,8 +110,15 @@ + + + + + + + @@ -126,15 +133,25 @@ + + + + + + + + + + @@ -148,10 +165,19 @@ - - - - + + + + + + + + + + + + + diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index fbafbfd2a..86b1a8372 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -32,6 +32,8 @@ public interface IPool IPoolStatistics Statistics { get; } + IPerPoolStats Stats { get; } + /// /// Initializes the specified bind ip. /// diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index 4454290e9..81f5d1e4a 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -30,6 +30,8 @@ public interface IPoolManager { IGlobalStatistics Statistics { get; } + IStatistics NewStatistics { get; } + IList GetPools(); IPool GetBySymbol(string symbol); diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index b4feb420f..df86e6b58 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -51,6 +51,7 @@ public class Pool : IPool public IPoolConfig Config { get; private set; } public IPoolStatistics Statistics { get; private set; } + public IPerPoolStats Stats { get; private set; } private readonly IDaemonClient _daemonClient; private readonly IServerFactory _serverFactory; @@ -64,6 +65,7 @@ public class Pool : IPool private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IPoolStatisticsFactory _poolStatisticsFactory; private readonly IBlockStatisticsFactory _blockStatisticsFactory; + private readonly IStatisticsObjectFactory _statisticsObjectFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -105,7 +107,8 @@ public Pool( IStorageFactory storageFactory, IPaymentProcessorFactory paymentProcessorFactory, IPoolStatisticsFactory poolStatisticsFactory, - IBlockStatisticsFactory blockStatisticsFactory) + IBlockStatisticsFactory blockStatisticsFactory, + IStatisticsObjectFactory statisticsObjectFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); @@ -132,6 +135,7 @@ public Pool( _paymentProcessorFactory = paymentProcessorFactory; _poolStatisticsFactory = poolStatisticsFactory; _blockStatisticsFactory = blockStatisticsFactory; + _statisticsObjectFactory = statisticsObjectFactory; GenerateInstanceId(); } @@ -185,6 +189,10 @@ private void InitManagers() var blockStatistics = _blockStatisticsFactory.Get(_daemonClient, _storage); Statistics = _poolStatisticsFactory.Get(_daemonClient, blockStatistics, _minerManager, _hashAlgorithm, _storage); + + + var blockStats = _statisticsObjectFactory.GetBlockStats(_storage); + Stats = _statisticsObjectFactory.GetPerPoolStats(_daemonClient, _hashAlgorithm, blockStats, _storage); } private void InitServers() diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 48b00236e..74619be65 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -35,6 +35,7 @@ namespace Coinium.Mining.Pools public class PoolManager : IPoolManager { public IGlobalStatistics Statistics { get; private set; } + public IStatistics NewStatistics { get; private set; } private readonly List _pools = new List(); @@ -44,18 +45,22 @@ public class PoolManager : IPoolManager private readonly IGlobalStatisticsFactory _algorithmStatisticsFactory; - public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IGlobalStatisticsFactory algorithmStatisticsFactory) + private readonly IStatisticsObjectFactory _objectFactory; + + public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IStatisticsObjectFactory objectFactory, IGlobalStatisticsFactory algorithmStatisticsFactory) { _poolFactory = poolFactory; _poolConfigFactory = poolConfigFactory; + _objectFactory = objectFactory; _algorithmStatisticsFactory = algorithmStatisticsFactory; } public void Run() { - Statistics = _algorithmStatisticsFactory.Get(this); + LoadConfigs(); - LoadConfigs(); + Statistics = _algorithmStatisticsFactory.Get(this); + NewStatistics = _objectFactory.GetStatistics(); } public void LoadConfigs() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs new file mode 100644 index 000000000..05394e72d --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public class AlgoStats:IAlgoStats + { + private readonly Dictionary _algorithms; + + public AlgoStats() + { + _algorithms = new Dictionary(); + + _algorithms.Add("test", new PerAlgorithmStats()); + _algorithms.Add("test2", new PerAlgorithmStats()); + _algorithms.Add("test3", new PerAlgorithmStats()); + _algorithms.Add("test4", new PerAlgorithmStats()); + } + + public IEnumerator> GetEnumerator() + { + return _algorithms.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs index b54503116..3b7c12ecf 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs @@ -27,6 +27,7 @@ using Coinium.Daemon; using Coinium.Daemon.Exceptions; using Coinium.Persistance; +using Coinium.Persistance.Blocks; namespace Coinium.Mining.Pools.Statistics { @@ -81,25 +82,25 @@ private void Recache(object state) // TODO: duplicate code from payment processor. private void CheckBlocks(IEnumerable blocks) { - foreach (var block in blocks) - { - foreach (var hashes in block.Hashes) - { - CheckBlockHashes(hashes); - } - } + //foreach (var block in blocks) + //{ + // foreach (var hashes in block) + // { + // CheckBlockHashes(hashes); + // } + //} } // TODO: duplicate code from payment processor. - private void CheckBlockHashes(IPersistedBlockHashes hashes) + private void CheckBlockHashes(IHashCandidate candidate) { try { // get the transaction. - var transaction = _daemonClient.GetTransaction(hashes.TransactionHash); + var transaction = _daemonClient.GetTransaction(candidate.TransactionHash); // total amount of coins contained in the block. - hashes.Total = transaction.Details.Sum(output => (decimal)output.Amount); + candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); // get the output transaction that targets pools central wallet. var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); @@ -107,34 +108,34 @@ private void CheckBlockHashes(IPersistedBlockHashes hashes) // make sure output for the pool central wallet exists if (poolOutput == null) { - hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. - hashes.Reward = 0; + candidate.Status = BlockStatus.Kicked; // kick the hash. + candidate.Reward = 0; } else { switch (poolOutput.Category) { case "immature": - hashes.Status = PersistedBlockStatus.Pending; + candidate.Status = BlockStatus.Pending; break; case "orphan": - hashes.Status = PersistedBlockStatus.Orphan; + candidate.Status = BlockStatus.Orphaned; break; case "generate": - hashes.Status = PersistedBlockStatus.Confirmed; + candidate.Status = BlockStatus.Confirmed; break; default: - hashes.Status = PersistedBlockStatus.Pending; + candidate.Status = BlockStatus.Pending; break; } - hashes.Reward = (decimal)poolOutput.Amount; + candidate.Reward = (decimal)poolOutput.Amount; } } catch (RpcException) { - hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. - hashes.Reward = 0; + candidate.Status = BlockStatus.Kicked; // kick the candidate. + candidate.Reward = 0; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs new file mode 100644 index 000000000..c469e02a4 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Coinium.Persistance; +using Coinium.Persistance.Blocks; + +namespace Coinium.Mining.Pools.Statistics +{ + public class BlockStats:IBlockStats + { + private IEnumerable _blocks; + + private readonly IStorage _storage; + + public BlockStats(IStorage storage) + { + _storage = storage; + } + + public void Recache() + { + _blocks = _storage.GetAllBlocks().OrderByDescending(x => x.Key).Take(20).Select(item => item.Value).ToList(); + } + + public IEnumerator GetEnumerator() + { + return _blocks.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs index 981b56f88..4a3f80d9d 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs @@ -25,7 +25,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Coinium.Coin.Helpers; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs new file mode 100644 index 000000000..d68f39a1e --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public class GlobalStats : IGlobalStats, IStatisticsProvider + { + public UInt64 Hashrate { get; private set; } + public UInt32 WorkerCount { get; private set; } + + public GlobalStats() + { + + } + + public void Recache() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs new file mode 100644 index 000000000..d02249f61 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IAlgoStats: IEnumerable> + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs index d001b567e..4c6d99989 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs @@ -23,6 +23,7 @@ using System.Collections.Generic; using Coinium.Persistance; +using Coinium.Persistance.Blocks; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs new file mode 100644 index 000000000..90f546e7f --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Coinium.Persistance.Blocks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IBlockStats : IStatisticsProvider, IEnumerable + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs new file mode 100644 index 000000000..9908c57f8 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IGlobalStats + { + UInt64 Hashrate { get; } + + UInt32 WorkerCount { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs new file mode 100644 index 000000000..d5480c7ab --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IPerAlgorithmStats + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs new file mode 100644 index 000000000..01255a584 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IPerPoolStats: IStatisticsProvider + { + UInt64 Hashrate { get; } + + UInt64 NetworkHashrate { get; } + + double Difficulty { get; } + + int CurrentBlock { get; } + + IBlockStats LatestBlocks { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs new file mode 100644 index 000000000..2e95b0e4c --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IPoolStats : IEnumerable> + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs new file mode 100644 index 000000000..f7d7d5093 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs @@ -0,0 +1,36 @@ +#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; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IStatistics + { + IGlobalStats Global { get; } + + IAlgoStats Algorithms { get; } + + IPoolStats Pools { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs new file mode 100644 index 000000000..446621cd9 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -0,0 +1,40 @@ +#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 Coinium.Crypto.Algorithms; +using Coinium.Daemon; +using Coinium.Persistance; + +namespace Coinium.Mining.Pools.Statistics +{ + public interface IStatisticsObjectFactory + { + IStatistics GetStatistics(); + + IPoolStats GetPoolStats(IPoolManager poolManager); + + IPerPoolStats GetPerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage); + + IBlockStats GetBlockStats(IStorage storage); + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs new file mode 100644 index 000000000..367f00bec --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs @@ -0,0 +1,30 @@ +#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 Coinium.Mining.Pools.Statistics +{ + public interface IStatisticsProvider + { + void Recache(); + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs new file mode 100644 index 000000000..e39cca686 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Mining.Pools.Statistics +{ + public class PerAlgorithmStats:IPerAlgorithmStats + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs new file mode 100644 index 000000000..33ec268e3 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Coinium.Crypto.Algorithms; +using Coinium.Daemon; +using Coinium.Persistance; +using Coinium.Utils.Helpers.Time; +using HashLib; + +namespace Coinium.Mining.Pools.Statistics +{ + public class PerPoolStats:IPerPoolStats + { + public ulong Hashrate { get; private set; } + public ulong NetworkHashrate { get; private set; } + public double Difficulty { get; private set; } + public int CurrentBlock { get; private set; } + public IBlockStats LatestBlocks { get; private set; } + + private readonly IDaemonClient _daemonClient; + private readonly IStorage _storage; + private readonly IHashAlgorithm _hashAlgorithm; + + private readonly double _shareMultiplier; + private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ + + public PerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage ) + { + _daemonClient = daemonClient; + _hashAlgorithm = hashAlgorithm; + LatestBlocks = blockStatistics; + _storage = storage; + + _shareMultiplier = Math.Pow(2, 32) / _hashAlgorithm.Multiplier; + } + + public void Recache() + { + ReadCoinData(); + ReadHashrate(); + + LatestBlocks.Recache(); + } + + private void ReadHashrate() + { + // read hashrate stats. + var windowTime = TimeHelpers.NowInUnixTime() - HashrateWindow; + _storage.DeleteExpiredHashrateData(windowTime); + var hashrates = _storage.GetHashrateData(windowTime); + + double total = hashrates.Sum(pair => pair.Value); + Hashrate = Convert.ToUInt64(_shareMultiplier * total / HashrateWindow); + } + + private void ReadCoinData() + { + var miningInfo = _daemonClient.GetMiningInfo(); + NetworkHashrate = miningInfo.NetworkHashps; + Difficulty = miningInfo.Difficulty; + CurrentBlock = miningInfo.Blocks; + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs new file mode 100644 index 000000000..8dcf0cfd9 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Coinium.Mining.Pools.Statistics +{ + public class PoolStats:IPoolStats + { + private readonly Dictionary _pools; + + public PoolStats(IPoolManager poolManager) + { + _pools = new Dictionary(); + + foreach (var pool in poolManager.GetPools()) + { + _pools.Add(pool.Config.Coin.Name, pool.Stats); + pool.Stats.Recache(); + } + } + + public IEnumerator> GetEnumerator() + { + return _pools.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs new file mode 100644 index 000000000..798a922a3 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -0,0 +1,46 @@ +#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; + +namespace Coinium.Mining.Pools.Statistics +{ + public class Statistics:IStatistics, IStatisticsProvider + { + public IGlobalStats Global { get; private set; } + public IAlgoStats Algorithms { get; private set; } + public IPoolStats Pools { get; private set; } + + public Statistics(IPoolManager poolManager, IStatisticsObjectFactory statisticsObjectFactory) + { + Pools = statisticsObjectFactory.GetPoolStats(poolManager); + Global = new GlobalStats(); + Algorithms = new AlgoStats(); + } + + public void Recache() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs new file mode 100644 index 000000000..add088212 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -0,0 +1,84 @@ +#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 Coinium.Crypto.Algorithms; +using Coinium.Daemon; +using Coinium.Persistance; +using Coinium.Repository.Context; +using Nancy.TinyIoc; + +namespace Coinium.Mining.Pools.Statistics +{ + public class StatististicsObjectFactory : IStatisticsObjectFactory + { + /// + /// The _kernel + /// + private readonly IApplicationContext _applicationContext; + + /// + /// Initializes a new instance of the class. + /// + /// The application context. + public StatististicsObjectFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public IStatistics GetStatistics() + { + var @params = new NamedParameterOverloads + { }; + + return _applicationContext.Container.Resolve(@params); + } + + public IPoolStats GetPoolStats(IPoolManager poolManager) + { + return _applicationContext.Container.Resolve(); + } + + public IPerPoolStats GetPerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"daemonClient", daemonClient}, + {"hashAlgorithm", hashAlgorithm}, + {"blockStatistics", blockStatistics}, + {"storage", storage}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + public IBlockStats GetBlockStats(IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"storage", storage}, + }; + + return _applicationContext.Container.Resolve(@params); + } + } +} diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index e50b40e08..fb44ddb1c 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -22,13 +22,13 @@ #endregion using System.Collections.Generic; -using Coinium.Persistance; +using Coinium.Persistance.Blocks; namespace Coinium.Payments { public interface IPaymentRound { - IPersistedBlock Block {get;} + IFinalizedBlock Block { get; } Dictionary Shares { get; } diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 4775952df..1f9cec7af 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -29,6 +29,7 @@ using Coinium.Daemon; using Coinium.Daemon.Exceptions; using Coinium.Persistance; +using Coinium.Persistance.Blocks; using Serilog; namespace Coinium.Payments @@ -94,16 +95,16 @@ private void RunPayments(object state) { _stopWatch.Start(); - var blocks = _storage.GetPendingBlocks(); // get all the pending blocks. - CheckBlocks(blocks); - var rounds = GetPaymentRounds(blocks); // get the list of rounds that should be paid. + + 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. 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. ExecutePayments(workerBalances); // execute the payments. - ProcessRemainingBalances(workerBalances); // process the remaining balances. - ProcessRounds(rounds); // process the rounds. Log.ForContext().Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds/1000); @@ -136,7 +137,7 @@ private IList CalculateRewards(IEnumerable rounds // add rewards by rounds foreach (var round in rounds) { - if (round.Block.Status != PersistedBlockStatus.Confirmed) // only pay to confirmed rounds. + if (round.Block.Status != BlockStatus.Confirmed) // only pay to confirmed rounds. continue; foreach (var pair in round.Payouts) // loop through all payouts for the rounds @@ -199,17 +200,17 @@ private void ProcessRounds(IEnumerable rounds) { foreach (var round in rounds) { - if (round.Block.OutstandingHashes.Status == PersistedBlockStatus.Pending) // if the block is still pending, + if (round.Block.Status == BlockStatus.Pending) // if the block is still pending, continue; // just skip it. - switch (round.Block.OutstandingHashes.Status) + switch (round.Block.Status) { - case PersistedBlockStatus.Confirmed: + case BlockStatus.Confirmed: _storage.DeleteShares(round); // delete the associated shares. _storage.MoveBlock(round); // move pending block to appropriate place. break; - case PersistedBlockStatus.Kicked: - case PersistedBlockStatus.Orphan: + 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. break; @@ -232,26 +233,40 @@ private void AssignSharesToRounds(IList rounds) } } - private void CheckBlocks(IEnumerable blocks) + private IList GetFinalizedBlocks(IEnumerable blocks) { + var finalizedBlocks = new List(); + foreach (var block in blocks) { - foreach (var hashes in block.Hashes) + foreach (var candidate in block.Candidates) { - CheckBlockHashes(hashes); + CheckCandidates(candidate); } + + block.Check(); + + if(block.IsFinalized) + finalizedBlocks.Add(block.Finalized); } + + return finalizedBlocks; + } + + private IEnumerable GetConfirmedBlocks(IEnumerable blocks) + { + return blocks.OfType().ToList(); } - private void CheckBlockHashes(IPersistedBlockHashes hashes) + private void CheckCandidates(IHashCandidate candidate) { try { // get the transaction. - var transaction = _daemonClient.GetTransaction(hashes.TransactionHash); + var transaction = _daemonClient.GetTransaction(candidate.TransactionHash); // total amount of coins contained in the block. - hashes.Total = transaction.Details.Sum(output => (decimal)output.Amount); + candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); // get the output transaction that targets pools central wallet. var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); @@ -259,38 +274,38 @@ private void CheckBlockHashes(IPersistedBlockHashes hashes) // make sure output for the pool central wallet exists if (poolOutput == null) { - hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. - hashes.Reward = 0; + candidate.Status = BlockStatus.Kicked; // kick the hash. + candidate.Reward = 0; } else { switch (poolOutput.Category) { case "immature": - hashes.Status = PersistedBlockStatus.Pending; + candidate.Status = BlockStatus.Pending; break; case "orphan": - hashes.Status = PersistedBlockStatus.Orphan; + candidate.Status = BlockStatus.Orphaned; break; case "generate": - hashes.Status = PersistedBlockStatus.Confirmed; + candidate.Status = BlockStatus.Confirmed; break; default: - hashes.Status = PersistedBlockStatus.Pending; + candidate.Status = BlockStatus.Pending; break; } - hashes.Reward = (decimal) poolOutput.Amount; + candidate.Reward = (decimal) poolOutput.Amount; } } catch (RpcException) { - hashes.Status = PersistedBlockStatus.Kicked; // kick the hash. - hashes.Reward = 0; + candidate.Status = BlockStatus.Kicked; // kick the hash. + candidate.Reward = 0; } } - 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 1664bc012..2bcd52251 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -23,18 +23,18 @@ using System.Collections.Generic; using System.Linq; -using Coinium.Persistance; +using Coinium.Persistance.Blocks; namespace Coinium.Payments { public class PaymentRound:IPaymentRound { - public IPersistedBlock Block { get; private set; } + public IFinalizedBlock Block { get; private set; } public Dictionary Shares { get; private set; } public Dictionary Payouts { get; private set; } - public PaymentRound(IPersistedBlock block) + public PaymentRound(IFinalizedBlock block) { Block = block; Payouts = new Dictionary(); @@ -48,7 +48,8 @@ public void AddShares(IDictionary shares) Shares.Add(pair.Key, pair.Value); } - CalculatePayouts(); + if(Block.Status == BlockStatus.Confirmed) + CalculatePayouts(); } private void CalculatePayouts() @@ -59,7 +60,7 @@ private void CalculatePayouts() foreach (var pair in Shares) { var percent = pair.Value/totalShares; - var workerRewardInSatoshis = (decimal) percent*Block.OutstandingHashes.Reward; + var workerRewardInSatoshis = (decimal)percent * Block.Reward; Payouts.Add(pair.Key, workerRewardInSatoshis); } @@ -67,7 +68,7 @@ private void CalculatePayouts() public override string ToString() { - return string.Format("Amount: {0}, Block: {1}", Block.OutstandingHashes.Reward, Block); + return string.Format("Amount: {0}, Block: {1}", Block.Reward, Block); } } } diff --git a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs new file mode 100644 index 000000000..5ba7d595c --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs @@ -0,0 +1,33 @@ +#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 Coinium.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 new file mode 100644 index 000000000..066a1ed11 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs @@ -0,0 +1,31 @@ +namespace Coinium.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/PersistedBlockHashes.cs b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs similarity index 82% rename from src/CoiniumServ/Persistance/PersistedBlockHashes.cs rename to src/CoiniumServ/Persistance/Blocks/HashCandidate.cs index f5c9f6e80..c547be3a8 100644 --- a/src/CoiniumServ/Persistance/PersistedBlockHashes.cs +++ b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs @@ -21,21 +21,21 @@ // #endregion -namespace Coinium.Persistance +namespace Coinium.Persistance.Blocks { - public class PersistedBlockHashes : IPersistedBlockHashes + public class HashCandidate : IHashCandidate { public string BlockHash { get; private set; } public string TransactionHash { get; private set; } - public PersistedBlockStatus Status { get; set; } + public decimal Amount { get; set; } public decimal Reward { get; set; } - public decimal Total { get; set; } + public BlockStatus Status { get; set; } - public PersistedBlockHashes(string blockHash, string transactionHash) + public HashCandidate(string blockHash, string transactionHash) { BlockHash = blockHash; TransactionHash = transactionHash; - Status = PersistedBlockStatus.Pending; + Status = BlockStatus.Pending; } public override string ToString() diff --git a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs new file mode 100644 index 000000000..5ce1e7889 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Persistance.Blocks +{ + public interface IConfirmedBlock:IFinalizedBlock + { + } +} diff --git a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs new file mode 100644 index 000000000..3412934f1 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs @@ -0,0 +1,29 @@ +#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 Coinium.Persistance.Blocks +{ + public interface IFinalizedBlock:IPersistedBlock + { + } +} diff --git a/src/CoiniumServ/Persistance/IPersistedBlockHashes.cs b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs similarity index 87% rename from src/CoiniumServ/Persistance/IPersistedBlockHashes.cs rename to src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs index c9129b000..7a49ea909 100644 --- a/src/CoiniumServ/Persistance/IPersistedBlockHashes.cs +++ b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs @@ -21,15 +21,14 @@ // #endregion -namespace Coinium.Persistance +namespace Coinium.Persistance.Blocks { - public interface IPersistedBlockHashes + public interface IHashCandidate { string BlockHash { get; } string TransactionHash { get; } - PersistedBlockStatus Status { get; set; } + decimal Amount { get; set; } decimal Reward { get; set; } - - decimal Total { get; set; } + BlockStatus Status { get; set; } } } diff --git a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs new file mode 100644 index 000000000..5610a85d7 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Persistance.Blocks +{ + public interface IKickedBlock:IFinalizedBlock + { + } +} diff --git a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs new file mode 100644 index 000000000..21bc9b46b --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coinium.Persistance.Blocks +{ + public interface IOrphanedBlock:IFinalizedBlock + { + } +} diff --git a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs new file mode 100644 index 000000000..bba3ed75f --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs @@ -0,0 +1,40 @@ +#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; + +namespace Coinium.Persistance.Blocks +{ + public interface IPendingBlock: IPersistedBlock + { + bool IsFinalized { get; } + + IFinalizedBlock Finalized { get; } + + List Candidates { get; } + + void AddHashCandidate(IHashCandidate hash); + + void Check(); + } +} diff --git a/src/CoiniumServ/Persistance/IPersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs similarity index 74% rename from src/CoiniumServ/Persistance/IPersistedBlock.cs rename to src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs index 9e6fe703b..8b8daff9c 100644 --- a/src/CoiniumServ/Persistance/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs @@ -22,25 +22,16 @@ #endregion using System; -using System.Collections.Generic; -namespace Coinium.Persistance +namespace Coinium.Persistance.Blocks { public interface IPersistedBlock { UInt32 Height { get; } - List Hashes { get; } - PersistedBlockStatus Status { get; } - IPersistedBlockHashes OutstandingHashes { get; } - - void AddHashes(IPersistedBlockHashes hash); - } - - public enum PersistedBlockStatus - { - Pending, - Kicked, - Orphan, - Confirmed + BlockStatus Status { get; } + string BlockHash { get; } + string TransactionHash { get; } + decimal Reward { get; } + decimal Amount { get; } } } diff --git a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs new file mode 100644 index 000000000..d0cc34420 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs @@ -0,0 +1,31 @@ +namespace Coinium.Persistance.Blocks +{ + public class KickedBlock:IKickedBlock + { + 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 KickedBlock(uint height, string blockHash, string transactionHash, decimal amount, decimal reward) + { + 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/Blocks/OrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs new file mode 100644 index 000000000..78e337ed3 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs @@ -0,0 +1,31 @@ +namespace Coinium.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 new file mode 100644 index 000000000..d2966b9d6 --- /dev/null +++ b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs @@ -0,0 +1,109 @@ +#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.Collections.Generic; +using System.Linq; + +namespace Coinium.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 : "Many.."; } + } + + public string TransactionHash + { + get { return IsFinalized ? Finalized.BlockHash : "Many.."; } + } + + 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/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index b377acd92..458e4152e 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using Coinium.Mining.Shares; using Coinium.Payments; +using Coinium.Persistance.Blocks; namespace Coinium.Persistance { @@ -50,7 +51,7 @@ public interface IStorage IDictionary GetHashrateData(int since); - IList GetPendingBlocks(); + IList GetPendingBlocks(); IDictionary GetAllBlocks(); diff --git a/src/CoiniumServ/Persistance/PersistedBlock.cs b/src/CoiniumServ/Persistance/PersistedBlock.cs deleted file mode 100644 index 3903f0abe..000000000 --- a/src/CoiniumServ/Persistance/PersistedBlock.cs +++ /dev/null @@ -1,86 +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 Coinium.Persistance -{ - public class PersistedBlock : IPersistedBlock - { - public uint Height { get; private set; } - - public List Hashes { get; private set; } - - public IPersistedBlockHashes OutstandingHashes - { - get - { - switch (Status) - { - case PersistedBlockStatus.Pending: - return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Pending); - case PersistedBlockStatus.Kicked: - return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Kicked); - case PersistedBlockStatus.Orphan: - return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Orphan); - case PersistedBlockStatus.Confirmed: - return Hashes.FirstOrDefault(hash => hash.Status == PersistedBlockStatus.Confirmed); - } - - return null; - } - } - - public PersistedBlockStatus Status - { - get - { - if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Confirmed)) // if any hash is confirmed - return PersistedBlockStatus.Confirmed; // block is confirmed - else if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Orphan)) // if any hash is orphaned - return PersistedBlockStatus.Orphan; // block is orphaned - else if (Hashes.Any(hashes => hashes.Status == PersistedBlockStatus.Kicked)) // if any hash is kicked - return PersistedBlockStatus.Kicked; // block is kicked - else - return PersistedBlockStatus.Pending; // block is pending - } - } - - public PersistedBlock(uint height) - { - Height = height; - Hashes = new List(); - } - - public void AddHashes(IPersistedBlockHashes hash) - { - Hashes.Add(hash); - } - - public override string ToString() - { - return string.Format("Height: {0}, Status: {1}, Outstanding: {2}", Height, Status,OutstandingHashes); - } - } -} diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 3eb9c02a1..055f6ed34 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -26,9 +26,11 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using Coinium.Daemon.Responses; using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Payments; +using Coinium.Persistance.Blocks; using Coinium.Utils.Configuration; using Coinium.Utils.Extensions; using Coinium.Utils.Helpers.Time; @@ -150,6 +152,9 @@ public void MoveSharesToCurrentRound(IPaymentRound round) if (!IsEnabled || !IsConnected) return; + if (round.Block.Status == BlockStatus.Confirmed || round.Block.Status == BlockStatus.Pending) + return; + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. var currentRound = string.Format("{0}:shares:round:current", coin); // current round key. var roundShares = string.Format("{0}:shares:round:{1}", coin, round.Block.Height); // rounds shares key. @@ -169,6 +174,9 @@ public void MoveBlock(IPaymentRound round) if (!IsEnabled || !IsConnected) return; + if (round.Block.Status == BlockStatus.Pending) + return; + var coin = _poolConfig.Coin.Name.ToLower(); // the coin we are working on. // re-flag the rounds. @@ -177,21 +185,19 @@ public void MoveBlock(IPaymentRound round) switch (round.Block.Status) { - case PersistedBlockStatus.Kicked: + case BlockStatus.Kicked: newKey = string.Format("{0}:blocks:kicked", coin); break; - case PersistedBlockStatus.Orphan: + case BlockStatus.Orphaned: newKey = string.Format("{0}:blocks:orphaned", coin); break; - case PersistedBlockStatus.Confirmed: + case BlockStatus.Confirmed: newKey = string.Format("{0}:blocks:confirmed", coin); break; } - - if (string.IsNullOrEmpty(newKey)) // if the block is still pending - return; // just skip it. - - var entry = string.Format("{0}:{1}", round.Block.OutstandingHashes.BlockHash, round.Block.OutstandingHashes.TransactionHash); + + var entry = string.Format("{0}:{1}", round.Block.BlockHash, round.Block.TransactionHash); + _database.SortedSetRemoveRangeByScoreAsync(pendingKey, round.Block.Height, round.Block.Height, Exclude.None, CommandFlags.FireAndForget); _database.SortedSetAddAsync(newKey, entry, round.Block.Height, CommandFlags.FireAndForget); } @@ -260,12 +266,15 @@ public IDictionary GetHashrateData(int since) return hashrates; } - private IDictionary GetBlocks(string key) + public IList GetPendingBlocks() { - var blocks = new Dictionary(); + var blocks = new Dictionary(); + + 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:{1}", coin, key); + var pendingKey = string.Format("{0}:blocks:pending", coin); var task = _database.SortedSetRangeByRankWithScoresAsync(pendingKey, 0, -1, Order.Ascending, CommandFlags.HighPriority); var results = task.Result; @@ -275,48 +284,96 @@ private IDictionary GetBlocks(string key) var data = result.Element.ToString().Split(':'); var blockHash = data[0]; var transactionHash = data[1]; - var hashes = new PersistedBlockHashes(blockHash, transactionHash); + var hashCandidate = new HashCandidate(blockHash, transactionHash); if (!blocks.ContainsKey((UInt32)result.Score)) - blocks.Add((UInt32)result.Score, new PersistedBlock((UInt32)result.Score)); + blocks.Add((UInt32)result.Score, new PendingBlock((UInt32)result.Score)); var persistedBlock = blocks[(UInt32)result.Score]; - persistedBlock.AddHashes(hashes); + persistedBlock.AddHashCandidate(hashCandidate); } - return blocks; + return blocks.Values.ToList(); } - public IList GetPendingBlocks() + private IEnumerable GetFinalizedBlocks(BlockStatus status) { - var blocks = new List(); + var blocks = new Dictionary(); if (!IsEnabled || !IsConnected) - return blocks; + 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; + + switch (status) + { + case BlockStatus.Kicked: + key = string.Format("{0}:blocks:kicked", coin); + break; + case BlockStatus.Orphaned: + key = string.Format("{0}:blocks:orphaned", coin); + break; + case BlockStatus.Confirmed: + key = string.Format("{0}:blocks:confirmed", coin); + break; + } - return GetBlocks("pending").Values.ToList(); + var task = _database.SortedSetRangeByRankWithScoresAsync(key, 0, -1, Order.Ascending, CommandFlags.HighPriority); + var results = task.Result; + + foreach (var result in results) + { + var data = result.Element.ToString().Split(':'); + var blockHash = data[0]; + var transactionHash = data[1]; + + switch (status) + { + case BlockStatus.Kicked: + blocks.Add((UInt32) result.Score, new KickedBlock((UInt32) result.Score, blockHash, transactionHash, 0, 0)); + break; + case BlockStatus.Orphaned: + blocks.Add((UInt32)result.Score, new OrphanedBlock((UInt32)result.Score, blockHash, transactionHash, 0, 0)); + break; + case BlockStatus.Confirmed: + blocks.Add((UInt32)result.Score, new ConfirmedBlock((UInt32)result.Score, blockHash, transactionHash, 0, 0)); + break; + } + } + + return blocks.Values.ToList(); } public IDictionary GetAllBlocks() { + var blocks = new Dictionary(); if (!IsEnabled || !IsConnected) return blocks; - foreach (var pair in GetBlocks("pending")) + foreach (var block in GetFinalizedBlocks(BlockStatus.Confirmed)) + { + blocks.Add(block.Height, block); + } + + foreach (var block in GetFinalizedBlocks(BlockStatus.Orphaned)) { - blocks.Add(pair.Key, pair.Value); + blocks.Add(block.Height, block); } - foreach (var pair in GetBlocks("confirmed")) + foreach (var block in GetFinalizedBlocks(BlockStatus.Kicked)) { - blocks.Add(pair.Key, pair.Value); + blocks.Add(block.Height, block); } - foreach (var pair in GetBlocks("orphaned")) + foreach (var block in GetPendingBlocks()) { - blocks.Add(pair.Key, pair.Value); + blocks.Add(block.Height, block); } return blocks; diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index dcca215cb..59a01fd62 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -54,6 +54,10 @@ public void RegisterInstances() _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index bf89cd507..c7cddb2f5 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -66,6 +66,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index 8dbe887a6..5bc17928d 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -24,19 +24,20 @@ using System.Collections.Generic; using System.Dynamic; using Coinium.Mining.Pools; +using Coinium.Mining.Pools.Statistics; using Nancy; +using Newtonsoft.Json; namespace Coinium.Server.Web.Modules { public class ApiModule: NancyModule { - public ApiModule(IPoolManager poolManager) + public ApiModule(IPoolManager poolManager, IStatistics statistics) { - Get["/api"] = _ => View["api", new IndexModel + Get["/api"] = _ => { - Global = poolManager.Statistics, - Pools = poolManager.GetPools() - }]; + return "Not implemented yet"; + }; Get["/api/global"] = _ => { @@ -59,6 +60,11 @@ public ApiModule(IPoolManager poolManager) return Response.AsJson(globalStats); }; + + Get["/api/pools"] = _ => + { + return Response.AsJson(statistics); + }; } } } diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 1c3f29d38..a0e158359 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -1,7 +1,9 @@ @using System @using System.Linq @using Coinium.Coin.Helpers +@using Coinium.Daemon.Responses @using Coinium.Persistance +@using Coinium.Persistance.Blocks @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } @@ -101,20 +103,21 @@ @switch (block.Status) { - case PersistedBlockStatus.Pending: + case BlockStatus.Pending: @block.Status break; - case PersistedBlockStatus.Orphan: + case BlockStatus.Orphaned: + case BlockStatus.Kicked: @block.Status break; - case PersistedBlockStatus.Confirmed: + case BlockStatus.Confirmed: @block.Status break; } - @block.OutstandingHashes.Total - @block.OutstandingHashes.BlockHash.Substring(0, 10).. - @block.OutstandingHashes.TransactionHash.Substring(0, 10).. + @block.Amount + @block.BlockHash.Substring(0, 10).. + @block.TransactionHash.Substring(0, 10).. } diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 8c4e8e5ea..0badc0981 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -54,6 +54,7 @@ public class PoolTests private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IPoolStatisticsFactory _poolStatisticsFactory; private readonly IBlockStatisticsFactory _blockStatisticsFactory; + private readonly IStatisticsObjectFactory _statisticsObjectFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -67,6 +68,7 @@ public class PoolTests private readonly IPaymentProcessor _paymentProcessor; private readonly IPoolStatistics _poolStatistics; private readonly IBlockStatistics _blockStatistics; + private readonly IStatistics _statistics; /// /// Initialize mock objects. @@ -84,6 +86,7 @@ public PoolTests() _paymentProcessorFactory = Substitute.For(); _poolStatisticsFactory = Substitute.For(); _blockStatisticsFactory = Substitute.For(); + _statisticsObjectFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -96,6 +99,7 @@ public PoolTests() _paymentProcessor = Substitute.For(); _poolStatistics = Substitute.For(); _blockStatistics = Substitute.For(); + _statistics = Substitute.For(); } /// @@ -116,7 +120,8 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _storageFactory, _paymentProcessorFactory, _poolStatisticsFactory, - _blockStatisticsFactory + _blockStatisticsFactory, + _statisticsObjectFactory ); pool.Should().Not.Be.Null(); @@ -141,7 +146,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _storageFactory, _paymentProcessorFactory, _poolStatisticsFactory, - _blockStatisticsFactory + _blockStatisticsFactory, + _statisticsObjectFactory ); pool.Should().Not.Be.Null(); From e09cab8d8948a68f0164b7356fb237cf4ca70bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sun, 13 Jul 2014 21:41:26 +0300 Subject: [PATCH 056/230] Fixed a tiny bug in pool.cshtml. --- .../Mining/Pools/Statistics/GlobalStats.cs | 32 +++++++++++++++---- .../Statistics/IStatisticsObjectFactory.cs | 4 ++- .../Pools/Statistics/IStatisticsProvider.cs | 2 ++ .../Mining/Pools/Statistics/Statistics.cs | 6 ++-- .../Statistics/StatisticsObjectFactory.cs | 10 +++--- .../Repository/Registries/ClassRegistry.cs | 2 ++ src/CoiniumServ/web/default/pool.cshtml | 4 +-- 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs index d68f39a1e..cf76798ce 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs @@ -1,8 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +#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; namespace Coinium.Mining.Pools.Statistics { @@ -11,7 +31,7 @@ public class GlobalStats : IGlobalStats, IStatisticsProvider public UInt64 Hashrate { get; private set; } public UInt32 WorkerCount { get; private set; } - public GlobalStats() + public GlobalStats(IPoolStats poolStatistics) { } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 446621cd9..8daf24642 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -31,7 +31,9 @@ public interface IStatisticsObjectFactory { IStatistics GetStatistics(); - IPoolStats GetPoolStats(IPoolManager poolManager); + IGlobalStats GetGlobalStatistics(); + + IPoolStats GetPoolStats(); IPerPoolStats GetPerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage); diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs index 367f00bec..a70e83506 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs @@ -21,6 +21,8 @@ // #endregion +using System; + namespace Coinium.Mining.Pools.Statistics { public interface IStatisticsProvider diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index 798a922a3..c84cfea77 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -31,10 +31,10 @@ public class Statistics:IStatistics, IStatisticsProvider public IAlgoStats Algorithms { get; private set; } public IPoolStats Pools { get; private set; } - public Statistics(IPoolManager poolManager, IStatisticsObjectFactory statisticsObjectFactory) + public Statistics(IStatisticsObjectFactory statisticsObjectFactory) { - Pools = statisticsObjectFactory.GetPoolStats(poolManager); - Global = new GlobalStats(); + Pools = statisticsObjectFactory.GetPoolStats(); + Global = statisticsObjectFactory.GetGlobalStatistics(); Algorithms = new AlgoStats(); } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index add088212..402ea7609 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -47,13 +47,15 @@ public StatististicsObjectFactory(IApplicationContext applicationContext) public IStatistics GetStatistics() { - var @params = new NamedParameterOverloads - { }; + return _applicationContext.Container.Resolve(); + } - return _applicationContext.Container.Resolve(@params); + public IGlobalStats GetGlobalStatistics() + { + return _applicationContext.Container.Resolve(); } - public IPoolStats GetPoolStats(IPoolManager poolManager) + public IPoolStats GetPoolStats() { return _applicationContext.Container.Resolve(); } diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 59a01fd62..04090adc7 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -58,6 +58,8 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index a0e158359..7f2674dff 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -116,8 +116,8 @@ } @block.Amount - @block.BlockHash.Substring(0, 10).. - @block.TransactionHash.Substring(0, 10).. + @block.BlockHash.Substring(0, block.BlockHash.Length > 10 ? 10 : block.BlockHash.Length).. + @block.TransactionHash.Substring(0, block.TransactionHash.Length > 10 ? 10 : block.TransactionHash.Length).. } From b1bdc80536b54970914ebcef6d4dd4c7cf3551be Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 15 Jul 2014 14:00:22 +0300 Subject: [PATCH 057/230] More statistics work. --- src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- .../Mining/Pools/Statistics/AlgoStats.cs | 26 ++++++++++++++----- .../Mining/Pools/Statistics/BlockStats.cs | 2 +- .../Mining/Pools/Statistics/GlobalStats.cs | 19 ++++++++++---- .../Mining/Pools/Statistics/IAlgoStats.cs | 2 +- .../Mining/Pools/Statistics/IGlobalStats.cs | 4 +-- .../Pools/Statistics/IPerAlgorithmStats.cs | 7 +++++ .../Mining/Pools/Statistics/IPerPoolStats.cs | 4 +++ .../Mining/Pools/Statistics/IPoolStats.cs | 2 +- .../Statistics/IStatisticsObjectFactory.cs | 6 ++++- .../Pools/Statistics/IStatisticsProvider.cs | 2 +- .../Pools/Statistics/PerAlgorithmStats.cs | 14 ++++++++++ .../Mining/Pools/Statistics/PerPoolStats.cs | 17 +++++++++--- .../Mining/Pools/Statistics/PoolStats.cs | 12 ++++++++- .../Mining/Pools/Statistics/Statistics.cs | 18 ++++++++++--- .../Statistics/StatisticsObjectFactory.cs | 11 +++++++- 16 files changed, 121 insertions(+), 27 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index df86e6b58..2859efb0a 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -192,7 +192,7 @@ private void InitManagers() var blockStats = _statisticsObjectFactory.GetBlockStats(_storage); - Stats = _statisticsObjectFactory.GetPerPoolStats(_daemonClient, _hashAlgorithm, blockStats, _storage); + Stats = _statisticsObjectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, _storage); } private void InitServers() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs index 05394e72d..62263ab6d 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs @@ -7,18 +7,32 @@ namespace Coinium.Mining.Pools.Statistics { - public class AlgoStats:IAlgoStats + public class AlgoStats : IAlgoStats { private readonly Dictionary _algorithms; + private readonly IPoolStats _poolStatistics; - public AlgoStats() + public AlgoStats(IPoolStats poolStatistics) { + _poolStatistics = poolStatistics; _algorithms = new Dictionary(); + } + + public void Recache(object state) + { + foreach (var pair in _algorithms) + { + pair.Value.Reset(); + } + + foreach (var pair in _poolStatistics) + { + if (!_algorithms.ContainsKey(pair.Value.Algorithm)) + _algorithms.Add(pair.Value.Algorithm, new PerAlgorithmStats(pair.Value.Algorithm)); - _algorithms.Add("test", new PerAlgorithmStats()); - _algorithms.Add("test2", new PerAlgorithmStats()); - _algorithms.Add("test3", new PerAlgorithmStats()); - _algorithms.Add("test4", new PerAlgorithmStats()); + _algorithms[pair.Value.Algorithm].Hashrate = pair.Value.Hashrate; + _algorithms[pair.Value.Algorithm].WorkerCount = pair.Value.WorkerCount; + } } public IEnumerator> GetEnumerator() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs index c469e02a4..40fe0fbc1 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs @@ -18,7 +18,7 @@ public BlockStats(IStorage storage) _storage = storage; } - public void Recache() + public void Recache(object state) { _blocks = _storage.GetAllBlocks().OrderByDescending(x => x.Key).Take(20).Select(item => item.Value).ToList(); } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs index cf76798ce..28d5c1100 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs @@ -26,19 +26,28 @@ namespace Coinium.Mining.Pools.Statistics { - public class GlobalStats : IGlobalStats, IStatisticsProvider + public class GlobalStats : IGlobalStats { public UInt64 Hashrate { get; private set; } - public UInt32 WorkerCount { get; private set; } + public Int32 WorkerCount { get; private set; } + + private readonly IPoolStats _poolStatistics; public GlobalStats(IPoolStats poolStatistics) { - + _poolStatistics = poolStatistics; } - public void Recache() + public void Recache(object state) { - throw new NotImplementedException(); + Hashrate = 0; + WorkerCount = 0; + + foreach (var pair in _poolStatistics) + { + Hashrate += pair.Value.Hashrate; + WorkerCount += pair.Value.WorkerCount; + } } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs index d02249f61..820e4f3a6 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs @@ -6,7 +6,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IAlgoStats: IEnumerable> + public interface IAlgoStats: IEnumerable>, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs index 9908c57f8..ac6db9084 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs @@ -6,10 +6,10 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IGlobalStats + public interface IGlobalStats: IStatisticsProvider { UInt64 Hashrate { get; } - UInt32 WorkerCount { get; } + Int32 WorkerCount { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs index d5480c7ab..1ceea38f1 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs @@ -8,5 +8,12 @@ namespace Coinium.Mining.Pools.Statistics { public interface IPerAlgorithmStats { + string Name { get; } + + Int32 WorkerCount { get; set; } + + UInt64 Hashrate { get; set; } + + void Reset(); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs index 01255a584..7b27fc385 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs @@ -12,10 +12,14 @@ public interface IPerPoolStats: IStatisticsProvider UInt64 NetworkHashrate { get; } + Int32 WorkerCount { get; } + double Difficulty { get; } int CurrentBlock { get; } IBlockStats LatestBlocks { get; } + + string Algorithm { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs index 2e95b0e4c..5c85dc61f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs @@ -6,7 +6,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPoolStats : IEnumerable> + public interface IPoolStats : IEnumerable>, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 8daf24642..04c05d842 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -23,6 +23,8 @@ using Coinium.Crypto.Algorithms; using Coinium.Daemon; +using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; namespace Coinium.Mining.Pools.Statistics @@ -33,9 +35,11 @@ public interface IStatisticsObjectFactory IGlobalStats GetGlobalStatistics(); + IAlgoStats GetAlgorithmStatistics(); + IPoolStats GetPoolStats(); - IPerPoolStats GetPerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage); + IPerPoolStats GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage); IBlockStats GetBlockStats(IStorage storage); } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs index a70e83506..c94a0ee0a 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs @@ -27,6 +27,6 @@ namespace Coinium.Mining.Pools.Statistics { public interface IStatisticsProvider { - void Recache(); + void Recache(object state); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs index e39cca686..2d5351414 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs @@ -8,5 +8,19 @@ namespace Coinium.Mining.Pools.Statistics { public class PerAlgorithmStats:IPerAlgorithmStats { + public string Name { get; private set; } + public int WorkerCount { get; set; } + public ulong Hashrate { get; set; } + + public PerAlgorithmStats(string algorithm) + { + Name = algorithm; + } + + public void Reset() + { + Hashrate = 0; + WorkerCount = 0; + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs index 33ec268e3..61ce69ce9 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs @@ -5,6 +5,8 @@ using System.Threading.Tasks; using Coinium.Crypto.Algorithms; using Coinium.Daemon; +using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Utils.Helpers.Time; using HashLib; @@ -15,33 +17,42 @@ public class PerPoolStats:IPerPoolStats { public ulong Hashrate { get; private set; } public ulong NetworkHashrate { get; private set; } + public int WorkerCount { get; private set; } public double Difficulty { get; private set; } public int CurrentBlock { get; private set; } public IBlockStats LatestBlocks { get; private set; } + public string Algorithm { get; private set; } private readonly IDaemonClient _daemonClient; private readonly IStorage _storage; private readonly IHashAlgorithm _hashAlgorithm; + private readonly IMinerManager _minerManager; + private readonly IPoolConfig _poolConfig; private readonly double _shareMultiplier; private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ - public PerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage ) + public PerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) { + _poolConfig = poolConfig; _daemonClient = daemonClient; _hashAlgorithm = hashAlgorithm; + _minerManager = minerManager; LatestBlocks = blockStatistics; _storage = storage; _shareMultiplier = Math.Pow(2, 32) / _hashAlgorithm.Multiplier; } - public void Recache() + public void Recache(object state) { ReadCoinData(); ReadHashrate(); - LatestBlocks.Recache(); + WorkerCount = _minerManager.Miners.Count; + Algorithm = _poolConfig.Coin.Algorithm; + + LatestBlocks.Recache(state); } private void ReadHashrate() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs index 8dcf0cfd9..249541399 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs @@ -6,15 +6,17 @@ namespace Coinium.Mining.Pools.Statistics public class PoolStats:IPoolStats { private readonly Dictionary _pools; + private readonly IPoolManager _poolManager; public PoolStats(IPoolManager poolManager) { + _poolManager = poolManager; _pools = new Dictionary(); + foreach (var pool in poolManager.GetPools()) { _pools.Add(pool.Config.Coin.Name, pool.Stats); - pool.Stats.Recache(); } } @@ -27,5 +29,13 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + public void Recache(object state) + { + foreach (var pool in _poolManager.GetPools()) + { + pool.Stats.Recache(state); + } + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index c84cfea77..fb7620747 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -22,6 +22,7 @@ #endregion using System; +using System.Threading; namespace Coinium.Mining.Pools.Statistics { @@ -31,16 +32,27 @@ public class Statistics:IStatistics, IStatisticsProvider public IAlgoStats Algorithms { get; private set; } public IPoolStats Pools { get; private set; } + private readonly Timer _timer; + private const int TimerExpiration = 10; + public Statistics(IStatisticsObjectFactory statisticsObjectFactory) { Pools = statisticsObjectFactory.GetPoolStats(); Global = statisticsObjectFactory.GetGlobalStatistics(); - Algorithms = new AlgoStats(); + Algorithms = statisticsObjectFactory.GetAlgorithmStatistics(); + + _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + Recache(null); // recache data initially. } - public void Recache() + public void Recache(object state) { - throw new NotImplementedException(); + Global.Recache(state); + Pools.Recache(state); + Algorithms.Recache(state); + + // reset the recache timer. + _timer.Change(TimerExpiration * 1000, Timeout.Infinite); } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index 402ea7609..94b9269fe 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -23,6 +23,8 @@ using Coinium.Crypto.Algorithms; using Coinium.Daemon; +using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Repository.Context; using Nancy.TinyIoc; @@ -55,16 +57,23 @@ public IGlobalStats GetGlobalStatistics() return _applicationContext.Container.Resolve(); } + public IAlgoStats GetAlgorithmStatistics() + { + return _applicationContext.Container.Resolve(); + } + public IPoolStats GetPoolStats() { return _applicationContext.Container.Resolve(); } - public IPerPoolStats GetPerPoolStats(IDaemonClient daemonClient, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) + public IPerPoolStats GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) { var @params = new NamedParameterOverloads { + {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, + {"minerManager",minerManager}, {"hashAlgorithm", hashAlgorithm}, {"blockStatistics", blockStatistics}, {"storage", storage}, From 9257a60680bd3be7a35f2b140341ae3270f2d296 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 15 Jul 2014 14:07:56 +0300 Subject: [PATCH 058/230] More statistics works. --- src/CoiniumServ/Coin/Helpers/Hashrate.cs | 1 - src/CoiniumServ/CoiniumServ.csproj | 14 -- src/CoiniumServ/Daemon/DaemonErrorResponse.cs | 1 - src/CoiniumServ/Daemon/IDaemonBase.cs | 1 - src/CoiniumServ/Daemon/IDaemonClient.cs | 1 - .../Daemon/Responses/MiningInfo.cs | 1 - .../Daemon/Responses/Transaction.cs | 1 - src/CoiniumServ/Mining/Pools/IPool.cs | 3 - src/CoiniumServ/Mining/Pools/IPoolManager.cs | 2 - .../Mining/Pools/IPoolManagerFactory.cs | 1 - src/CoiniumServ/Mining/Pools/Pool.cs | 14 -- src/CoiniumServ/Mining/Pools/PoolManager.cs | 8 +- .../Mining/Pools/PoolManagerFactory.cs | 1 - .../Mining/Pools/Statistics/AlgoStats.cs | 26 +++- .../Pools/Statistics/BlockStatistics.cs | 142 ------------------ .../Statistics/BlockStatisticsFactory.cs | 58 ------- .../Mining/Pools/Statistics/BlockStats.cs | 23 ++- .../Pools/Statistics/GlobalStatistics.cs | 82 ---------- .../Statistics/GlobalStatisticsFactory.cs | 49 ------ .../Mining/Pools/Statistics/GlobalStats.cs | 2 - .../Mining/Pools/Statistics/IAlgoStats.cs | 26 +++- .../Pools/Statistics/IBlockStatistics.cs | 40 ----- .../Statistics/IBlockStatisticsFactory.cs | 33 ---- .../Mining/Pools/Statistics/IBlockStats.cs | 26 +++- .../Pools/Statistics/IGlobalStatistics.cs | 37 ----- .../Statistics/IGlobalStatisticsFactory.cs | 30 ---- .../Mining/Pools/Statistics/IGlobalStats.cs | 28 +++- .../Statistics/IPerAlgorithmStatistics.cs | 38 ----- .../Pools/Statistics/IPerAlgorithmStats.cs | 28 +++- .../Mining/Pools/Statistics/IPerPoolStats.cs | 28 +++- .../Pools/Statistics/IPoolStatistics.cs | 44 ------ .../Statistics/IPoolStatisticsFactory.cs | 35 ----- .../Mining/Pools/Statistics/IPoolStats.cs | 26 +++- .../Mining/Pools/Statistics/IStatistics.cs | 3 - .../Statistics/IStatisticsObjectFactory.cs | 1 - .../Pools/Statistics/IStatisticsProvider.cs | 3 - .../Statistics/PerAlgorithmStatistics.cs | 43 ------ .../Pools/Statistics/PerAlgorithmStats.cs | 28 +++- .../Mining/Pools/Statistics/PerPoolStats.cs | 28 +++- .../Mining/Pools/Statistics/PoolStatistics.cs | 96 ------------ .../Pools/Statistics/PoolStatisticsFactory.cs | 63 -------- .../Mining/Pools/Statistics/PoolStats.cs | 24 ++- .../Mining/Pools/Statistics/Statistics.cs | 2 - .../Statistics/StatisticsObjectFactory.cs | 1 - .../Net/Server/Http/Basic/HttpServer.cs | 1 - .../Net/Server/Http/Web/ErrorConfiguration.cs | 1 - .../Net/Server/Http/Web/HttpServer.cs | 1 - .../Net/Server/Http/Web/NancyBootstrapper.cs | 1 - .../Net/Server/Http/Web/RootPathProvider.cs | 1 - src/CoiniumServ/Payments/IPaymentProcessor.cs | 1 - .../Payments/IPaymentProcessorFactory.cs | 1 - src/CoiniumServ/Payments/IPaymentRound.cs | 1 - src/CoiniumServ/Payments/IWorkerBalance.cs | 1 - src/CoiniumServ/Payments/PaymentProcessor.cs | 1 - .../Payments/PaymentProcessorFactory.cs | 1 - src/CoiniumServ/Payments/PaymentRound.cs | 1 - src/CoiniumServ/Payments/WorkerBalance.cs | 1 - .../Persistance/Blocks/BlockStatus.cs | 1 - .../Persistance/Blocks/ConfirmedBlock.cs | 24 ++- .../Persistance/Blocks/HashCandidate.cs | 1 - .../Persistance/Blocks/IConfirmedBlock.cs | 24 ++- .../Persistance/Blocks/IFinalizedBlock.cs | 1 - .../Persistance/Blocks/IHashCandidate.cs | 1 - .../Persistance/Blocks/IKickedBlock.cs | 24 ++- .../Persistance/Blocks/IOrphanedBlock.cs | 24 ++- .../Persistance/Blocks/IPendingBlock.cs | 1 - .../Persistance/Blocks/IPersistedBlock.cs | 1 - .../Persistance/Blocks/KickedBlock.cs | 24 ++- .../Persistance/Blocks/OrphanedBlock.cs | 24 ++- .../Persistance/Blocks/PendingBlock.cs | 1 - src/CoiniumServ/Persistance/IStorage.cs | 1 - .../Persistance/IStorageFactory.cs | 1 - src/CoiniumServ/Persistance/StorageFactory.cs | 1 - src/CoiniumServ/Repository/Bootstrapper.cs | 1 - .../Repository/Registries/ClassRegistry.cs | 3 - .../Repository/Registries/FactoryRegistry.cs | 3 - .../Repository/Registries/ManagerRegistry.cs | 1 - .../Repository/Registries/ServerRegistry.cs | 1 - .../Server/Mining/IMiningServer.cs | 1 - .../Server/Mining/IMiningServerConfig.cs | 1 - .../Stratum/Config/IStratumServerConfig.cs | 1 - .../Stratum/Config/StratumServerConfig.cs | 1 - .../Stratum/Errors/AuthenticationError.cs | 1 - .../Stratum/Errors/DuplicateShareError.cs | 1 - .../Mining/Stratum/Errors/IStratumError.cs | 1 - .../Mining/Stratum/Errors/JobNotFoundError.cs | 1 - .../Stratum/Errors/LowDifficultyShare.cs | 1 - .../Stratum/Errors/NotSubscriberError.cs | 1 - .../Mining/Stratum/Errors/OtherError.cs | 1 - .../Server/Mining/Stratum/IStratumMiner.cs | 1 - .../Stratum/Notifications/Difficulty.cs | 1 - .../Mining/Stratum/Notifications/IJob.cs | 1 - .../Mining/Stratum/Notifications/Job.cs | 1 - .../Stratum/Responses/SubscribeResponse.cs | 1 - .../Server/Mining/Stratum/StratumMiner.cs | 1 - .../Server/Mining/Stratum/StratumServer.cs | 1 - .../Vanilla/Config/IVanillaServerConfig.cs | 1 - .../Vanilla/Config/VanillaServerConfig.cs | 1 - .../Server/Mining/Vanilla/VanillaMiner.cs | 1 - .../Server/Mining/Vanilla/VanillaServer.cs | 1 - src/CoiniumServ/Server/Servers.cs | 1 - src/CoiniumServ/Server/Web/IWebServer.cs | 1 - .../Server/Web/IWebServerConfig.cs | 1 - src/CoiniumServ/Server/Web/Modules/Api.cs | 31 ++-- src/CoiniumServ/Server/Web/Modules/Index.cs | 3 - src/CoiniumServ/Server/Web/Modules/Pool.cs | 1 - src/CoiniumServ/Server/Web/WebServer.cs | 1 - src/CoiniumServ/Server/Web/WebServerConfig.cs | 1 - src/Tests/Mining/Pools/PoolTests.cs | 12 -- 109 files changed, 402 insertions(+), 990 deletions(-) delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/BlockStatisticsFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IBlockStatisticsFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs diff --git a/src/CoiniumServ/Coin/Helpers/Hashrate.cs b/src/CoiniumServ/Coin/Helpers/Hashrate.cs index 2b00553cb..1c65a5d01 100644 --- a/src/CoiniumServ/Coin/Helpers/Hashrate.cs +++ b/src/CoiniumServ/Coin/Helpers/Hashrate.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Coin.Helpers diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index a841753f8..f4dd4fc28 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -115,12 +115,8 @@ - - - - @@ -131,25 +127,15 @@ - - - - - - - - - - diff --git a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs index f3bf4926c..7995b6661 100644 --- a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Newtonsoft.Json; diff --git a/src/CoiniumServ/Daemon/IDaemonBase.cs b/src/CoiniumServ/Daemon/IDaemonBase.cs index 7e36c66e0..a6de9a2fe 100644 --- a/src/CoiniumServ/Daemon/IDaemonBase.cs +++ b/src/CoiniumServ/Daemon/IDaemonBase.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Daemon.Config; diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index e08f2889a..c759d54a2 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using Coinium.Daemon.Config; using Coinium.Daemon.Responses; diff --git a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs index 4d34ac821..0423f8a10 100644 --- a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Daemon.Responses diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index bc9832a5f..c22110b76 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index 86b1a8372..d3854cc0b 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools.Config; using Coinium.Mining.Pools.Statistics; @@ -30,8 +29,6 @@ public interface IPool { IPoolConfig Config { get; } - IPoolStatistics Statistics { get; } - IPerPoolStats Stats { get; } /// diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index 81f5d1e4a..4375d022c 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -28,8 +28,6 @@ namespace Coinium.Mining.Pools { public interface IPoolManager { - IGlobalStatistics Statistics { get; } - IStatistics NewStatistics { get; } IList GetPools(); diff --git a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs index 864f51f0d..88fe1a9b6 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Mining.Pools { public interface IPoolManagerFactory diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 2859efb0a..0338d43e1 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -50,7 +50,6 @@ public class Pool : IPool { public IPoolConfig Config { get; private set; } - public IPoolStatistics Statistics { get; private set; } public IPerPoolStats Stats { get; private set; } private readonly IDaemonClient _daemonClient; @@ -63,8 +62,6 @@ public class Pool : IPool private readonly IHashAlgorithmFactory _hashAlgorithmFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; - private readonly IPoolStatisticsFactory _poolStatisticsFactory; - private readonly IBlockStatisticsFactory _blockStatisticsFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private IMinerManager _minerManager; @@ -106,8 +103,6 @@ public Pool( IShareManagerFactory shareManagerFactory, IStorageFactory storageFactory, IPaymentProcessorFactory paymentProcessorFactory, - IPoolStatisticsFactory poolStatisticsFactory, - IBlockStatisticsFactory blockStatisticsFactory, IStatisticsObjectFactory statisticsObjectFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); @@ -120,8 +115,6 @@ public Pool( Enforce.ArgumentNotNull(shareManagerFactory, "IShareManagerFactory"); Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); - Enforce.ArgumentNotNull(poolStatisticsFactory, "IPoolStatisticsFactory"); - Enforce.ArgumentNotNull(blockStatisticsFactory, "IBlockStatisticsFactory"); _daemonClient = client; _minerManagerFactory = minerManagerFactory; @@ -133,8 +126,6 @@ public Pool( _hashAlgorithmFactory = hashAlgorithmFactory; _storageFactory = storageFactory; _paymentProcessorFactory = paymentProcessorFactory; - _poolStatisticsFactory = poolStatisticsFactory; - _blockStatisticsFactory = blockStatisticsFactory; _statisticsObjectFactory = statisticsObjectFactory; GenerateInstanceId(); @@ -186,11 +177,6 @@ private void InitManagers() _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); - var blockStatistics = _blockStatisticsFactory.Get(_daemonClient, _storage); - - Statistics = _poolStatisticsFactory.Get(_daemonClient, blockStatistics, _minerManager, _hashAlgorithm, _storage); - - var blockStats = _statisticsObjectFactory.GetBlockStats(_storage); Stats = _statisticsObjectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, _storage); } diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 74619be65..a9bf83e7c 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; @@ -34,7 +33,6 @@ namespace Coinium.Mining.Pools { public class PoolManager : IPoolManager { - public IGlobalStatistics Statistics { get; private set; } public IStatistics NewStatistics { get; private set; } private readonly List _pools = new List(); @@ -43,23 +41,19 @@ public class PoolManager : IPoolManager private readonly IPoolConfigFactory _poolConfigFactory; - private readonly IGlobalStatisticsFactory _algorithmStatisticsFactory; - private readonly IStatisticsObjectFactory _objectFactory; - public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IStatisticsObjectFactory objectFactory, IGlobalStatisticsFactory algorithmStatisticsFactory) + public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IStatisticsObjectFactory objectFactory) { _poolFactory = poolFactory; _poolConfigFactory = poolConfigFactory; _objectFactory = objectFactory; - _algorithmStatisticsFactory = algorithmStatisticsFactory; } public void Run() { LoadConfigs(); - Statistics = _algorithmStatisticsFactory.Get(this); NewStatistics = _objectFactory.GetStatistics(); } diff --git a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs index a1ba1e63d..6ec5c19f5 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; namespace Coinium.Mining.Pools diff --git a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs index 62263ab6d..46f8407ac 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs @@ -1,9 +1,27 @@ -using System; +#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; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs deleted file mode 100644 index 3b7c12ecf..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatistics.cs +++ /dev/null @@ -1,142 +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; -using System.Threading; -using Coinium.Daemon; -using Coinium.Daemon.Exceptions; -using Coinium.Persistance; -using Coinium.Persistance.Blocks; - -namespace Coinium.Mining.Pools.Statistics -{ - public class BlockStatistics : IBlockStatistics - { - public IEnumerable Latest { get; private set; } - - public int Pending { get; private set; } - public int Confirmed { get; private set; } - public int Orphaned { get; private set; } - - public int Total - { - get { return Pending + Confirmed + Orphaned; } - } - - private readonly IStorage _storage; - private readonly IDaemonClient _daemonClient; - - private readonly Timer _timer; - private const int TimerExpiration = 10; - - private const string PoolAddress = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; - - public BlockStatistics(IDaemonClient daemonClient, IStorage storage) - { - _daemonClient = daemonClient; - _storage = storage; - - _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. - Recache(null); // recache data initially. - } - - private void Recache(object state) - { - // get block statistics. - var blockCounts = _storage.GetBlockCounts(); - - // read block stats. - Pending = blockCounts.ContainsKey("pending") ? blockCounts["pending"] : 0; - Confirmed = blockCounts.ContainsKey("confirmed") ? blockCounts["confirmed"] : 0; - Orphaned = blockCounts.ContainsKey("orphaned") ? blockCounts["orphaned"] : 0; - - // read blocks - Latest = _storage.GetAllBlocks().OrderByDescending(x => x.Key).Take(20).Select(item=> item.Value).ToList(); - CheckBlocks(Latest); - - // reset the recache timer. - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); - } - - // TODO: duplicate code from payment processor. - private void CheckBlocks(IEnumerable blocks) - { - //foreach (var block in blocks) - //{ - // foreach (var hashes in block) - // { - // CheckBlockHashes(hashes); - // } - //} - } - - // TODO: duplicate code from payment processor. - private void CheckBlockHashes(IHashCandidate candidate) - { - try - { - // get the transaction. - var transaction = _daemonClient.GetTransaction(candidate.TransactionHash); - - // total amount of coins contained in the block. - candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); - - // get the output transaction that targets pools central wallet. - var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); - - // 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; - } - - candidate.Reward = (decimal)poolOutput.Amount; - } - } - catch (RpcException) - { - candidate.Status = BlockStatus.Kicked; // kick the candidate. - candidate.Reward = 0; - } - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStatisticsFactory.cs deleted file mode 100644 index 2f994dba1..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStatisticsFactory.cs +++ /dev/null @@ -1,58 +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 Coinium.Daemon; -using Coinium.Persistance; -using Coinium.Repository.Context; -using Nancy.TinyIoc; - -namespace Coinium.Mining.Pools.Statistics -{ - public class BlockStatisticsFactory:IBlockStatisticsFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public BlockStatisticsFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IBlockStatistics Get(IDaemonClient daemonClient, IStorage storage) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"storage", storage}, - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs index 40fe0fbc1..bffd49de2 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs @@ -1,4 +1,25 @@ -using System; +#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; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs deleted file mode 100644 index 4a3f80d9d..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatistics.cs +++ /dev/null @@ -1,82 +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; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace Coinium.Mining.Pools.Statistics -{ - public class GlobalStatistics:IGlobalStatistics - { - public Int32 Workers { get; private set; } - public UInt64 Hashrate { get; private set; } - public IList Algorithms { get; private set; } - - private readonly IDictionary _algorithms; - - private readonly IPoolManager _poolManager; - - private readonly Timer _timer; - private const int TimerExpiration = 10; - - public GlobalStatistics(IPoolManager poolManager) - { - _poolManager = poolManager; - - _algorithms = new Dictionary(); - - _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. - Recache(null); // recache data initially. - } - - private void Recache(object state) - { - Hashrate = 0; - Workers = 0; - - foreach (var pair in _algorithms) - { - pair.Value.Reset(); - } - - foreach (var pool in _poolManager.GetPools()) - { - Hashrate += pool.Statistics.Hashrate; - Workers += pool.Statistics.Miners.Count; - - if (!_algorithms.ContainsKey(pool.Config.Coin.Algorithm)) - _algorithms.Add(pool.Config.Coin.Algorithm, new PerAlgorithmStatistics(pool.Config.Coin.Algorithm)); - - _algorithms[pool.Config.Coin.Algorithm].Hashrate += pool.Statistics.Hashrate; - _algorithms[pool.Config.Coin.Algorithm].Workers += pool.Statistics.Miners.Count; - } - - Algorithms = _algorithms.Values.ToList(); - - // reset the recache timer. - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs deleted file mode 100644 index c2043049a..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStatisticsFactory.cs +++ /dev/null @@ -1,49 +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 Coinium.Repository.Context; - -namespace Coinium.Mining.Pools.Statistics -{ - public class GlobalStatisticsFactory:IGlobalStatisticsFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public GlobalStatisticsFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IGlobalStatistics Get(IPoolManager poolManager) - { - return _applicationContext.Container.Resolve(); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs index 28d5c1100..1ef55f363 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs @@ -20,8 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - - using System; namespace Coinium.Mining.Pools.Statistics diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs index 820e4f3a6..494d8abd7 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs @@ -1,8 +1,26 @@ -using System; +#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; -using System.Text; -using System.Threading.Tasks; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs deleted file mode 100644 index 4c6d99989..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatistics.cs +++ /dev/null @@ -1,40 +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 Coinium.Persistance; -using Coinium.Persistance.Blocks; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IBlockStatistics - { - int Pending { get; } - int Confirmed { get; } - int Orphaned { get; } - - int Total { get; } - - IEnumerable Latest { get; } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatisticsFactory.cs deleted file mode 100644 index b08a4f574..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStatisticsFactory.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 - -using Coinium.Daemon; -using Coinium.Persistance; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IBlockStatisticsFactory - { - IBlockStatistics Get(IDaemonClient daemonClient, IStorage storage); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs index 90f546e7f..3cf5f9f93 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs @@ -1,8 +1,26 @@ -using System; +#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; -using System.Text; -using System.Threading.Tasks; using Coinium.Persistance.Blocks; namespace Coinium.Mining.Pools.Statistics diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs deleted file mode 100644 index a90c364c6..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatistics.cs +++ /dev/null @@ -1,37 +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; -using System.Collections.Generic; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IGlobalStatistics - { - UInt64 Hashrate { get; } - - Int32 Workers { get; } - - IList Algorithms { get; } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs deleted file mode 100644 index 55dccbbea..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStatisticsFactory.cs +++ /dev/null @@ -1,30 +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 Coinium.Mining.Pools.Statistics -{ - public interface IGlobalStatisticsFactory - { - IGlobalStatistics Get(IPoolManager poolManager); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs index ac6db9084..d50161727 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs @@ -1,8 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +#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; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs deleted file mode 100644 index d730943ef..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStatistics.cs +++ /dev/null @@ -1,38 +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; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IPerAlgorithmStatistics - { - string Name { get; } - - Int32 Workers { get; set; } - - UInt64 Hashrate { get; set; } - - void Reset(); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs index 1ceea38f1..2bccc3149 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs @@ -1,8 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +#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; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs index 7b27fc385..56624e336 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs @@ -1,8 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +#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; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs deleted file mode 100644 index 1df5ab3c5..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatistics.cs +++ /dev/null @@ -1,44 +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; -using System.Collections.Generic; -using Coinium.Mining.Miners; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IPoolStatistics - { - IBlockStatistics Blocks { get; } - - UInt64 Hashrate { get; } - - UInt64 NetworkHashrate { get; } - - double Difficulty { get; } - - int CurrentBlockHeight { get; } - - IList Miners { get; } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs deleted file mode 100644 index f40d72d7c..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStatisticsFactory.cs +++ /dev/null @@ -1,35 +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 Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Persistance; - -namespace Coinium.Mining.Pools.Statistics -{ - public interface IPoolStatisticsFactory - { - IPoolStatistics Get(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs index 5c85dc61f..a962ea1ac 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs @@ -1,8 +1,26 @@ -using System; +#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; -using System.Text; -using System.Threading.Tasks; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs index f7d7d5093..720618264 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs @@ -20,9 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - -using System; - namespace Coinium.Mining.Pools.Statistics { public interface IStatistics diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 04c05d842..94f87dd41 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Miners; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs index c94a0ee0a..3e6bc5c3e 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs @@ -20,9 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - -using System; - namespace Coinium.Mining.Pools.Statistics { public interface IStatisticsProvider diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs deleted file mode 100644 index 6f9fc3016..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStatistics.cs +++ /dev/null @@ -1,43 +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 Coinium.Mining.Pools.Statistics -{ - public class PerAlgorithmStatistics:IPerAlgorithmStatistics - { - public string Name { get; private set; } - public int Workers { get; set; } - public ulong Hashrate { get; set; } - - public PerAlgorithmStatistics(string algorithm) - { - Name = algorithm; - } - - public void Reset() - { - Hashrate = 0; - Workers = 0; - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs index 2d5351414..3cdabc1da 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs @@ -1,9 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +#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 Coinium.Mining.Pools.Statistics { public class PerAlgorithmStats:IPerAlgorithmStats diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs index 61ce69ce9..02932afaa 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs @@ -1,15 +1,33 @@ -using System; -using System.Collections.Generic; +#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 System.Text; -using System.Threading.Tasks; using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Miners; using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Utils.Helpers.Time; -using HashLib; namespace Coinium.Mining.Pools.Statistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs deleted file mode 100644 index f3d0ade11..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatistics.cs +++ /dev/null @@ -1,96 +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; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Persistance; -using Coinium.Utils.Helpers.Time; - -namespace Coinium.Mining.Pools.Statistics -{ - public class PoolStatistics : IPoolStatistics - { - public IBlockStatistics Blocks { get; private set; } - - public UInt64 Hashrate { get; private set; } - public UInt64 NetworkHashrate { get; private set; } - public double Difficulty { get; private set; } - public int CurrentBlockHeight { get; private set; } - - public IList Miners - { - get { return _minerManager.Miners; } - } - - private readonly IDaemonClient _daemonClient; - private readonly IMinerManager _minerManager; - private readonly IStorage _storage; - private readonly IHashAlgorithm _hashAlgorithm; - - private readonly Timer _timer; - private const int TimerExpiration = 10; - private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ - - private readonly double _shareMultiplier; - - public PoolStatistics(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IStorage storage, IHashAlgorithm hashAlgorithm) - { - _daemonClient = daemonClient; - _minerManager = minerManager; - _storage = storage; - _hashAlgorithm = hashAlgorithm; - - _shareMultiplier = Math.Pow(2, 32)/_hashAlgorithm.Multiplier; - - Blocks = blockStatistics; - - _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. - Recache(null); // recache data initially. - } - - private void Recache(object state) - { - // read hashrate stats. - var windowTime = TimeHelpers.NowInUnixTime() - HashrateWindow; - _storage.DeleteExpiredHashrateData(windowTime); - var hashrates = _storage.GetHashrateData(windowTime); - - double total = hashrates.Sum(pair => pair.Value); - Hashrate = Convert.ToUInt64(_shareMultiplier*total/HashrateWindow); - - // read data from daemon - var miningInfo = _daemonClient.GetMiningInfo(); - NetworkHashrate = miningInfo.NetworkHashps; - Difficulty = miningInfo.Difficulty; - CurrentBlockHeight = miningInfo.Blocks; - - // reset the recache timer. - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs deleted file mode 100644 index 571fa9cac..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStatisticsFactory.cs +++ /dev/null @@ -1,63 +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 Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Persistance; -using Coinium.Repository.Context; -using Nancy.TinyIoc; - -namespace Coinium.Mining.Pools.Statistics -{ - public class PoolStatisticsFactory:IPoolStatisticsFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public PoolStatisticsFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IPoolStatistics Get(IDaemonClient daemonClient, IBlockStatistics blockStatistics, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IStorage storage) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"blockStatistics", blockStatistics}, - {"minerManager", minerManager}, - {"hashAlgorithm", hashAlgorithm}, - {"storage", storage}, - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs index 249541399..48163e45a 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs @@ -1,4 +1,26 @@ -using System.Collections; +#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; using System.Collections.Generic; namespace Coinium.Mining.Pools.Statistics diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index fb7620747..991f49252 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -20,8 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - -using System; using System.Threading; namespace Coinium.Mining.Pools.Statistics diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index 94b9269fe..6a3182bc0 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Mining.Miners; diff --git a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs index 545ea8142..93974b54a 100644 --- a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Net; diff --git a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs index ade5e1411..ed6c185c6 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Nancy; using Nancy.CustomErrors; diff --git a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index 024f4dbcc..56fd1b29e 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Repository.Context; using Nancy.Bootstrapper; diff --git a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs index e5ab9a101..7395a3aa9 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Nancy; using Nancy.Bootstrapper; diff --git a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs index 0f179b7ee..ca4b19b4b 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.IO; using System.Reflection; using Coinium.Utils.Platform; diff --git a/src/CoiniumServ/Payments/IPaymentProcessor.cs b/src/CoiniumServ/Payments/IPaymentProcessor.cs index 98f5a1d52..bc8da694d 100644 --- a/src/CoiniumServ/Payments/IPaymentProcessor.cs +++ b/src/CoiniumServ/Payments/IPaymentProcessor.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Payments { public interface IPaymentProcessor diff --git a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs index ac13cf181..8fe75f3dd 100644 --- a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Persistance; diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index fb44ddb1c..170552850 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using Coinium.Persistance.Blocks; diff --git a/src/CoiniumServ/Payments/IWorkerBalance.cs b/src/CoiniumServ/Payments/IWorkerBalance.cs index 27f0f8331..eab13680b 100644 --- a/src/CoiniumServ/Payments/IWorkerBalance.cs +++ b/src/CoiniumServ/Payments/IWorkerBalance.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Payments { public interface IWorkerBalance diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 1f9cec7af..5565e537c 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs index b745a8d81..00c9c0f15 100644 --- a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Daemon; using Coinium.Persistance; using Coinium.Repository.Context; diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs index 2bcd52251..b39af8b84 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using System.Linq; using Coinium.Persistance.Blocks; diff --git a/src/CoiniumServ/Payments/WorkerBalance.cs b/src/CoiniumServ/Payments/WorkerBalance.cs index 1a4977634..a2ea3f0fa 100644 --- a/src/CoiniumServ/Payments/WorkerBalance.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Payments diff --git a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs index 5ba7d595c..3be792c4e 100644 --- a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs +++ b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Persistance.Blocks { public enum BlockStatus diff --git a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs index 066a1ed11..b17a6d069 100644 --- a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs @@ -1,4 +1,26 @@ -namespace Coinium.Persistance.Blocks +#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 Coinium.Persistance.Blocks { public class ConfirmedBlock:IConfirmedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs index c547be3a8..9d0e1d1e3 100644 --- a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs +++ b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Persistance.Blocks { public class HashCandidate : IHashCandidate diff --git a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs index 5ce1e7889..94c2e0cd9 100644 --- a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs @@ -1,4 +1,26 @@ -using System; +#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.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs index 3412934f1..9cbd8414e 100644 --- a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Persistance.Blocks { public interface IFinalizedBlock:IPersistedBlock diff --git a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs index 7a49ea909..0a4ce6ce8 100644 --- a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs +++ b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Persistance.Blocks { public interface IHashCandidate diff --git a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs index 5610a85d7..154910702 100644 --- a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs @@ -1,4 +1,26 @@ -using System; +#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.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs index 21bc9b46b..232d501f3 100644 --- a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs @@ -1,4 +1,26 @@ -using System; +#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.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs index bba3ed75f..9086ff925 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; namespace Coinium.Persistance.Blocks diff --git a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs index 8b8daff9c..079cbcc2a 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Persistance.Blocks diff --git a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs index d0cc34420..988eb7ca6 100644 --- a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs @@ -1,4 +1,26 @@ -namespace Coinium.Persistance.Blocks +#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 Coinium.Persistance.Blocks { public class KickedBlock:IKickedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs index 78e337ed3..aea263500 100644 --- a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs @@ -1,4 +1,26 @@ -namespace Coinium.Persistance.Blocks +#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 Coinium.Persistance.Blocks { public class OrphanedBlock:IOrphanedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs index d2966b9d6..acf24c5b8 100644 --- a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 458e4152e..e5ef0ca92 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using Coinium.Mining.Shares; diff --git a/src/CoiniumServ/Persistance/IStorageFactory.cs b/src/CoiniumServ/Persistance/IStorageFactory.cs index baa084f54..807376507 100644 --- a/src/CoiniumServ/Persistance/IStorageFactory.cs +++ b/src/CoiniumServ/Persistance/IStorageFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools.Config; namespace Coinium.Persistance diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs index 8abcde0a4..66672a2a5 100644 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ b/src/CoiniumServ/Persistance/StorageFactory.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools.Config; using Coinium.Repository.Context; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Repository/Bootstrapper.cs b/src/CoiniumServ/Repository/Bootstrapper.cs index 693772286..0adf5aada 100644 --- a/src/CoiniumServ/Repository/Bootstrapper.cs +++ b/src/CoiniumServ/Repository/Bootstrapper.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Registries; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 04090adc7..edca1aa9a 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -47,9 +47,6 @@ public void RegisterInstances() _applicationContext.Container.Register(Algorithms.Scrypt).AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index c7cddb2f5..aae80996f 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -63,9 +63,6 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 9c11babcb..b8691744e 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; using Coinium.Mining.Pools; diff --git a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs index 38fd84dce..8c4485818 100644 --- a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Repository.Context; using Coinium.Server; using Coinium.Server.Mining; diff --git a/src/CoiniumServ/Server/Mining/IMiningServer.cs b/src/CoiniumServ/Server/Mining/IMiningServer.cs index f9649da58..d652f595b 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServer.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Net.Server; namespace Coinium.Server.Mining diff --git a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs index a6bb3179d..1dc707d5f 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Utils.Configuration; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index d20fdfd2e..59e368bc2 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Server.Mining.Stratum.Config diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index e913c6c40..9d03c8bf3 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Service; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs index 0724bcb00..7d7a0ecd9 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; namespace Coinium.Server.Mining.Stratum.Errors diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs index cc6d04e01..51be9bb38 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using AustinHarris.JsonRpc; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs index 9458e7b89..9797b084a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Server.Mining.Stratum.Errors { public interface IStratumError diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs index 1dfca6bed..f3ba7723a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using AustinHarris.JsonRpc; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs index d13d90d5e..377ab50d1 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; namespace Coinium.Server.Mining.Stratum.Errors diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs index 37942aae2..e94e99a89 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; namespace Coinium.Server.Mining.Stratum.Errors diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs index 93a7f9224..ef3653636 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using AustinHarris.JsonRpc; namespace Coinium.Server.Mining.Stratum.Errors diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index 1ddd37c48..3453bef26 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Mining.Miners; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs index eebe2fff2..6eb549029 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections; using System.Collections.Generic; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs index f86e26b68..7a2ace7fb 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections.Generic; using Coinium.Crypto.Algorithms; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs index 1464a21b5..503d261f3 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Collections; using System.Collections.Generic; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs b/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs index 2abf75fac..78236c256 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections; using System.Collections.Generic; using System.Globalization; diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 23a3bf64f..b670d880e 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.Text; using AustinHarris.JsonRpc; diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index 8ff59c443..644ad3fda 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; using Coinium.Mining.Pools; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs index b34160876..9cac24aa0 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Server.Mining.Vanilla.Config { public interface IVanillaServerConfig : IServerConfig diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs index e7edb41bf..ae78e627c 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using Coinium.Service; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 0514a3871..18d37150e 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; using System.IO; using System.Net; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index 530685673..21ebce8f7 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Net; using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Miners; diff --git a/src/CoiniumServ/Server/Servers.cs b/src/CoiniumServ/Server/Servers.cs index 6858935e3..7a7ee34f2 100644 --- a/src/CoiniumServ/Server/Servers.cs +++ b/src/CoiniumServ/Server/Servers.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Server { public class Servers diff --git a/src/CoiniumServ/Server/Web/IWebServer.cs b/src/CoiniumServ/Server/Web/IWebServer.cs index 189801471..e3012f866 100644 --- a/src/CoiniumServ/Server/Web/IWebServer.cs +++ b/src/CoiniumServ/Server/Web/IWebServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Net.Server; using Coinium.Server.Mining; diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index bb8074226..1bffdb9cf 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System; namespace Coinium.Server.Web diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index 5bc17928d..9e9b4de4d 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using System.Dynamic; using Coinium.Mining.Pools; @@ -43,22 +42,24 @@ public ApiModule(IPoolManager poolManager, IStatistics statistics) { var algorithms = new Dictionary(); - foreach (var algo in poolManager.Statistics.Algorithms) - { - dynamic @obj = new ExpandoObject(); - algorithms.Add(algo.Name, @obj); - @obj.hashrate = algo.Hashrate; - @obj.workers = algo.Workers; - } + //foreach (var algo in poolManager.Statistics.Algorithms) + //{ + // dynamic @obj = new ExpandoObject(); + // algorithms.Add(algo.Name, @obj); + // @obj.hashrate = algo.Hashrate; + // @obj.workers = algo.Workers; + //} + + //var globalStats = new + //{ + // hashrate = poolManager.Statistics.Hashrate, + // workers = poolManager.Statistics.Workers, + // algorithms = algorithms, + //}; - var globalStats = new - { - hashrate = poolManager.Statistics.Hashrate, - workers = poolManager.Statistics.Workers, - algorithms = algorithms, - }; + //return Response.AsJson(globalStats); - return Response.AsJson(globalStats); + return null; }; Get["/api/pools"] = _ => diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index f3225f110..c2572d787 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using System.Collections.Generic; using Coinium.Mining.Pools; using Coinium.Mining.Pools.Statistics; @@ -34,7 +33,6 @@ public IndexModule(IPoolManager poolManager) { Get["/"] = _ => View["index", new IndexModel { - Global = poolManager.Statistics, Pools = poolManager.GetPools() }]; } @@ -42,7 +40,6 @@ public IndexModule(IPoolManager poolManager) public class IndexModel { - public IGlobalStatistics Global { get; set; } public IList Pools { get; set; } } } diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index ef09ddd36..1ee8b6e38 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools; using Nancy; diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 382f4e4f6..beff42fe7 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - using Coinium.Mining.Pools; using Coinium.Net.Server.Http.Web; using Coinium.Repository.Context; diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index bd6f62009..077c46ce2 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -20,7 +20,6 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion - namespace Coinium.Server.Web { public class WebServerConfig : IWebServerConfig diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 0badc0981..c68a6e0b3 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -52,8 +52,6 @@ public class PoolTests private readonly IMinerManagerFactory _minerManagerFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; - private readonly IPoolStatisticsFactory _poolStatisticsFactory; - private readonly IBlockStatisticsFactory _blockStatisticsFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; // object mocks. @@ -66,8 +64,6 @@ public class PoolTests private readonly IMiningServer _miningServer; private readonly IRpcService _rpcService; private readonly IPaymentProcessor _paymentProcessor; - private readonly IPoolStatistics _poolStatistics; - private readonly IBlockStatistics _blockStatistics; private readonly IStatistics _statistics; /// @@ -84,8 +80,6 @@ public PoolTests() _serviceFactory = Substitute.For(); _storageFactory = Substitute.For(); _paymentProcessorFactory = Substitute.For(); - _poolStatisticsFactory = Substitute.For(); - _blockStatisticsFactory = Substitute.For(); _statisticsObjectFactory = Substitute.For(); _daemonClient = Substitute.For(); @@ -97,8 +91,6 @@ public PoolTests() _rpcService = Substitute.For(); _storage = Substitute.For(); _paymentProcessor = Substitute.For(); - _poolStatistics = Substitute.For(); - _blockStatistics = Substitute.For(); _statistics = Substitute.For(); } @@ -119,8 +111,6 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _shareManagerFactory, _storageFactory, _paymentProcessorFactory, - _poolStatisticsFactory, - _blockStatisticsFactory, _statisticsObjectFactory ); @@ -145,8 +135,6 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _shareManagerFactory, _storageFactory, _paymentProcessorFactory, - _poolStatisticsFactory, - _blockStatisticsFactory, _statisticsObjectFactory ); From 9fbf4107799ecf6b22fcdc5cb5a1d3cb0a6a5720 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 15 Jul 2014 14:42:55 +0300 Subject: [PATCH 059/230] Fixed pools.cshtml and web.cshtml. --- src/CoiniumServ/CoiniumServ.csproj | 26 +++++---- src/CoiniumServ/Mining/Pools/IPool.cs | 2 +- src/CoiniumServ/Mining/Pools/Pool.cs | 9 ++- .../{AlgoStats.cs => Algorithms.cs} | 14 ++--- .../Mining/Pools/Statistics/Blocks.cs | 57 +++++++++++++++++++ .../Statistics/{GlobalStats.cs => Global.cs} | 6 +- .../{IPoolStats.cs => IAlgorithms.cs} | 2 +- .../Mining/Pools/Statistics/IBlocks.cs | 35 ++++++++++++ .../{IGlobalStats.cs => IGlobal.cs} | 2 +- .../{IBlockStats.cs => ILatestBlocks.cs} | 3 +- ...IPerAlgorithmStats.cs => IPerAlgorithm.cs} | 2 +- .../{IPerPoolStats.cs => IPerPool.cs} | 4 +- .../Statistics/{IAlgoStats.cs => IPools.cs} | 2 +- .../Mining/Pools/Statistics/IStatistics.cs | 6 +- .../Statistics/IStatisticsObjectFactory.cs | 12 ++-- .../{BlockStats.cs => LatestBlocks.cs} | 16 +++--- .../{PerAlgorithmStats.cs => PerAlgorithm.cs} | 4 +- .../{PerPoolStats.cs => PerPool.cs} | 10 ++-- .../Statistics/{PoolStats.cs => Pools.cs} | 14 ++--- .../Mining/Pools/Statistics/Statistics.cs | 6 +- .../Statistics/StatisticsObjectFactory.cs | 31 ++++++---- .../Repository/Registries/ClassRegistry.cs | 13 +++-- src/CoiniumServ/Server/Web/Modules/Index.cs | 7 ++- src/CoiniumServ/web/default/index.cshtml | 16 +++--- src/CoiniumServ/web/default/pool.cshtml | 8 +-- 25 files changed, 212 insertions(+), 95 deletions(-) rename src/CoiniumServ/Mining/Pools/Statistics/{AlgoStats.cs => Algorithms.cs} (82%) create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs rename src/CoiniumServ/Mining/Pools/Statistics/{GlobalStats.cs => Global.cs} (91%) rename src/CoiniumServ/Mining/Pools/Statistics/{IPoolStats.cs => IAlgorithms.cs} (91%) create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs rename src/CoiniumServ/Mining/Pools/Statistics/{IGlobalStats.cs => IGlobal.cs} (95%) rename src/CoiniumServ/Mining/Pools/Statistics/{IBlockStats.cs => ILatestBlocks.cs} (92%) rename src/CoiniumServ/Mining/Pools/Statistics/{IPerAlgorithmStats.cs => IPerAlgorithm.cs} (96%) rename src/CoiniumServ/Mining/Pools/Statistics/{IPerPoolStats.cs => IPerPool.cs} (93%) rename src/CoiniumServ/Mining/Pools/Statistics/{IAlgoStats.cs => IPools.cs} (91%) rename src/CoiniumServ/Mining/Pools/Statistics/{BlockStats.cs => LatestBlocks.cs} (92%) rename src/CoiniumServ/Mining/Pools/Statistics/{PerAlgorithmStats.cs => PerAlgorithm.cs} (92%) rename src/CoiniumServ/Mining/Pools/Statistics/{PerPoolStats.cs => PerPool.cs} (89%) rename src/CoiniumServ/Mining/Pools/Statistics/{PoolStats.cs => Pools.cs} (80%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index f4dd4fc28..12e3dcc9c 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,13 +110,15 @@ - - + + + + - - - + + + @@ -127,16 +129,16 @@ - - - + + + - + - - - + + + diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index d3854cc0b..907802daa 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -29,7 +29,7 @@ public interface IPool { IPoolConfig Config { get; } - IPerPoolStats Stats { get; } + IPerPool Statistics { get; } /// /// Initializes the specified bind ip. diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 0338d43e1..29caed83c 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -50,7 +50,7 @@ public class Pool : IPool { public IPoolConfig Config { get; private set; } - public IPerPoolStats Stats { get; private set; } + public IPerPool Statistics { get; private set; } private readonly IDaemonClient _daemonClient; private readonly IServerFactory _serverFactory; @@ -92,6 +92,7 @@ public class Pool : IPool /// The share manager factory. /// /// + /// public Pool( IHashAlgorithmFactory hashAlgorithmFactory, IServerFactory serverFactory, @@ -177,8 +178,10 @@ private void InitManagers() _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); - var blockStats = _statisticsObjectFactory.GetBlockStats(_storage); - Stats = _statisticsObjectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, _storage); + + var latestBlocks = _statisticsObjectFactory.GetLatestBlocks(_storage); + var blockStats = _statisticsObjectFactory.GetBlockStats(latestBlocks, _storage); + Statistics = _statisticsObjectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, _storage); } private void InitServers() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs similarity index 82% rename from src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs index 46f8407ac..26d69c03c 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/AlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs @@ -25,15 +25,15 @@ namespace Coinium.Mining.Pools.Statistics { - public class AlgoStats : IAlgoStats + public class Algorithms : IAlgorithms { - private readonly Dictionary _algorithms; - private readonly IPoolStats _poolStatistics; + private readonly Dictionary _algorithms; + private readonly IPools _poolStatistics; - public AlgoStats(IPoolStats poolStatistics) + public Algorithms(IPools poolStatistics) { _poolStatistics = poolStatistics; - _algorithms = new Dictionary(); + _algorithms = new Dictionary(); } public void Recache(object state) @@ -46,14 +46,14 @@ public void Recache(object state) foreach (var pair in _poolStatistics) { if (!_algorithms.ContainsKey(pair.Value.Algorithm)) - _algorithms.Add(pair.Value.Algorithm, new PerAlgorithmStats(pair.Value.Algorithm)); + _algorithms.Add(pair.Value.Algorithm, new PerAlgorithm(pair.Value.Algorithm)); _algorithms[pair.Value.Algorithm].Hashrate = pair.Value.Hashrate; _algorithms[pair.Value.Algorithm].WorkerCount = pair.Value.WorkerCount; } } - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { return _algorithms.GetEnumerator(); } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs new file mode 100644 index 000000000..f1c6c0c46 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs @@ -0,0 +1,57 @@ +#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 Coinium.Persistance; + +namespace Coinium.Mining.Pools.Statistics +{ + public class Blocks:IBlocks + { + public int Pending { get; private set; } + public int Confirmed { get; private set; } + public int Orphaned { get; private set; } + public int Total { get; private set; } + public ILatestBlocks Latest { get; private set; } + + private readonly IStorage _storage; + + public Blocks(ILatestBlocks latestBlocks, IStorage storage) + { + _storage = storage; + Latest = latestBlocks; + } + + public void Recache(object state) + { + // get block statistics. + var blockCounts = _storage.GetBlockCounts(); + + // read block stats. + Pending = blockCounts.ContainsKey("pending") ? blockCounts["pending"] : 0; + Confirmed = blockCounts.ContainsKey("confirmed") ? blockCounts["confirmed"] : 0; + Orphaned = blockCounts.ContainsKey("orphaned") ? blockCounts["orphaned"] : 0; + + Latest.Recache(state); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs similarity index 91% rename from src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/Global.cs index 1ef55f363..9c7d63621 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/GlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs @@ -24,14 +24,14 @@ namespace Coinium.Mining.Pools.Statistics { - public class GlobalStats : IGlobalStats + public class Global : IGlobal { public UInt64 Hashrate { get; private set; } public Int32 WorkerCount { get; private set; } - private readonly IPoolStats _poolStatistics; + private readonly IPools _poolStatistics; - public GlobalStats(IPoolStats poolStatistics) + public Global(IPools poolStatistics) { _poolStatistics = poolStatistics; } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs similarity index 91% rename from src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs index a962ea1ac..2ebecd790 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPoolStats : IEnumerable>, IStatisticsProvider + public interface IAlgorithms: IEnumerable>, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs new file mode 100644 index 000000000..5a9bf204c --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs @@ -0,0 +1,35 @@ +#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 Coinium.Mining.Pools.Statistics +{ + public interface IBlocks : IStatisticsProvider + { + int Pending { get; } + int Confirmed { get; } + int Orphaned { get; } + int Total { get; } + + ILatestBlocks Latest { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs similarity index 95% rename from src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs index d50161727..470090066 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobalStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IGlobalStats: IStatisticsProvider + public interface IGlobal: IStatisticsProvider { UInt64 Hashrate { get; } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs similarity index 92% rename from src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs index 3cf5f9f93..7fcf0ee90 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlockStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using Coinium.Persistance.Blocks; namespace Coinium.Mining.Pools.Statistics { - public interface IBlockStats : IStatisticsProvider, IEnumerable + public interface ILatestBlocks: IEnumerable, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs index 2bccc3149..f4ba021e3 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPerAlgorithmStats + public interface IPerAlgorithm { string Name { get; } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs similarity index 93% rename from src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs index 56624e336..02be9086b 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPerPoolStats: IStatisticsProvider + public interface IPerPool: IStatisticsProvider { UInt64 Hashrate { get; } @@ -36,7 +36,7 @@ public interface IPerPoolStats: IStatisticsProvider int CurrentBlock { get; } - IBlockStats LatestBlocks { get; } + IBlocks Blocks { get; } string Algorithm { get; } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs similarity index 91% rename from src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/IPools.cs index 494d8abd7..ca1618b4f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgoStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IAlgoStats: IEnumerable>, IStatisticsProvider + public interface IPools : IEnumerable>, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs index 720618264..0412c5ba3 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs @@ -24,10 +24,10 @@ namespace Coinium.Mining.Pools.Statistics { public interface IStatistics { - IGlobalStats Global { get; } + IGlobal Global { get; } - IAlgoStats Algorithms { get; } + IAlgorithms Algorithms { get; } - IPoolStats Pools { get; } + IPools Pools { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 94f87dd41..83c2f7bd7 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -32,14 +32,16 @@ public interface IStatisticsObjectFactory { IStatistics GetStatistics(); - IGlobalStats GetGlobalStatistics(); + IGlobal GetGlobalStatistics(); - IAlgoStats GetAlgorithmStatistics(); + IAlgorithms GetAlgorithmStatistics(); - IPoolStats GetPoolStats(); + IPools GetPoolStats(); - IPerPoolStats GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage); + IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage); - IBlockStats GetBlockStats(IStorage storage); + IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage); + + ILatestBlocks GetLatestBlocks(IStorage storage); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs similarity index 92% rename from src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs index bffd49de2..ab3f9a4ed 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/BlockStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections; using System.Collections.Generic; using System.Linq; @@ -28,22 +29,17 @@ namespace Coinium.Mining.Pools.Statistics { - public class BlockStats:IBlockStats + public class LatestBlocks:ILatestBlocks { private IEnumerable _blocks; private readonly IStorage _storage; - public BlockStats(IStorage storage) + public LatestBlocks(IStorage storage) { _storage = storage; } - public void Recache(object state) - { - _blocks = _storage.GetAllBlocks().OrderByDescending(x => x.Key).Take(20).Select(item => item.Value).ToList(); - } - public IEnumerator GetEnumerator() { return _blocks.GetEnumerator(); @@ -53,5 +49,11 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + public void Recache(object state) + { + // read latest blocks + _blocks = _storage.GetAllBlocks().OrderByDescending(x => x.Key).Take(20).Select(item => item.Value).ToList(); + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs similarity index 92% rename from src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs index 3cdabc1da..75d92f762 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithmStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs @@ -22,13 +22,13 @@ #endregion namespace Coinium.Mining.Pools.Statistics { - public class PerAlgorithmStats:IPerAlgorithmStats + public class PerAlgorithm:IPerAlgorithm { public string Name { get; private set; } public int WorkerCount { get; set; } public ulong Hashrate { get; set; } - public PerAlgorithmStats(string algorithm) + public PerAlgorithm(string algorithm) { Name = algorithm; } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs similarity index 89% rename from src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs index 02932afaa..46da61f57 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs @@ -31,14 +31,14 @@ namespace Coinium.Mining.Pools.Statistics { - public class PerPoolStats:IPerPoolStats + public class PerPool:IPerPool { public ulong Hashrate { get; private set; } public ulong NetworkHashrate { get; private set; } public int WorkerCount { get; private set; } public double Difficulty { get; private set; } public int CurrentBlock { get; private set; } - public IBlockStats LatestBlocks { get; private set; } + public IBlocks Blocks { get; private set; } public string Algorithm { get; private set; } private readonly IDaemonClient _daemonClient; @@ -50,13 +50,13 @@ public class PerPoolStats:IPerPoolStats private readonly double _shareMultiplier; private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ - public PerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) + public PerPool(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) { _poolConfig = poolConfig; _daemonClient = daemonClient; _hashAlgorithm = hashAlgorithm; _minerManager = minerManager; - LatestBlocks = blockStatistics; + Blocks = blockStatistics; _storage = storage; _shareMultiplier = Math.Pow(2, 32) / _hashAlgorithm.Multiplier; @@ -70,7 +70,7 @@ public void Recache(object state) WorkerCount = _minerManager.Miners.Count; Algorithm = _poolConfig.Coin.Algorithm; - LatestBlocks.Recache(state); + Blocks.Recache(state); } private void ReadHashrate() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs similarity index 80% rename from src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs rename to src/CoiniumServ/Mining/Pools/Statistics/Pools.cs index 48163e45a..3abad8b4a 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PoolStats.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs @@ -25,24 +25,24 @@ namespace Coinium.Mining.Pools.Statistics { - public class PoolStats:IPoolStats + public class Pools:IPools { - private readonly Dictionary _pools; + private readonly Dictionary _pools; private readonly IPoolManager _poolManager; - public PoolStats(IPoolManager poolManager) + public Pools(IPoolManager poolManager) { _poolManager = poolManager; - _pools = new Dictionary(); + _pools = new Dictionary(); foreach (var pool in poolManager.GetPools()) { - _pools.Add(pool.Config.Coin.Name, pool.Stats); + _pools.Add(pool.Config.Coin.Name, pool.Statistics); } } - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { return _pools.GetEnumerator(); } @@ -56,7 +56,7 @@ public void Recache(object state) { foreach (var pool in _poolManager.GetPools()) { - pool.Stats.Recache(state); + pool.Statistics.Recache(state); } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index 991f49252..c82291e2f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -26,9 +26,9 @@ namespace Coinium.Mining.Pools.Statistics { public class Statistics:IStatistics, IStatisticsProvider { - public IGlobalStats Global { get; private set; } - public IAlgoStats Algorithms { get; private set; } - public IPoolStats Pools { get; private set; } + public IGlobal Global { get; private set; } + public IAlgorithms Algorithms { get; private set; } + public IPools Pools { get; private set; } private readonly Timer _timer; private const int TimerExpiration = 10; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index 6a3182bc0..5ceb7450b 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -51,22 +51,22 @@ public IStatistics GetStatistics() return _applicationContext.Container.Resolve(); } - public IGlobalStats GetGlobalStatistics() + public IGlobal GetGlobalStatistics() { - return _applicationContext.Container.Resolve(); + return _applicationContext.Container.Resolve(); } - public IAlgoStats GetAlgorithmStatistics() + public IAlgorithms GetAlgorithmStatistics() { - return _applicationContext.Container.Resolve(); + return _applicationContext.Container.Resolve(); } - public IPoolStats GetPoolStats() + public IPools GetPoolStats() { - return _applicationContext.Container.Resolve(); + return _applicationContext.Container.Resolve(); } - public IPerPoolStats GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlockStats blockStatistics, IStorage storage) + public IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) { var @params = new NamedParameterOverloads { @@ -78,17 +78,28 @@ public IPerPoolStats GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemo {"storage", storage}, }; - return _applicationContext.Container.Resolve(@params); + return _applicationContext.Container.Resolve(@params); } - public IBlockStats GetBlockStats(IStorage storage) + public ILatestBlocks GetLatestBlocks(IStorage storage) { var @params = new NamedParameterOverloads { + {"storage", storage} + }; + + return _applicationContext.Container.Resolve(@params); + } + + public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"latestBlocks", latestBlocks}, {"storage", storage}, }; - return _applicationContext.Container.Resolve(@params); + return _applicationContext.Container.Resolve(@params); } } } diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index edca1aa9a..78e13b095 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -44,7 +44,7 @@ public ClassRegistry(IApplicationContext applicationContext) public void RegisterInstances() { - _applicationContext.Container.Register(Algorithms.Scrypt).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Scrypt).AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); @@ -52,11 +52,12 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index c2572d787..0816661bf 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -29,11 +29,12 @@ namespace Coinium.Server.Web.Modules { public class IndexModule : NancyModule { - public IndexModule(IPoolManager poolManager) + public IndexModule(IPoolManager poolManager, IStatistics statistics) { Get["/"] = _ => View["index", new IndexModel { - Pools = poolManager.GetPools() + Pools = poolManager.GetPools(), + Statistics = statistics, }]; } } @@ -41,5 +42,7 @@ public IndexModule(IPoolManager poolManager) public class IndexModel { public IList Pools { get; set; } + + public IStatistics Statistics { get; set; } } } diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index e552367a8..1fc3c2416 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -22,8 +22,8 @@ - @Model.Global.Workers - @Model.Global.Hashrate.GetReadableHashrate() + @Model.Statistics.Global.WorkerCount + @Model.Statistics.Global.Hashrate.GetReadableHashrate() @@ -49,12 +49,12 @@ - @foreach (var algorithm in Model.Global.Algorithms) + @foreach (var algorithm in Model.Statistics.Algorithms) { - @algorithm.Name - @algorithm.Workers - @algorithm.Hashrate.GetReadableHashrate() + @algorithm.Value.Name + @algorithm.Value.WorkerCount + @algorithm.Value.Hashrate.GetReadableHashrate() } @@ -96,9 +96,9 @@ @pool.Statistics.Hashrate.GetReadableHashrate() @pool.Statistics.NetworkHashrate.GetReadableHashrate() @pool.Statistics.Difficulty - @pool.Statistics.Miners.Count + @pool.Statistics.WorkerCount @pool.Config.Coin.Algorithm - @pool.Statistics.CurrentBlockHeight + @pool.Statistics.CurrentBlock } diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 7f2674dff..70da3e96d 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -33,7 +33,7 @@ Difficulty - @Model.Statistics.Miners.Count + @Model.Statistics.WorkerCount Workers @@ -41,7 +41,7 @@ Algorithm - @Model.Statistics.CurrentBlockHeight + @Model.Statistics.CurrentBlock Current Block
    @@ -116,8 +116,8 @@ } @block.Amount - @block.BlockHash.Substring(0, block.BlockHash.Length > 10 ? 10 : block.BlockHash.Length).. - @block.TransactionHash.Substring(0, block.TransactionHash.Length > 10 ? 10 : block.TransactionHash.Length).. + @block.BlockHash.Substring(0, block.BlockHash.Length > 10 ? 10 : block.BlockHash.Length).. + @block.TransactionHash.Substring(0, block.TransactionHash.Length > 10 ? 10 : block.TransactionHash.Length).. } From 52382d6ef9f0ca7dce6e3b2a0178a41a7d1501d5 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 15 Jul 2014 17:26:52 +0300 Subject: [PATCH 060/230] Fixed statistics & implemented api responses. --- src/CoiniumServ/CoiniumServ.csproj | 3 ++ .../Mining/Pools/Statistics/Algorithms.cs | 44 ++++++++++++--- .../Mining/Pools/Statistics/Global.cs | 29 ++++++++-- .../Mining/Pools/Statistics/IAlgorithms.cs | 3 +- .../Mining/Pools/Statistics/IGlobal.cs | 2 +- .../Mining/Pools/Statistics/IJsonResponse.cs | 32 +++++++++++ .../Mining/Pools/Statistics/IPerAlgorithm.cs | 8 +-- .../Mining/Pools/Statistics/IPerPool.cs | 4 +- .../Mining/Pools/Statistics/IPools.cs | 2 +- .../Mining/Pools/Statistics/PerAlgorithm.cs | 32 ++++++++++- .../Mining/Pools/Statistics/PerPool.cs | 33 ++++++++++-- .../Mining/Pools/Statistics/Pools.cs | 23 +++++++- .../Mining/Pools/Statistics/Statistics.cs | 2 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 54 ++++++++++--------- .../Server/Web/Modules/Models/Error.cs | 31 +++++++++++ .../Server/Web/Modules/Models/JsonError.cs | 35 ++++++++++++ src/CoiniumServ/Server/Web/Modules/Pool.cs | 9 +--- 17 files changed, 285 insertions(+), 61 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs create mode 100644 src/CoiniumServ/Server/Web/Modules/Models/Error.cs create mode 100644 src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 12e3dcc9c..f39cec813 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -112,6 +112,7 @@ + @@ -173,6 +174,8 @@ + + diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs index 26d69c03c..9712a33ff 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs @@ -22,35 +22,58 @@ #endregion using System.Collections; using System.Collections.Generic; +using System.Dynamic; +using Coinium.Coin.Helpers; +using Newtonsoft.Json; namespace Coinium.Mining.Pools.Statistics { public class Algorithms : IAlgorithms { + public string Json { get; private set; } + private readonly Dictionary _algorithms; - private readonly IPools _poolStatistics; + private readonly Dictionary _response; + private readonly IPoolManager _poolManager; - public Algorithms(IPools poolStatistics) + public Algorithms(IPoolManager poolManager) { - _poolStatistics = poolStatistics; + _poolManager = poolManager; _algorithms = new Dictionary(); + _response = new Dictionary(); } public void Recache(object state) { + // recache data. foreach (var pair in _algorithms) { pair.Value.Reset(); } - foreach (var pair in _poolStatistics) + foreach (var pool in _poolManager.GetPools()) { - if (!_algorithms.ContainsKey(pair.Value.Algorithm)) - _algorithms.Add(pair.Value.Algorithm, new PerAlgorithm(pair.Value.Algorithm)); + if (!_algorithms.ContainsKey(pool.Config.Coin.Algorithm)) + _algorithms.Add(pool.Config.Coin.Algorithm, new PerAlgorithm(pool.Config.Coin.Algorithm)); - _algorithms[pair.Value.Algorithm].Hashrate = pair.Value.Hashrate; - _algorithms[pair.Value.Algorithm].WorkerCount = pair.Value.WorkerCount; + _algorithms[pool.Config.Coin.Algorithm].Recache(pool.Statistics.Hashrate, pool.Statistics.WorkerCount); } + + // recache response. + _response.Clear(); + + foreach (var pair in _algorithms) + { + var algorithm = pair.Value; + _response.Add(algorithm.Name, algorithm.GetResponseObject()); + } + + Json = JsonConvert.SerializeObject(_response); + } + + public IPerAlgorithm GetByName(string name) + { + return !_algorithms.ContainsKey(name) ? null : _algorithms[name]; } public IEnumerator> GetEnumerator() @@ -62,5 +85,10 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + public object GetResponseObject() + { + return _response; + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs index 9c7d63621..6fd911a40 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs @@ -21,6 +21,8 @@ // #endregion using System; +using System.Dynamic; +using Newtonsoft.Json; namespace Coinium.Mining.Pools.Statistics { @@ -28,24 +30,43 @@ public class Global : IGlobal { public UInt64 Hashrate { get; private set; } public Int32 WorkerCount { get; private set; } + public string Json { get; private set; } - private readonly IPools _poolStatistics; + private readonly dynamic _response; + private readonly IPools _pools; + private readonly IAlgorithms _algorithms; - public Global(IPools poolStatistics) + + public Global(IPools pools, IAlgorithms algorithms) { - _poolStatistics = poolStatistics; + _pools = pools; + _algorithms = algorithms; + _response = new ExpandoObject(); } public void Recache(object state) { + // recache data. Hashrate = 0; WorkerCount = 0; - foreach (var pair in _poolStatistics) + foreach (var pair in _pools) { Hashrate += pair.Value.Hashrate; WorkerCount += pair.Value.WorkerCount; } + + // recache response. + _response.hashrate = Hashrate; + _response.workers = WorkerCount; + _response.algorithms = _algorithms.GetResponseObject(); + + Json = JsonConvert.SerializeObject(_response); + } + + public object GetResponseObject() + { + return _response; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs index 2ebecd790..b165be861 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs @@ -24,7 +24,8 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IAlgorithms: IEnumerable>, IStatisticsProvider + public interface IAlgorithms: IEnumerable>, IJsonResponse, IStatisticsProvider { + IPerAlgorithm GetByName(string name); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs index 470090066..742254c42 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IGlobal: IStatisticsProvider + public interface IGlobal: IJsonResponse, IStatisticsProvider { UInt64 Hashrate { get; } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs b/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs new file mode 100644 index 000000000..f821da5ae --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs @@ -0,0 +1,32 @@ +#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 Coinium.Mining.Pools.Statistics +{ + public interface IJsonResponse + { + string Json { get; } + + object GetResponseObject(); + } +} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs index f4ba021e3..d103d2410 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs @@ -24,14 +24,16 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPerAlgorithm + public interface IPerAlgorithm:IJsonResponse { string Name { get; } - Int32 WorkerCount { get; set; } + Int32 WorkerCount { get; } - UInt64 Hashrate { get; set; } + UInt64 Hashrate { get; } void Reset(); + + void Recache(UInt64 hashrate, int workerCount); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs index 02be9086b..36ea1eb1f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPerPool: IStatisticsProvider + public interface IPerPool:IJsonResponse, IStatisticsProvider { UInt64 Hashrate { get; } @@ -37,7 +37,5 @@ public interface IPerPool: IStatisticsProvider int CurrentBlock { get; } IBlocks Blocks { get; } - - string Algorithm { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs index ca1618b4f..f47f07f63 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs @@ -24,7 +24,7 @@ namespace Coinium.Mining.Pools.Statistics { - public interface IPools : IEnumerable>, IStatisticsProvider + public interface IPools : IEnumerable>,IJsonResponse, IStatisticsProvider { } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs index 75d92f762..d23b0f356 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs @@ -20,17 +20,27 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; +using System.Dynamic; +using Newtonsoft.Json; + namespace Coinium.Mining.Pools.Statistics { public class PerAlgorithm:IPerAlgorithm { + public string Json { get; private set; } public string Name { get; private set; } - public int WorkerCount { get; set; } - public ulong Hashrate { get; set; } + public int WorkerCount { get; private set; } + public ulong Hashrate { get; private set; } + + private readonly dynamic _response; public PerAlgorithm(string algorithm) { Name = algorithm; + + _response = new ExpandoObject(); } public void Reset() @@ -38,5 +48,23 @@ public void Reset() Hashrate = 0; WorkerCount = 0; } + + public void Recache(UInt64 hashrate, int workerCount) + { + // recache data. + Hashrate = hashrate; + WorkerCount = workerCount; + + // recache json response. + _response.hashrate = Hashrate; + _response.workers = WorkerCount; + + Json = JsonConvert.SerializeObject(_response); + } + + public object GetResponseObject() + { + return _response; + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs index 46da61f57..95df5b362 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Dynamic; using System.Linq; using Coinium.Crypto.Algorithms; using Coinium.Daemon; @@ -28,6 +29,7 @@ using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Utils.Helpers.Time; +using Newtonsoft.Json; namespace Coinium.Mining.Pools.Statistics { @@ -39,13 +41,15 @@ public class PerPool:IPerPool public double Difficulty { get; private set; } public int CurrentBlock { get; private set; } public IBlocks Blocks { get; private set; } - public string Algorithm { get; private set; } + + public string Json { get; private set; } private readonly IDaemonClient _daemonClient; private readonly IStorage _storage; private readonly IHashAlgorithm _hashAlgorithm; private readonly IMinerManager _minerManager; private readonly IPoolConfig _poolConfig; + private readonly dynamic _response; private readonly double _shareMultiplier; private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ @@ -59,18 +63,34 @@ public PerPool(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager Blocks = blockStatistics; _storage = storage; + _response = new ExpandoObject(); _shareMultiplier = Math.Pow(2, 32) / _hashAlgorithm.Multiplier; } public void Recache(object state) { + // recache data. + WorkerCount = _minerManager.Miners.Count; + ReadCoinData(); ReadHashrate(); + Blocks.Recache(state); - WorkerCount = _minerManager.Miners.Count; - Algorithm = _poolConfig.Coin.Algorithm; + // recache json response. + _response.workers = WorkerCount; + _response.hashrate = Hashrate; - Blocks.Recache(state); + _response.coin = new ExpandoObject(); + _response.coin.symbol = _poolConfig.Coin.Symbol; + _response.coin.name = _poolConfig.Coin.Name; + _response.coin.algorithm = _poolConfig.Coin.Algorithm; + + _response.network = new ExpandoObject(); + _response.network.currentBlock = CurrentBlock; + _response.network.difficulty = Difficulty; + _response.network.hashrate = NetworkHashrate; + + Json = JsonConvert.SerializeObject(_response); } private void ReadHashrate() @@ -91,5 +111,10 @@ private void ReadCoinData() Difficulty = miningInfo.Difficulty; CurrentBlock = miningInfo.Blocks; } + + public object GetResponseObject() + { + return _response; + } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs index 3abad8b4a..d2eb1f18b 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs @@ -22,19 +22,24 @@ #endregion using System.Collections; using System.Collections.Generic; +using System.Dynamic; +using Newtonsoft.Json; namespace Coinium.Mining.Pools.Statistics { public class Pools:IPools { + public string Json { get; private set; } + private readonly Dictionary _pools; private readonly IPoolManager _poolManager; + private readonly Dictionary _response; public Pools(IPoolManager poolManager) { _poolManager = poolManager; _pools = new Dictionary(); - + _response = new Dictionary(); foreach (var pool in poolManager.GetPools()) { @@ -54,10 +59,26 @@ IEnumerator IEnumerable.GetEnumerator() public void Recache(object state) { + // recache data. foreach (var pool in _poolManager.GetPools()) { pool.Statistics.Recache(state); } + + // recache response. + _response.Clear(); + + foreach (var pool in _poolManager.GetPools()) + { + _response.Add(pool.Config.Coin.Symbol.ToLower(), (ExpandoObject)pool.Statistics.GetResponseObject()); + } + + Json = JsonConvert.SerializeObject(_response); + } + + public object GetResponseObject() + { + return _response; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index c82291e2f..7b90b7d62 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -45,9 +45,9 @@ public Statistics(IStatisticsObjectFactory statisticsObjectFactory) public void Recache(object state) { - Global.Recache(state); Pools.Recache(state); Algorithms.Recache(state); + Global.Recache(state); // reset the recache timer. _timer.Change(TimerExpiration * 1000, Timeout.Infinite); diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index 9e9b4de4d..aab9e2948 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System.Collections.Generic; + using System.Dynamic; using Coinium.Mining.Pools; using Coinium.Mining.Pools.Statistics; +using Coinium.Server.Web.Modules.Models; using Nancy; using Newtonsoft.Json; @@ -33,38 +34,41 @@ public class ApiModule: NancyModule { public ApiModule(IPoolManager poolManager, IStatistics statistics) { - Get["/api"] = _ => - { - return "Not implemented yet"; - }; + Get["/api"] = _ => View["api"]; - Get["/api/global"] = _ => + Get["/api/global"] = _ => Response.AsJson(statistics.Global.GetResponseObject()); + + Get["/api/pools"] = _ => Response.AsJson(statistics.Pools.GetResponseObject()); + Get["/api/pool/{slug}"] = _ => { - var algorithms = new Dictionary(); - - //foreach (var algo in poolManager.Statistics.Algorithms) - //{ - // dynamic @obj = new ExpandoObject(); - // algorithms.Add(algo.Name, @obj); - // @obj.hashrate = algo.Hashrate; - // @obj.workers = algo.Workers; - //} + var pool = poolManager.GetBySymbol(_.slug); - //var globalStats = new - //{ - // hashrate = poolManager.Statistics.Hashrate, - // workers = poolManager.Statistics.Workers, - // algorithms = algorithms, - //}; + Response response; - //return Response.AsJson(globalStats); + if (pool == null) + response = JsonConvert.SerializeObject(new JsonError("Pool not found!")); + else + response = (Response)pool.Json; - return null; + response.ContentType = "application/json"; + return response; }; - Get["/api/pools"] = _ => + Get["/api/algorithms"] = _ => Response.AsJson(statistics.Algorithms.GetResponseObject()); + + Get["/api/algorithm/{slug}"] = _ => { - return Response.AsJson(statistics); + var algorithm = statistics.Algorithms.GetByName(_.slug); + + Response response; + + if (algorithm == null) + response = JsonConvert.SerializeObject(new JsonError("Algorithm not found!")); + else + response = (Response)algorithm.Json; + + response.ContentType = "application/json"; + return response; }; } } diff --git a/src/CoiniumServ/Server/Web/Modules/Models/Error.cs b/src/CoiniumServ/Server/Web/Modules/Models/Error.cs new file mode 100644 index 000000000..dd460024d --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Models/Error.cs @@ -0,0 +1,31 @@ +#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 Coinium.Server.Web.Modules.Models +{ + public class Error + { + public string Summary { get; set; } + public string Details { get; set; } + } +} diff --git a/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs b/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs new file mode 100644 index 000000000..a8f50fce1 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs @@ -0,0 +1,35 @@ +#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 Coinium.Server.Web.Modules.Models +{ + public class JsonError + { + public string Error { get; private set; } + + public JsonError(string error) + { + Error = error; + } + } +} diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index 1ee8b6e38..3607a1bf7 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -21,6 +21,7 @@ // #endregion using Coinium.Mining.Pools; +using Coinium.Server.Web.Modules.Models; using Nancy; namespace Coinium.Server.Web.Modules @@ -37,7 +38,7 @@ public PoolModule(IPoolManager poolManager) return View["pool", pool]; - var error = new ErrorModel + var error = new Error { Summary = "Pool not found", Details = string.Format("The request pool does not exist: {0}", _.slug) @@ -46,11 +47,5 @@ public PoolModule(IPoolManager poolManager) return View["error", error]; }; } - - public class ErrorModel - { - public string Summary { get; set; } - public string Details { get; set; } - } } } From 212566340b89c2f7c15392c866cd90e8e057b879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 02:34:29 +0300 Subject: [PATCH 061/230] added pool central address, payment rewards and vardiff settings to pool configuration. --- src/CoiniumServ/config/pools/sample.json | 40 +++++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index 2b666a6da..e307a48ad 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -3,7 +3,12 @@ "coin": "litecoin.json", - # coin daemon config + # pool configuration + "pool" : { + "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" + }, + + # coin daemon connection configuration "daemon": { "host": "127.0.0.1", "port": 9333, @@ -11,29 +16,40 @@ "password": "password" }, - # stratum server config + # payment processing configuration + "payments": { + "enabled": false, + "interval": 60, + "minimum": 1, + "rewards": { + "myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1 + } + }, + + # stratum server configuration "stratum": { "enabled": true, "bind": "0.0.0.0", "port": 3333, - "diff": 16 + "diff": 16, + "vardiff": { + "enabled": true, + "minDiff": 8, + "maxDiff": 512, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } }, - # vanilla server config + # vanilla server configuration "vanilla": { "enabled": true, "bind": "localhost", "port": 3334 }, - # payment processing - "payments": { - "enabled": false, - "interval": 60, - "minimum": 1 - }, - - # mpos compat mode + # mpos compat mode configuration - not implemented yet! "mpos": { "enabled": false, "database": { From 8e9a6f507dad2d2bec6fc5873b9aa071f11c196d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 03:00:09 +0300 Subject: [PATCH 062/230] Started implementing vardiff. --- src/CoiniumServ/CoiniumServ.csproj | 9 ++- src/CoiniumServ/Mining/Pools/Pool.cs | 10 ++- .../Mining/Shares/IShareManager.cs | 2 + .../Mining/Shares/ShareEventArgs.cs | 38 ++++++++++ src/CoiniumServ/Mining/Shares/ShareManager.cs | 13 +++- .../Mining/Shares/ShareManagerFactory.cs | 3 - .../Mining/Vardiff/IVardiffManager.cs | 29 ++++++++ .../Mining/Vardiff/IVardiffManagerFactory.cs | 32 +++++++++ .../Mining/Vardiff/VardiffManager.cs | 44 ++++++++++++ .../Mining/Vardiff/VardiffManagerFactory.cs | 56 +++++++++++++++ src/CoiniumServ/Program.cs | 3 +- .../Repository/Registries/FactoryRegistry.cs | 2 + .../Repository/Registries/ManagerRegistry.cs | 2 + .../Utils/Console/ConsoleWindow.cs | 67 ------------------ src/CoiniumServ/Utils/ConsoleWindow.cs | 70 +++++++++++++++++++ .../Utils/{Logging => }/Logging.cs | 3 +- 16 files changed, 306 insertions(+), 77 deletions(-) create mode 100644 src/CoiniumServ/Mining/Shares/ShareEventArgs.cs create mode 100644 src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs create mode 100644 src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs create mode 100644 src/CoiniumServ/Mining/Vardiff/VardiffManager.cs create mode 100644 src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs delete mode 100644 src/CoiniumServ/Utils/Console/ConsoleWindow.cs create mode 100644 src/CoiniumServ/Utils/ConsoleWindow.cs rename src/CoiniumServ/Utils/{Logging => }/Logging.cs (99%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index f39cec813..d8aa3174b 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -141,6 +141,11 @@ + + + + + @@ -225,7 +230,7 @@ - + @@ -356,7 +361,7 @@ - + diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 29caed83c..ce10d24f5 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -33,6 +33,7 @@ using Coinium.Mining.Pools.Config; using Coinium.Mining.Pools.Statistics; using Coinium.Mining.Shares; +using Coinium.Mining.Vardiff; using Coinium.Payments; using Coinium.Persistance; using Coinium.Server; @@ -63,6 +64,7 @@ public class Pool : IPool private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; + private readonly IVardiffManagerFactory _varddManagerFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -71,6 +73,7 @@ public class Pool : IPool private IStorage _storage; private IHashAlgorithm _hashAlgorithm; private IPaymentProcessor _paymentProcessor; + private IVardiffManager _vardiffManager; private Dictionary _servers; @@ -104,7 +107,8 @@ public Pool( IShareManagerFactory shareManagerFactory, IStorageFactory storageFactory, IPaymentProcessorFactory paymentProcessorFactory, - IStatisticsObjectFactory statisticsObjectFactory) + IStatisticsObjectFactory statisticsObjectFactory, + IVardiffManagerFactory vardiffManagerFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); @@ -116,6 +120,7 @@ public Pool( Enforce.ArgumentNotNull(shareManagerFactory, "IShareManagerFactory"); Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); + Enforce.ArgumentNotNull(vardiffManagerFactory, "IVardiffManagerFactory"); _daemonClient = client; _minerManagerFactory = minerManagerFactory; @@ -128,6 +133,7 @@ public Pool( _storageFactory = storageFactory; _paymentProcessorFactory = paymentProcessorFactory; _statisticsObjectFactory = statisticsObjectFactory; + _varddManagerFactory = vardiffManagerFactory; GenerateInstanceId(); } @@ -175,6 +181,8 @@ private void InitManagers() _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage); + _vardiffManager = _varddManagerFactory.Get(_shareManager); + _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); diff --git a/src/CoiniumServ/Mining/Shares/IShareManager.cs b/src/CoiniumServ/Mining/Shares/IShareManager.cs index 386b3d1a4..605cc1c82 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManager.cs @@ -33,5 +33,7 @@ public interface IShareManager IShare ProcessShare(VanillaMiner miner, string data); event EventHandler BlockFound; + + event EventHandler ShareSubmitted; } } diff --git a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs new file mode 100644 index 000000000..84cc3df94 --- /dev/null +++ b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs @@ -0,0 +1,38 @@ +#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 Coinium.Server.Mining.Stratum; + +namespace Coinium.Mining.Shares +{ + public class ShareEventArgs:EventArgs + { + public StratumMiner Miner { get; private set; } + + public ShareEventArgs(StratumMiner miner) + { + Miner = miner; + } + } +} diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 249da74cc..53d63abc2 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -37,6 +37,8 @@ public class ShareManager : IShareManager { public event EventHandler BlockFound; + public event EventHandler ShareSubmitted; + private readonly IJobTracker _jobTracker; private readonly IDaemonClient _daemonClient; @@ -123,6 +125,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, Log.ForContext().Debug("Share rejected at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); } + OnShareSubmitted(new ShareEventArgs(miner)); // notify the listeners about the share. return share; } @@ -170,12 +173,20 @@ private bool CheckIfBlockAccepted(Share share) } } - protected virtual void OnBlockFound(EventArgs e) + private void OnBlockFound(EventArgs e) { var handler = BlockFound; if (handler != null) handler(this, e); } + + private void OnShareSubmitted(EventArgs e) + { + var handler = ShareSubmitted; + + if (handler != null) + handler(this, e); + } } } diff --git a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs index 965c93373..799830808 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs @@ -21,13 +21,10 @@ // #endregion using Coinium.Daemon; -using Coinium.Mining.Jobs; -using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Jobs.Tracker; using Coinium.Persistance; using Coinium.Repository.Context; using Nancy.TinyIoc; -using Serilog; namespace Coinium.Mining.Shares { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs new file mode 100644 index 000000000..5a54857a1 --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs @@ -0,0 +1,29 @@ +#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 Coinium.Mining.Vardiff +{ + public interface IVardiffManager + { + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs new file mode 100644 index 000000000..281dd087e --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs @@ -0,0 +1,32 @@ +#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 Coinium.Mining.Shares; + +namespace Coinium.Mining.Vardiff +{ + public interface IVardiffManagerFactory + { + IVardiffManager Get(IShareManager shareManager); + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs new file mode 100644 index 000000000..bd4ab73c3 --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -0,0 +1,44 @@ +#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 Coinium.Mining.Shares; + +namespace Coinium.Mining.Vardiff +{ + public class VardiffManager:IVardiffManager + { + public VardiffManager(IShareManager shareManager) + { + shareManager.ShareSubmitted += OnShare; + } + + private void OnShare(object sender, EventArgs e) + { + var shareArgs = (ShareEventArgs) e; + var miner = shareArgs.Miner; + + // TODO: implement vardiff. + } + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs new file mode 100644 index 000000000..b65378859 --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs @@ -0,0 +1,56 @@ +#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 Coinium.Mining.Shares; +using Coinium.Repository.Context; +using Nancy.TinyIoc; + +namespace Coinium.Mining.Vardiff +{ + public class VardiffManagerFactory : IVardiffManagerFactory + { + /// + /// The _kernel + /// + private readonly IApplicationContext _applicationContext; + + /// + /// Initializes a new instance of the class. + /// + /// The application context. + public VardiffManagerFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public IVardiffManager Get(IShareManager shareManager) + { + var @params = new NamedParameterOverloads + { + {"shareManager", shareManager}, + }; + + return _applicationContext.Container.Resolve(@params); + } + } +} diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 4e291d25c..27c0fefe5 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -28,10 +28,9 @@ using Coinium.Repository; using Coinium.Repository.Context; using Coinium.Server.Web; +using Coinium.Utils; using Coinium.Utils.Commands; using Coinium.Utils.Configuration; -using Coinium.Utils.Console; -using Coinium.Utils.Logging; using Coinium.Utils.Platform; using Serilog; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index aae80996f..1835274e5 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -29,6 +29,7 @@ using Coinium.Mining.Pools.Config; using Coinium.Mining.Pools.Statistics; using Coinium.Mining.Shares; +using Coinium.Mining.Vardiff; using Coinium.Payments; using Coinium.Persistance; using Coinium.Repository.Context; @@ -64,6 +65,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index b8691744e..960852396 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -24,6 +24,7 @@ using Coinium.Mining.Miners; using Coinium.Mining.Pools; using Coinium.Mining.Shares; +using Coinium.Mining.Vardiff; using Coinium.Repository.Context; namespace Coinium.Repository.Registries @@ -44,6 +45,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsMultiInstance(); } } } diff --git a/src/CoiniumServ/Utils/Console/ConsoleWindow.cs b/src/CoiniumServ/Utils/Console/ConsoleWindow.cs deleted file mode 100644 index 6ddd5b24b..000000000 --- a/src/CoiniumServ/Utils/Console/ConsoleWindow.cs +++ /dev/null @@ -1,67 +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; - -namespace Coinium.Utils.Console -{ - /// - /// Utility class to handle console window stuff. - /// - class ConsoleWindow - { - /// - /// Prints an info banner. - /// - public static void PrintBanner() - { - System.Console.ForegroundColor = ConsoleColor.Yellow; - System.Console.WriteLine(@" .__ .__ "); - System.Console.WriteLine(@" ____ ____ |__| ____ |__|__ __ _____ ______ ______________ __"); - System.Console.WriteLine(@"_/ ___\/ _ \| |/ \| | | \/ \ / ___// __ \_ __ \ \/ /"); - System.Console.WriteLine(@"\ \__( <_> ) | | \ | | / Y Y \\___ \\ ___/| | \/\ / "); - System.Console.WriteLine(@" \___ >____/|__|___| /__|____/|__|_| /____ >\___ >__| \_/ "); - System.Console.WriteLine(@" \/ \/ \/ \/ \/ "); - System.Console.WriteLine(); - } - - /// - /// Prints a copyright banner. - /// - public static void PrintLicense() - { - System.Console.ForegroundColor = ConsoleColor.Magenta; - System.Console.WriteLine("Copyright (C) 2013 - 2014, Coinium project - http://www.coinium.org"); - System.Console.WriteLine(); - System.Console.ForegroundColor = ConsoleColor.DarkYellow; - System.Console.WriteLine("CoiniumServ comes with ABSOLUTELY NO WARRANTY."); - System.Console.WriteLine(); - System.Console.ForegroundColor = ConsoleColor.Cyan; - System.Console.WriteLine("You can contribute the development of the project by donating;"); - System.Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D."); - System.Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa."); - System.Console.WriteLine("DOGE: D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc."); - System.Console.WriteLine(); - System.Console.ResetColor(); - } - } -} diff --git a/src/CoiniumServ/Utils/ConsoleWindow.cs b/src/CoiniumServ/Utils/ConsoleWindow.cs new file mode 100644 index 000000000..3c601bf5f --- /dev/null +++ b/src/CoiniumServ/Utils/ConsoleWindow.cs @@ -0,0 +1,70 @@ +#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; + +namespace Coinium.Utils +{ + /// + /// Utility class to handle console window stuff. + /// + class ConsoleWindow + { + /// + /// Prints an info banner. + /// + public static void PrintBanner() + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(@" .__ .__ "); + Console.WriteLine(@" ____ ____ |__| ____ |__|__ __ _____ ______ ______________ __"); + Console.WriteLine(@"_/ ___\/ _ \| |/ \| | | \/ \ / ___// __ \_ __ \ \/ /"); + Console.WriteLine(@"\ \__( <_> ) | | \ | | / Y Y \\___ \\ ___/| | \/\ / "); + Console.WriteLine(@" \___ >____/|__|___| /__|____/|__|_| /____ >\___ >__| \_/ "); + Console.WriteLine(@" \/ \/ \/ \/ \/ "); + Console.WriteLine(); + } + + /// + /// Prints a copyright banner. + /// + public static void PrintLicense() + { + Console.ForegroundColor = ConsoleColor.Magenta; + Console.WriteLine("Copyright (C) 2013 - 2014, Coinium project - http://www.coinium.org"); + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine("CoiniumServ comes with ABSOLUTELY NO WARRANTY."); + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("You can contribute the development of the project by donating;"); + Console.ForegroundColor = ConsoleColor.Yellow; + //Console.BackgroundColor=ConsoleColor.DarkGray; + Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D."); + Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa."); + Console.WriteLine("DOGE: D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc."); + Console.WriteLine(); + Console.ResetColor(); + } + } +} diff --git a/src/CoiniumServ/Utils/Logging/Logging.cs b/src/CoiniumServ/Utils/Logging.cs similarity index 99% rename from src/CoiniumServ/Utils/Logging/Logging.cs rename to src/CoiniumServ/Utils/Logging.cs index f060d2096..b2d352122 100644 --- a/src/CoiniumServ/Utils/Logging/Logging.cs +++ b/src/CoiniumServ/Utils/Logging.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; using System.Linq; @@ -28,7 +29,7 @@ using Serilog.Core; using Serilog.Events; -namespace Coinium.Utils.Logging +namespace Coinium.Utils { /// /// Controls the logging facilities. From a7f0d84eb49ae69be3f6f44ced79e3a3c42278c0 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 12:05:49 +0300 Subject: [PATCH 063/230] Moved services to correct folders. --- src/CoiniumServ/CoiniumServ.csproj | 20 +++++++++---------- src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- .../Repository/Registries/FactoryRegistry.cs | 2 +- .../Repository/Registries/ServiceRegistry.cs | 6 +++--- .../Mining}/Service/IRpcService.cs | 2 +- .../Mining}/Service/IServiceFactory.cs | 3 ++- .../Mining}/Service/ServiceFactory.cs | 3 ++- .../{ => Server/Mining}/Service/Services.cs | 2 +- .../Stratum/Config/StratumServerConfig.cs | 2 +- .../Stratum/Service}/SocketServiceContext.cs | 3 ++- .../Stratum/Service}/SocketServiceRequest.cs | 3 ++- .../Mining/Stratum/Service}/StratumService.cs | 5 +++-- .../Server/Mining/Stratum/StratumMiner.cs | 2 +- .../Vanilla/Config/VanillaServerConfig.cs | 2 +- .../Vanilla/Service}/HttpServiceContext.cs | 3 ++- .../Vanilla/Service}/HttpServiceRequest.cs | 3 ++- .../Mining/Vanilla/Service}/VanillaService.cs | 5 +++-- .../Server/Mining/Vanilla/VanillaMiner.cs | 2 +- src/Tests/Mining/Pools/PoolTests.cs | 2 +- 19 files changed, 40 insertions(+), 32 deletions(-) rename src/CoiniumServ/{ => Server/Mining}/Service/IRpcService.cs (96%) rename src/CoiniumServ/{ => Server/Mining}/Service/IServiceFactory.cs (97%) rename src/CoiniumServ/{ => Server/Mining}/Service/ServiceFactory.cs (98%) rename src/CoiniumServ/{ => Server/Mining}/Service/Services.cs (96%) rename src/CoiniumServ/{Service/Stratum => Server/Mining/Stratum/Service}/SocketServiceContext.cs (96%) rename src/CoiniumServ/{Service/Stratum => Server/Mining/Stratum/Service}/SocketServiceRequest.cs (96%) rename src/CoiniumServ/{Service/Stratum => Server/Mining/Stratum/Service}/StratumService.cs (97%) rename src/CoiniumServ/{Service/Vanilla => Server/Mining/Vanilla/Service}/HttpServiceContext.cs (96%) rename src/CoiniumServ/{Service/Vanilla => Server/Mining/Vanilla/Service}/HttpServiceRequest.cs (97%) rename src/CoiniumServ/{Service/Vanilla => Server/Mining/Vanilla/Service}/VanillaService.cs (96%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index d8aa3174b..7f08e4b1b 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -223,7 +223,7 @@ - + @@ -288,12 +288,12 @@ - + - - + + @@ -301,20 +301,20 @@ - - + + - + - - + + - + diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index ce10d24f5..87b5957bf 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -38,7 +38,7 @@ using Coinium.Persistance; using Coinium.Server; using Coinium.Server.Mining; -using Coinium.Service; +using Coinium.Server.Mining.Service; using Coinium.Utils.Helpers.Validation; using Serilog; diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 1835274e5..ec95a7187 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -34,7 +34,7 @@ using Coinium.Persistance; using Coinium.Repository.Context; using Coinium.Server; -using Coinium.Service; +using Coinium.Server.Mining.Service; using Coinium.Utils.Configuration; namespace Coinium.Repository.Registries diff --git a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs index a17bac675..990948c19 100644 --- a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs @@ -21,9 +21,9 @@ // #endregion using Coinium.Repository.Context; -using Coinium.Service; -using Coinium.Service.Stratum; -using Coinium.Service.Vanilla; +using Coinium.Server.Mining.Service; +using Coinium.Server.Mining.Stratum.Service; +using Coinium.Server.Mining.Vanilla.Service; namespace Coinium.Repository.Registries { diff --git a/src/CoiniumServ/Service/IRpcService.cs b/src/CoiniumServ/Server/Mining/Service/IRpcService.cs similarity index 96% rename from src/CoiniumServ/Service/IRpcService.cs rename to src/CoiniumServ/Server/Mining/Service/IRpcService.cs index 1f5d64c32..dd410bb9b 100644 --- a/src/CoiniumServ/Service/IRpcService.cs +++ b/src/CoiniumServ/Server/Mining/Service/IRpcService.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Service +namespace Coinium.Server.Mining.Service { public interface IRpcService { } diff --git a/src/CoiniumServ/Service/IServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs similarity index 97% rename from src/CoiniumServ/Service/IServiceFactory.cs rename to src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs index 0e99f948f..32c91f836 100644 --- a/src/CoiniumServ/Service/IServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Coinium.Daemon; using Coinium.Mining.Shares; -namespace Coinium.Service +namespace Coinium.Server.Mining.Service { public interface IServiceFactory { diff --git a/src/CoiniumServ/Service/ServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs similarity index 98% rename from src/CoiniumServ/Service/ServiceFactory.cs rename to src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs index f6ee17002..2bf1d0276 100644 --- a/src/CoiniumServ/Service/ServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Coinium.Daemon; using Coinium.Mining.Shares; using Coinium.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Service +namespace Coinium.Server.Mining.Service { public class ServiceFactory : IServiceFactory { diff --git a/src/CoiniumServ/Service/Services.cs b/src/CoiniumServ/Server/Mining/Service/Services.cs similarity index 96% rename from src/CoiniumServ/Service/Services.cs rename to src/CoiniumServ/Server/Mining/Service/Services.cs index 06c5d20e4..091dd6b8b 100644 --- a/src/CoiniumServ/Service/Services.cs +++ b/src/CoiniumServ/Server/Mining/Service/Services.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Service +namespace Coinium.Server.Mining.Service { public static class Services { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index 9d03c8bf3..dc48bd22e 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -21,7 +21,7 @@ // #endregion using System; -using Coinium.Service; +using Coinium.Server.Mining.Service; namespace Coinium.Server.Mining.Stratum.Config { diff --git a/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs similarity index 96% rename from src/CoiniumServ/Service/Stratum/SocketServiceContext.cs rename to src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs index 4e40acd5c..b5ce134ad 100644 --- a/src/CoiniumServ/Service/Stratum/SocketServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Coinium.Mining.Miners; -namespace Coinium.Service.Stratum +namespace Coinium.Server.Mining.Stratum.Service { public class SocketServiceContext { diff --git a/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs similarity index 96% rename from src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs rename to src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs index f1105661c..6f86345c6 100644 --- a/src/CoiniumServ/Service/Stratum/SocketServiceRequest.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Newtonsoft.Json; -namespace Coinium.Service.Stratum +namespace Coinium.Server.Mining.Stratum.Service { /// /// JsonRpc 2.0 over sockets request. diff --git a/src/CoiniumServ/Service/Stratum/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs similarity index 97% rename from src/CoiniumServ/Service/Stratum/StratumService.cs rename to src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 048861dea..544046b2b 100644 --- a/src/CoiniumServ/Service/Stratum/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; using Coinium.Mining.Jobs; using Coinium.Mining.Shares; -using Coinium.Server.Mining.Stratum; +using Coinium.Server.Mining.Service; using Coinium.Server.Mining.Stratum.Responses; -namespace Coinium.Service.Stratum +namespace Coinium.Server.Mining.Stratum.Service { /// /// Stratum protocol implementation. diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index b670d880e..553726842 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -28,7 +28,7 @@ using Coinium.Net.Server.Sockets; using Coinium.Server.Mining.Stratum.Errors; using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Service.Stratum; +using Coinium.Server.Mining.Stratum.Service; using Coinium.Utils.Extensions; using Newtonsoft.Json; using Serilog; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs index ae78e627c..6ba4fc3b0 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs @@ -21,7 +21,7 @@ // #endregion using System; -using Coinium.Service; +using Coinium.Server.Mining.Service; namespace Coinium.Server.Mining.Vanilla.Config { diff --git a/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs similarity index 96% rename from src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs rename to src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs index 7dc9f5e40..ab96bb41f 100644 --- a/src/CoiniumServ/Service/Vanilla/HttpServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Coinium.Mining.Miners; -namespace Coinium.Service.Vanilla +namespace Coinium.Server.Mining.Vanilla.Service { public class HttpServiceContext { diff --git a/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs similarity index 97% rename from src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs rename to src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs index bf4ab05ba..43bae7e7b 100644 --- a/src/CoiniumServ/Service/Vanilla/HttpServiceRequest.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Net; using Newtonsoft.Json; -namespace Coinium.Service.Vanilla +namespace Coinium.Server.Mining.Vanilla.Service { /// /// JsonRpc 1.0 over http request. diff --git a/src/CoiniumServ/Service/Vanilla/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs similarity index 96% rename from src/CoiniumServ/Service/Vanilla/VanillaService.cs rename to src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index 0124b6979..a316aecf2 100644 --- a/src/CoiniumServ/Service/Vanilla/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Shares; -using Coinium.Server.Mining.Vanilla; +using Coinium.Server.Mining.Service; using Serilog; -namespace Coinium.Service.Vanilla +namespace Coinium.Server.Mining.Vanilla.Service { /// /// Stratum protocol implementation. diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 18d37150e..af19abb39 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -28,7 +28,7 @@ using Coinium.Mining.Miners; using Coinium.Mining.Pools; using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Service.Vanilla; +using Coinium.Server.Mining.Vanilla.Service; using Coinium.Utils.Extensions; using Serilog; diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index c68a6e0b3..1f7de7e13 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -33,7 +33,7 @@ using Coinium.Persistance; using Coinium.Server; using Coinium.Server.Mining; -using Coinium.Service; +using Coinium.Server.Mining.Service; using NSubstitute; using Should.Fluent; using Xunit; From 4a4c862e36a4c4c67e4737b4fcbf19e636d3d558 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 12:43:04 +0300 Subject: [PATCH 064/230] Implemented ringbuffer. --- src/CoiniumServ/CoiniumServ.csproj | 1 + src/CoiniumServ/Utils/RingBuffer.cs | 80 +++++++++++++++++++++++++++++ src/Tests/Mining/Pools/PoolTests.cs | 14 ++++- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/CoiniumServ/Utils/RingBuffer.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 7f08e4b1b..36ead9200 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -233,6 +233,7 @@ + diff --git a/src/CoiniumServ/Utils/RingBuffer.cs b/src/CoiniumServ/Utils/RingBuffer.cs new file mode 100644 index 000000000..7deb772ee --- /dev/null +++ b/src/CoiniumServ/Utils/RingBuffer.cs @@ -0,0 +1,80 @@ +#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.Linq; + +namespace Coinium.Utils +{ + public class RingBuffer + { + public int Size { get { return _isFull ? Capacity : _cursor; } } + + private readonly int[] _buffer; + + private int _cursor; + + private bool _isFull; + private int Capacity { get { return _buffer.Length; } } + + public RingBuffer(int capacity) + { + _buffer = new int[capacity]; + _cursor = 0; + _isFull = false; + } + + public void Clear() + { + for (int i = 0; i < Capacity; i++) + _buffer[i] = default(int); + + _cursor = 0; + _isFull = false; + } + + public void Append(int item) + { + _buffer[_cursor] = item; + + if (_isFull) + { + _cursor = (_cursor + 1) % Capacity; + } + else + { + _cursor++; + + if (_cursor >= Capacity) + { + _cursor = 0; + _isFull = true; + } + } + } + + public float Average() + { + return _buffer.Sum()/(_isFull ? Capacity : _cursor); + } + } +} diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 1f7de7e13..e17b915c1 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -29,6 +29,7 @@ using Coinium.Mining.Pools.Config; using Coinium.Mining.Pools.Statistics; using Coinium.Mining.Shares; +using Coinium.Mining.Vardiff; using Coinium.Payments; using Coinium.Persistance; using Coinium.Server; @@ -53,6 +54,7 @@ public class PoolTests private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; + private readonly IVardiffManagerFactory _vardiffManagerFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -65,6 +67,7 @@ public class PoolTests private readonly IRpcService _rpcService; private readonly IPaymentProcessor _paymentProcessor; private readonly IStatistics _statistics; + private readonly IVardiffManager _vardiffManager; /// /// Initialize mock objects. @@ -81,6 +84,7 @@ public PoolTests() _storageFactory = Substitute.For(); _paymentProcessorFactory = Substitute.For(); _statisticsObjectFactory = Substitute.For(); + _vardiffManagerFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -92,6 +96,7 @@ public PoolTests() _storage = Substitute.For(); _paymentProcessor = Substitute.For(); _statistics = Substitute.For(); + _vardiffManager = Substitute.For(); } /// @@ -111,7 +116,8 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _shareManagerFactory, _storageFactory, _paymentProcessorFactory, - _statisticsObjectFactory + _statisticsObjectFactory, + _vardiffManagerFactory ); pool.Should().Not.Be.Null(); @@ -135,7 +141,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _shareManagerFactory, _storageFactory, _paymentProcessorFactory, - _statisticsObjectFactory + _statisticsObjectFactory, + _vardiffManagerFactory ); pool.Should().Not.Be.Null(); @@ -164,6 +171,9 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // initialize share manager. _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage).Returns(_shareManager); + // vardiff manager + _vardiffManagerFactory.Get(_shareManager); + // initalize job manager. _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm).Returns(_jobManager); _jobManager.Initialize(pool.InstanceId); From 9bc09edc9071f180a8267ba9344c85fd486728df Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 13:01:35 +0300 Subject: [PATCH 065/230] More vardiff work. --- src/CoiniumServ/CoiniumServ.csproj | 5 ++- src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- .../Mining/Vardiff/IVardiffConfig.cs | 40 +++++++++++++++++ .../Mining/Vardiff/IVardiffManager.cs | 1 + .../Mining/Vardiff/IVardiffManagerFactory.cs | 2 +- .../Mining/Vardiff/VardiffConfig.cs | 45 +++++++++++++++++++ .../Mining/Vardiff/VardiffManager.cs | 7 ++- .../Mining/Vardiff/VardiffManagerFactory.cs | 3 +- .../Persistance/Redis/IRedisConfig.cs | 2 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 2 +- .../Persistance/Redis/RedisConfig.cs | 4 +- .../Stratum/Config/IStratumServerConfig.cs | 3 ++ .../Stratum/Config/StratumServerConfig.cs | 4 ++ .../Server/Mining/Stratum/IStratumMiner.cs | 3 ++ .../Server/Mining/Stratum/StratumMiner.cs | 3 ++ src/CoiniumServ/Utils/Buffers/IRingBuffer.cs | 36 +++++++++++++++ .../Utils/{ => Buffers}/RingBuffer.cs | 11 ++--- .../Configuration/IGlobalConfigFactory.cs | 3 +- 18 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs create mode 100644 src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs create mode 100644 src/CoiniumServ/Utils/Buffers/IRingBuffer.cs rename src/CoiniumServ/Utils/{ => Buffers}/RingBuffer.cs (92%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 36ead9200..2853ef7f9 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -142,8 +142,10 @@ + + @@ -230,10 +232,11 @@ + - + diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 87b5957bf..cc8597733 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -181,7 +181,7 @@ private void InitManagers() _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage); - _vardiffManager = _varddManagerFactory.Get(_shareManager); + _vardiffManager = _varddManagerFactory.Get(Config.Stratum.Vardiff, _shareManager); _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); _jobManager.Initialize(InstanceId); diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs new file mode 100644 index 000000000..e76c2c696 --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs @@ -0,0 +1,40 @@ +#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 Coinium.Mining.Vardiff +{ + public interface IVardiffConfig + { + bool Enabled { get; } + + int MinimumDifficulty { get; } + + int MaximumDifficulty { get; } + + int TargetTime { get; } + + int RetargetTime { get; } + + int VariancePercent { get; } + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs index 5a54857a1..e85d4637d 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs @@ -25,5 +25,6 @@ namespace Coinium.Mining.Vardiff { public interface IVardiffManager { + IVardiffConfig Config { get; } } } diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs index 281dd087e..a55eb0270 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs @@ -27,6 +27,6 @@ namespace Coinium.Mining.Vardiff { public interface IVardiffManagerFactory { - IVardiffManager Get(IShareManager shareManager); + IVardiffManager Get(IVardiffConfig vardiffConfig, IShareManager shareManager); } } diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs new file mode 100644 index 000000000..5a46a59d5 --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs @@ -0,0 +1,45 @@ +#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 Coinium.Mining.Vardiff +{ + public class VardiffConfig:IVardiffConfig + { + public bool Enabled { get; private set; } + public int MinimumDifficulty { get; private set; } + public int MaximumDifficulty { get; private set; } + public int TargetTime { get; private set; } + public int RetargetTime { get; private set; } + public int VariancePercent { get; private set; } + + public VardiffConfig(dynamic config) + { + Enabled = config.enabled; + MinimumDifficulty = config.minDiff; + MaximumDifficulty = config.maxDiff; + TargetTime = config.targetTime; + RetargetTime = config.retargetTime; + VariancePercent = config.variancePercent; + } + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index bd4ab73c3..6e432dd1e 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -28,8 +28,11 @@ namespace Coinium.Mining.Vardiff { public class VardiffManager:IVardiffManager { - public VardiffManager(IShareManager shareManager) + public IVardiffConfig Config { get; private set; } + + public VardiffManager(IVardiffConfig vardiffConfig, IShareManager shareManager) { + Config = vardiffConfig; shareManager.ShareSubmitted += OnShare; } @@ -38,7 +41,7 @@ private void OnShare(object sender, EventArgs e) var shareArgs = (ShareEventArgs) e; var miner = shareArgs.Miner; - // TODO: implement vardiff. + } } } diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs index b65378859..c0dbc1a0d 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs @@ -43,10 +43,11 @@ public VardiffManagerFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; } - public IVardiffManager Get(IShareManager shareManager) + public IVardiffManager Get(IVardiffConfig vardiffConfig, IShareManager shareManager) { var @params = new NamedParameterOverloads { + {"vardiffConfig", vardiffConfig}, {"shareManager", shareManager}, }; diff --git a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs index fc96e10f5..509857ef5 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs @@ -26,7 +26,7 @@ namespace Coinium.Persistance.Redis { public interface IRedisConfig { - bool IsEnabled { get; } + bool Enabled { get; } string Host { get; } Int32 Port { get; } string Password { get; } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 055f6ed34..b6bc015ca 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -56,7 +56,7 @@ public Redis(IGlobalConfigFactory globalConfigFactory, IPoolConfig poolConfig) { _poolConfig = poolConfig; // the pool config. _redisConfig = globalConfigFactory.GetRedisConfig(); // read the redis config. - IsEnabled = _redisConfig.IsEnabled; + IsEnabled = _redisConfig.Enabled; if (IsEnabled) Initialize(); diff --git a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs index a9d54b77a..96e538b49 100644 --- a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs @@ -26,7 +26,7 @@ namespace Coinium.Persistance.Redis { public class RedisConfig:IRedisConfig { - public bool IsEnabled { get; private set; } + public bool Enabled { get; private set; } public string Host { get; private set; } public Int32 Port { get; private set; } public string Password { get; private set; } @@ -34,7 +34,7 @@ public class RedisConfig:IRedisConfig public RedisConfig(dynamic config) { - IsEnabled = config.enabled; + Enabled = config.enabled; Host = config.host; Port = config.port; Password = config.password; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index 59e368bc2..89fdd11c9 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -21,11 +21,14 @@ // #endregion using System; +using Coinium.Mining.Vardiff; namespace Coinium.Server.Mining.Stratum.Config { public interface IStratumServerConfig : IServerConfig { Int32 Diff { get; } + + IVardiffConfig Vardiff { get; } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index dc48bd22e..f35bd4a6a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -21,6 +21,7 @@ // #endregion using System; +using Coinium.Mining.Vardiff; using Coinium.Server.Mining.Service; namespace Coinium.Server.Mining.Stratum.Config @@ -38,6 +39,7 @@ public class StratumServerConfig:IStratumServerConfig public Int32 Port { get; private set; } public Int32 Diff { get; private set; } + public IVardiffConfig Vardiff { get; private set; } public StratumServerConfig(dynamic config) { @@ -53,6 +55,8 @@ public StratumServerConfig(dynamic config) Port = config.port; Diff = config.diff; + Vardiff = new VardiffConfig(config.vardiff); + Valid = true; } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index 3453bef26..12ccce54e 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -22,6 +22,7 @@ #endregion using System; using Coinium.Mining.Miners; +using Coinium.Utils.Buffers; namespace Coinium.Server.Mining.Stratum { @@ -31,5 +32,7 @@ public interface IStratumMiner:IMiner /// Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) /// UInt32 ExtraNonce { get; } + + IRingBuffer VardiffBuffer { get; set; } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 553726842..29d596fb7 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -29,6 +29,7 @@ using Coinium.Server.Mining.Stratum.Errors; using Coinium.Server.Mining.Stratum.Notifications; using Coinium.Server.Mining.Stratum.Service; +using Coinium.Utils.Buffers; using Coinium.Utils.Extensions; using Newtonsoft.Json; using Serilog; @@ -75,6 +76,8 @@ public class StratumMiner : IClient, IStratumMiner /// public uint ExtraNonce { get; private set; } + public IRingBuffer VardiffBuffer { get; set; } + private readonly IMinerManager _minerManager; /// diff --git a/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs b/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs new file mode 100644 index 000000000..1f0901473 --- /dev/null +++ b/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs @@ -0,0 +1,36 @@ +#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 Coinium.Utils.Buffers +{ + public interface IRingBuffer + { + int Size { get; } + + void Clear(); + + void Append(int item); + + float Average { get; } + } +} diff --git a/src/CoiniumServ/Utils/RingBuffer.cs b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs similarity index 92% rename from src/CoiniumServ/Utils/RingBuffer.cs rename to src/CoiniumServ/Utils/Buffers/RingBuffer.cs index 7deb772ee..45b34d5c3 100644 --- a/src/CoiniumServ/Utils/RingBuffer.cs +++ b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs @@ -23,12 +23,14 @@ using System.Linq; -namespace Coinium.Utils +namespace Coinium.Utils.Buffers { - public class RingBuffer + public class RingBuffer:IRingBuffer { public int Size { get { return _isFull ? Capacity : _cursor; } } + public float Average { get { return _buffer.Sum() / (_isFull ? Capacity : _cursor); } } + private readonly int[] _buffer; private int _cursor; @@ -71,10 +73,5 @@ public void Append(int item) } } } - - public float Average() - { - return _buffer.Sum()/(_isFull ? Capacity : _cursor); - } } } diff --git a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs index b3a5a1b2a..900f48db6 100644 --- a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using Coinium.Mining.Vardiff; using Coinium.Persistance.Redis; using Coinium.Server.Web; @@ -36,6 +38,5 @@ public interface IGlobalConfigFactory IRedisConfig GetRedisConfig(); IWebServerConfig GetWebServerConfig(); - } } From a43c65d406df9764cabff33adee3681129279682 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 15:33:29 +0300 Subject: [PATCH 066/230] Vardiff implementation done. We won't be sending difficulty everytime we send a new job to miners. --- src/CoiniumServ/CoiniumServ.csproj | 1 + .../Mining/Jobs/Manager/JobManager.cs | 1 - src/CoiniumServ/Mining/Miners/IMiner.cs | 4 +- src/CoiniumServ/Mining/Miners/MinerManager.cs | 5 +- src/CoiniumServ/Mining/Pools/Pool.cs | 1 + .../Mining/Vardiff/IVardiffMiner.cs | 36 ++++++++++++ .../Mining/Vardiff/VardiffManager.cs | 57 ++++++++++++++++++- .../Server/Mining/Stratum/IStratumMiner.cs | 6 +- .../Stratum/Notifications/Difficulty.cs | 14 ++--- .../Server/Mining/Stratum/StratumMiner.cs | 10 +++- .../Server/Mining/Vanilla/VanillaMiner.cs | 5 +- src/CoiniumServ/Utils/Buffers/RingBuffer.cs | 2 +- src/CoiniumServ/Utils/ConsoleWindow.cs | 3 +- src/Tests/Mining/Pools/PoolTests.cs | 3 +- 14 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 2853ef7f9..7f86ac113 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -142,6 +142,7 @@ + diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 394ae9890..d639ddae0 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -183,7 +183,6 @@ private bool SendJobToMiner(IMiner miner, IJob job) if (!miner.SupportsJobNotifications) return false; - miner.SendDifficulty(); miner.SendJob(job); return true; diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Mining/Miners/IMiner.cs index 691fe25c9..8120c87aa 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Mining/Miners/IMiner.cs @@ -20,6 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; using Coinium.Mining.Pools; using Coinium.Server.Mining.Stratum.Notifications; @@ -52,7 +54,7 @@ public interface IMiner IPool Pool { get; } - Difficulty Difficulty { get; } + float Difficulty { get; set; } /// /// Authenticates the miner. diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index 120f1b8cf..ea6730bec 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -100,8 +100,11 @@ public void Authenticate(IMiner miner) Log.ForContext().Information(miner.Authenticated ? "Authenticated miner: {0} [{1}]" : "Unauthenticated miner: {0} [{1}]", miner.Username, ((IClient) miner).Connection.RemoteEndPoint); - if(miner.Authenticated) // if miner authenticated successfully. + if (miner.Authenticated) // if miner authenticated successfully. + { + miner.SendDifficulty(); // send the initial difficulty. OnMinerAuthenticated(new MinerEventArgs(miner)); // notify listeners about the new authenticated miner. + } } protected virtual void OnMinerAuthenticated(MinerEventArgs e) diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index cc8597733..d5a3325aa 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -96,6 +96,7 @@ public class Pool : IPool /// /// /// + /// public Pool( IHashAlgorithmFactory hashAlgorithmFactory, IServerFactory serverFactory, diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs new file mode 100644 index 000000000..f2fe0b05c --- /dev/null +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs @@ -0,0 +1,36 @@ +#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 Coinium.Utils.Buffers; + +namespace Coinium.Mining.Vardiff +{ + public interface IVardiffMiner + { + int LastVardiffTimestamp { get; set; } + + int LastVardiffRetarget { get; set; } + + IRingBuffer VardiffBuffer { get; set; } + } +} diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index 6e432dd1e..d077bb473 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -23,6 +23,8 @@ using System; using Coinium.Mining.Shares; +using Coinium.Utils.Buffers; +using Coinium.Utils.Helpers.Time; namespace Coinium.Mining.Vardiff { @@ -30,10 +32,24 @@ public class VardiffManager:IVardiffManager { public IVardiffConfig Config { get; private set; } + private float _variance; + private int _bufferSize; + private float _tMin; + private float _tMax; + public VardiffManager(IVardiffConfig vardiffConfig, IShareManager shareManager) { Config = vardiffConfig; + + if (!Config.Enabled) + return; + shareManager.ShareSubmitted += OnShare; + + _variance = vardiffConfig.TargetTime*((float)vardiffConfig.VariancePercent/100); + _bufferSize = vardiffConfig.RetargetTime/vardiffConfig.TargetTime*4; + _tMin = vardiffConfig.TargetTime - _variance; + _tMax = vardiffConfig.TargetTime + _variance; } private void OnShare(object sender, EventArgs e) @@ -41,7 +57,46 @@ private void OnShare(object sender, EventArgs e) var shareArgs = (ShareEventArgs) e; var miner = shareArgs.Miner; - + if (miner == null) + return; + + var now = TimeHelpers.NowInUnixTime(); + + if (miner.VardiffBuffer == null) + { + miner.LastVardiffRetarget = now - Config.RetargetTime / 2; + miner.LastVardiffTimestamp = now; + miner.VardiffBuffer = new RingBuffer(_bufferSize); + return; + } + + var sinceLast = now - miner.LastVardiffTimestamp; // how many seconds elapsed since last share? + miner.VardiffBuffer.Append(sinceLast); // append it to vardiff buffer. + miner.LastVardiffTimestamp = now; + + if (now - miner.LastVardiffRetarget < Config.RetargetTime && miner.VardiffBuffer.Size > 0) // check if we need a re-target. + return; + + miner.LastVardiffRetarget = now; + var average = miner.VardiffBuffer.Average; + var deltaDiff = Config.TargetTime/average; + + if (average > _tMax && miner.Difficulty > Config.MinimumDifficulty) + { + if (deltaDiff*miner.Difficulty < Config.MinimumDifficulty) + deltaDiff = Config.MinimumDifficulty/miner.Difficulty; + } + else if (average < _tMin) + { + if (deltaDiff*miner.Difficulty > Config.MaximumDifficulty) + deltaDiff = Config.MaximumDifficulty/miner.Difficulty; + } + else + return; + + miner.Difficulty = miner.Difficulty*deltaDiff; + miner.SendDifficulty(); + miner.VardiffBuffer.Clear(); } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index 12ccce54e..d57caf99e 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -22,17 +22,15 @@ #endregion using System; using Coinium.Mining.Miners; -using Coinium.Utils.Buffers; +using Coinium.Mining.Vardiff; namespace Coinium.Server.Mining.Stratum { - public interface IStratumMiner:IMiner + public interface IStratumMiner:IMiner, IVardiffMiner { /// /// Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) /// UInt32 ExtraNonce { get; } - - IRingBuffer VardiffBuffer { get; set; } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs index 6eb549029..de404937f 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; + using System.Collections; using System.Collections.Generic; -using System.Globalization; using Newtonsoft.Json; namespace Coinium.Server.Mining.Stratum.Notifications { + // TODO: can we get rid of this? + [JsonArray] public class Difficulty : IEnumerable { @@ -35,13 +36,13 @@ public class Difficulty : IEnumerable /// Difficulty for jobs. /// [JsonIgnore] - private readonly UInt32 _diff; + private readonly float _diff; /// /// Creates a new instance of JobNotification. /// /// - public Difficulty(UInt32 difficulty) + public Difficulty(float difficulty) { _diff = difficulty; } @@ -60,10 +61,5 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - - public override string ToString() - { - return _diff.ToString(CultureInfo.InvariantCulture); - } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 29d596fb7..e7eda68c3 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -64,7 +64,8 @@ public class StratumMiner : IClient, IStratumMiner public bool Authenticated { get; set; } public IPool Pool { get; private set; } - public Difficulty Difficulty { get; private set; } + + public float Difficulty { get; set; } /// /// Sends a new mining job to the miner. @@ -76,6 +77,8 @@ public class StratumMiner : IClient, IStratumMiner /// public uint ExtraNonce { get; private set; } + public int LastVardiffTimestamp { get; set; } + public int LastVardiffRetarget { get; set; } public IRingBuffer VardiffBuffer { get; set; } private readonly IMinerManager _minerManager; @@ -95,7 +98,7 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo Connection = connection; // the underlying connection. _minerManager = minerManager; Pool = pool; - Difficulty = new Difficulty(16); // set miner difficulty. + Difficulty = 16; // set miner difficulty. Subscribed = false; // miner has to subscribe. Authenticated = false; // miner has to authenticate. @@ -169,7 +172,7 @@ public void SendDifficulty() { Id = null, Method = "mining.set_difficulty", - Params = Difficulty + Params = new Difficulty(Difficulty) }; var json = JsonConvert.SerializeObject(notification) + "\n"; @@ -177,6 +180,7 @@ public void SendDifficulty() var data = Encoding.UTF8.GetBytes(json); Connection.Send(data); + Log.ForContext().Debug("Difficulty updated to {0} for miner: {1:l}", Difficulty, Username); Log.ForContext().Verbose("Send:\n{0}", data.ToEncodedString().PrettifyJson()); } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index af19abb39..7183ddefd 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -57,7 +57,8 @@ public class VanillaMiner : IMiner public bool Authenticated { get; set; } public IPool Pool { get; private set; } - public Difficulty Difficulty { get; private set; } + + public float Difficulty { get; set; } /// /// Can we send new mining job's to miner? @@ -75,7 +76,7 @@ public VanillaMiner(int id, IMinerManager minerManager) { Id = id; // the id of the miner. _minerManager = minerManager; - Difficulty = new Difficulty(16); + Difficulty = 16; Subscribed = true; // vanilla miners are subscribed by default. Authenticated = false; // miner has to authenticate. diff --git a/src/CoiniumServ/Utils/Buffers/RingBuffer.cs b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs index 45b34d5c3..c31a18369 100644 --- a/src/CoiniumServ/Utils/Buffers/RingBuffer.cs +++ b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs @@ -29,7 +29,7 @@ public class RingBuffer:IRingBuffer { public int Size { get { return _isFull ? Capacity : _cursor; } } - public float Average { get { return _buffer.Sum() / (_isFull ? Capacity : _cursor); } } + public float Average { get { return (float)_buffer.Sum() / (float)(_isFull ? Capacity : _cursor); } } private readonly int[] _buffer; diff --git a/src/CoiniumServ/Utils/ConsoleWindow.cs b/src/CoiniumServ/Utils/ConsoleWindow.cs index 3c601bf5f..6093f198b 100644 --- a/src/CoiniumServ/Utils/ConsoleWindow.cs +++ b/src/CoiniumServ/Utils/ConsoleWindow.cs @@ -56,10 +56,9 @@ public static void PrintLicense() Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("CoiniumServ comes with ABSOLUTELY NO WARRANTY."); Console.WriteLine(); - Console.ForegroundColor = ConsoleColor.Cyan; + Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("You can contribute the development of the project by donating;"); Console.ForegroundColor = ConsoleColor.Yellow; - //Console.BackgroundColor=ConsoleColor.DarkGray; Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D."); Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa."); Console.WriteLine("DOGE: D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc."); diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index e17b915c1..462878654 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -172,7 +172,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage).Returns(_shareManager); // vardiff manager - _vardiffManagerFactory.Get(_shareManager); + var vardiffConfig = Substitute.For(); + _vardiffManagerFactory.Get(vardiffConfig, _shareManager); // initalize job manager. _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm).Returns(_jobManager); From 2bca6a17e5cb7486aaae0e87d03d9016026417a4 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 15:36:29 +0300 Subject: [PATCH 067/230] Updated readme - platform agnostic section. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d16c63ec..53ab7ea2f 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ CoiniumServ was created to be used for [Coinium.org](http://www.coinium.org) min ### Features ###### Platform Agnostic -Can run on any platforms that C# can live in; -* *nix (including Linux) over mono -* Windows over DotNet. +Can run on these platforms; +* Linux/Unix over mono. +* MacOS over mono. +* Windows over dotNet. ###### Multiplexed Structure * Multiple pools & ports. From 0b54ffe4cd3afbe7f478821ac4325c1b7b1966bd Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 15:38:10 +0300 Subject: [PATCH 068/230] Another tiny readme update. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 53ab7ea2f..4a51205f9 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ CoiniumServ was created to be used for [Coinium.org](http://www.coinium.org) min ###### Platform Agnostic Can run on these platforms; -* Linux/Unix over mono. -* MacOS over mono. -* Windows over dotNet. +* Linux/Unix over [mono](http://www.mono-project.com/). +* MacOS over [mono](http://www.mono-project.com/). +* Windows over [.Net](http://www.microsoft.com/net). ###### Multiplexed Structure * Multiple pools & ports. From ea70018b2c196abbb5510ec997dd771d7f9394fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 16:30:11 +0300 Subject: [PATCH 069/230] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4a51205f9..4fcec54a4 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) * [Twitter](http://twitter.com/coinium) +* [Support forums](http://forum.coinium.org/forum/19-support/) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) ### Contributing From 69ad08665105c63e9610a32d48812a23efb2e2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 16:31:26 +0300 Subject: [PATCH 070/230] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fcec54a4..9c8f73c41 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ You can send tips and furher support the project or get tips for contributing by ### License -Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org +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 From 87701a8845d02766ec1edfcd21fae56c8b531205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 16:36:52 +0300 Subject: [PATCH 071/230] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9c8f73c41..9f1f7d666 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) * [Twitter](http://twitter.com/coinium) * [Support forums](http://forum.coinium.org/forum/19-support/) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) +* [Bitcoin wiki](https://en.bitcoin.it/wiki/CoiniumServ) ### Contributing From 7dec7e6da7711c7ca6716a532730d4233d81b7d9 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 16 Jul 2014 20:31:06 +0300 Subject: [PATCH 072/230] Wallet-config, rewards-config support. Improved Pool:PrintPoolInfo() - it will able to now print pool info even if daemon is still downloading blocks. --- deps/jsonconfig | 2 +- src/CoiniumServ/CoiniumServ.csproj | 4 ++ .../Mining/Jobs/Manager/IJobManagerFactory.cs | 5 +- .../Mining/Jobs/Manager/JobManager.cs | 15 ++++- .../Mining/Jobs/Manager/JobManagerFactory.cs | 9 ++- .../Mining/Pools/Config/IPoolConfig.cs | 4 ++ .../Mining/Pools/Config/IRewardsConfig.cs | 32 +++++++++++ .../Mining/Pools/Config/IWalletConfig.cs | 30 ++++++++++ .../Mining/Pools/Config/PoolConfig.cs | 12 +++- .../Mining/Pools/Config/PoolConfigFactory.cs | 1 + .../Mining/Pools/Config/RewardsConfig.cs | 57 +++++++++++++++++++ .../Mining/Pools/Config/WalletConfig.cs | 35 ++++++++++++ src/CoiniumServ/Mining/Pools/Pool.cs | 30 +++++----- .../Mining/Pools/Statistics/Algorithms.cs | 2 - src/CoiniumServ/Mining/Shares/Share.cs | 1 + .../Mining/Vardiff/VardiffManager.cs | 13 ++--- src/CoiniumServ/Payments/IPaymentConfig.cs | 1 + .../Payments/IPaymentProcessorFactory.cs | 3 +- src/CoiniumServ/Payments/PaymentConfig.cs | 7 +-- src/CoiniumServ/Payments/PaymentProcessor.cs | 14 +++-- .../Payments/PaymentProcessorFactory.cs | 6 +- .../Transactions/GenerationTransaction.cs | 15 ++--- src/CoiniumServ/config/pools/sample.json | 18 +++--- src/Tests/Mining/Pools/PoolTests.cs | 9 ++- .../Server/Stratum/Notifications/JobTests.cs | 5 +- .../GenerationTransactionTests.cs | 5 +- 26 files changed, 265 insertions(+), 70 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs diff --git a/deps/jsonconfig b/deps/jsonconfig index 7e2133611..4bfac3474 160000 --- a/deps/jsonconfig +++ b/deps/jsonconfig @@ -1 +1 @@ -Subproject commit 7e21336116cb2404cd49fa2d9cab8a53d76b80a8 +Subproject commit 4bfac34740819e2dd6ef8655a59e43f37cd01b2c diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 7f86ac113..1c05132ac 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,6 +110,10 @@ + + + + diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs index 809566019..69baaff95 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs @@ -24,6 +24,7 @@ using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; namespace Coinium.Mining.Jobs.Manager @@ -38,7 +39,9 @@ public interface IJobManagerFactory /// /// The miner manager. /// + /// + /// /// - IJobManager Get(IDaemonClient daemonClient, IJobTracker jobtracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm); + IJobManager Get(IDaemonClient daemonClient, IJobTracker jobtracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig); } } diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index d639ddae0..f9224b4e0 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -27,6 +27,7 @@ using Coinium.Daemon.Exceptions; using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Server.Mining.Stratum.Notifications; using Coinium.Transactions; @@ -48,6 +49,10 @@ public class JobManager : IJobManager private readonly IJobCounter _jobCounter; + private readonly IWalletConfig _walletConfig; + + private readonly IRewardsConfig _rewardsConfig; + private IExtraNonce _extraNonce; public IExtraNonce ExtraNonce { get { return _extraNonce; } } @@ -56,13 +61,15 @@ public class JobManager : IJobManager private Timer _timer; private const int TimerExpiration = 10; - public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm) + public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig) { _daemonClient = daemonClient; _jobTracker = jobTracker; _shareManager = shareManager; _minerManager = minerManager; _hashAlgorithm = hashAlgorithm; + _walletConfig = walletConfig; + _rewardsConfig = rewardsConfig; _jobCounter = new JobCounter(); } @@ -116,9 +123,13 @@ private IJob GetNewJob() { try { + // TODO: fix the error for [Error] [JobManager] [n/a] New job creation failed: + // Coinium.Daemon.Exceptions.RpcException: Dogecoin is downloading blocks... + var blockTemplate = _daemonClient.GetBlockTemplate(); - var generationTransaction = new GenerationTransaction(ExtraNonce, _daemonClient, blockTemplate); + // TODO: convert generation transaction to ioc based. + var generationTransaction = new GenerationTransaction(ExtraNonce, _daemonClient, blockTemplate,_walletConfig, _rewardsConfig); generationTransaction.Create(); // create the job notification. diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs index 859a2dbed..bcf18a244 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs @@ -24,6 +24,7 @@ using Coinium.Daemon; using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; +using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Repository.Context; using Nancy.TinyIoc; @@ -54,8 +55,10 @@ public JobManagerFactory(IApplicationContext applicationContext) /// /// The miner manager. /// + /// + /// /// - public IJobManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm) + public IJobManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig) { var @params = new NamedParameterOverloads { @@ -63,7 +66,9 @@ public IJobManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IShar {"jobTracker", jobTracker}, {"shareManager", shareManager}, {"minerManager", minerManager}, - {"hashAlgorithm", hashAlgorithm} + {"hashAlgorithm", hashAlgorithm}, + {"walletConfig", walletConfig}, + {"rewardsConfig", rewardsConfig} }; return _applicationContext.Container.Resolve(@params); diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 832f4439c..683dae55c 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -36,6 +36,8 @@ public interface IPoolConfig:IConfig /// bool Enabled { get; } + IWalletConfig Wallet { get; } + ICoinConfig Coin { get; } IStratumServerConfig Stratum { get; } @@ -44,6 +46,8 @@ public interface IPoolConfig:IConfig IDaemonConfig Daemon { get; } + IRewardsConfig Rewards { get; } + IPaymentConfig Payments { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs new file mode 100644 index 000000000..e4e5ca1e5 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs @@ -0,0 +1,32 @@ +#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 Coinium.Utils.Configuration; + +namespace Coinium.Mining.Pools.Config +{ + public interface IRewardsConfig :IEnumerable>, IConfig + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs new file mode 100644 index 000000000..f42e52534 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs @@ -0,0 +1,30 @@ +#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 Coinium.Mining.Pools.Config +{ + public interface IWalletConfig + { + string Adress { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 527837173..6766a9957 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -37,6 +37,7 @@ public class PoolConfig : IPoolConfig public bool Valid { get; private set; } public bool Enabled { get; private set; } + public IWalletConfig Wallet { get; private set; } public ICoinConfig Coin { get; private set; } @@ -47,11 +48,10 @@ public class PoolConfig : IPoolConfig /// /// Gets the daemon configuration. /// - /// - /// The daemon configuration. - /// public IDaemonConfig Daemon { get; private set; } + public IRewardsConfig Rewards { get; private set; } + public IPaymentConfig Payments { get; private set; } /// @@ -69,6 +69,12 @@ public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) Enabled = config.enabled ? config.enabled : false; + if (Enabled == false) + return; + + Wallet = new WalletConfig(config.wallet); + Rewards = new RewardsConfig(config.rewards); + var coinName = Path.GetFileNameWithoutExtension(config.coin); Coin = coinConfigFactory.GetConfig(coinName); diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs index 77741c76f..c83fbfbe6 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs @@ -54,6 +54,7 @@ public IPoolConfig Get(dynamic readConfig) { "coinConfigFactory", _applicationContext.Container.Resolve() }, { "config", readConfig } }; + return _applicationContext.Container.Resolve(@params); } } diff --git a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs new file mode 100644 index 000000000..daeeb9d1c --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs @@ -0,0 +1,57 @@ +#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; +using System.Collections.Generic; +using JsonConfig; + +namespace Coinium.Mining.Pools.Config +{ + public class RewardsConfig:IRewardsConfig + { + public bool Valid { get; private set; } + private readonly Dictionary _rewards; + + public RewardsConfig(dynamic config) + { + _rewards = new Dictionary(); + + // weird stuff going below because of JsonConfig libraries handling of dictionaries. + foreach (ConfigObject kvp in config) + foreach (KeyValuePair pair in kvp) + _rewards.Add(pair.Key, float.Parse(pair.Value.ToString())); + + Valid = true; + } + + public IEnumerator> GetEnumerator() + { + return _rewards.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs new file mode 100644 index 000000000..201737487 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs @@ -0,0 +1,35 @@ +#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 Coinium.Mining.Pools.Config +{ + public class WalletConfig:IWalletConfig + { + public string Adress { get; private set; } + + public WalletConfig(dynamic config) + { + Adress = config.address; + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index d5a3325aa..18b96fed5 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -147,15 +147,13 @@ public Pool( public void Initialize(IPoolConfig config) { Config = config; + + // TODO: validate pool central wallet & rewards within the startup. - // init coin daemon. - InitDaemon(); - - // init managers. + InitDaemon(); InitManagers(); - - // init servers InitServers(); + PrintPoolInfo(); } private void InitDaemon() @@ -173,7 +171,7 @@ private void InitManagers() _storage = _storageFactory.Get(Storages.Redis, Config); - _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage); + _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage, Config.Wallet); _paymentProcessor.Initialize(Config.Payments); _minerManager = _minerManagerFactory.Get(_daemonClient); @@ -184,10 +182,9 @@ private void InitManagers() _vardiffManager = _varddManagerFactory.Get(Config.Stratum.Vardiff, _shareManager); - _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm); + _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm, Config.Wallet, Config.Rewards); _jobManager.Initialize(InstanceId); - var latestBlocks = _statisticsObjectFactory.GetLatestBlocks(_storage); var blockStats = _statisticsObjectFactory.GetBlockStats(latestBlocks, _storage); Statistics = _statisticsObjectFactory.GetPerPoolStats(Config, _daemonClient, _minerManager, _hashAlgorithm, blockStats, _storage); @@ -231,20 +228,21 @@ public void Start() { server.Key.Start(); } - - GetPoolInfo(); } - private void GetPoolInfo() + private void PrintPoolInfo() { var info = _daemonClient.GetInfo(); var miningInfo = _daemonClient.GetMiningInfo(); + // TODO: add downloading blocks information from getblocktemplate(). + // TODO: make this multi-line & readable. + // TODO: read services from config so that we can print pool info even before starting the servers. Log.ForContext().Information("Pool started for {0:l}\r\n" + "Coin symbol: {1:l} algorithm: {2:l}\r\n" + "Coin version: {3} protocol: {4} wallet: {5}\r\n" + "Daemon network: {6:l} peers: {7} blocks: {8} errors: {9:l}\r\n" + - "Network difficulty: {10:0.0000} block difficulty: {11:0.00}\r\n" + + "Network difficulty: {10:0.00000000} block difficulty: {11:0.00}\r\n" + "Network hashrate: {12:l}\r\n" + "{13:l}\r\n", Config.Coin.Name, @@ -256,15 +254,15 @@ private void GetPoolInfo() info.Testnet ? "testnet" : "mainnet", info.Connections, info.Blocks, string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors, - _jobTracker.Current.Difficulty, - _jobTracker.Current.Difficulty*_hashAlgorithm.Multiplier, + miningInfo.Difficulty, + miningInfo.Difficulty * _hashAlgorithm.Multiplier, miningInfo.NetworkHashps.GetReadableHashrate(), "Services: " + _servers.Select(pair => pair.Key) .Aggregate(string.Empty, (current, server) => current + string.Format("{0} @ {1}:{2}, ", server.Config.Name.ToLower(), server.BindIP, server.Port)) - ); + ); } public void Stop() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs index 9712a33ff..44fb12f8b 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs @@ -22,8 +22,6 @@ #endregion using System.Collections; using System.Collections.Generic; -using System.Dynamic; -using Coinium.Coin.Helpers; using Newtonsoft.Json; namespace Coinium.Mining.Pools.Statistics diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index ffbb69d04..a21c30122 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -119,6 +119,7 @@ public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, st // create the block headers HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, NTime, Nonce); + // TODO: add sha256 and others support! HeaderHash = Job.HashAlgorithm.Hash(HeaderBuffer); HeaderValue = new BigInteger(HeaderHash); diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index d077bb473..0f15aa6bc 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -32,10 +32,9 @@ public class VardiffManager:IVardiffManager { public IVardiffConfig Config { get; private set; } - private float _variance; - private int _bufferSize; - private float _tMin; - private float _tMax; + private readonly int _bufferSize; + private readonly float _tMin; + private readonly float _tMax; public VardiffManager(IVardiffConfig vardiffConfig, IShareManager shareManager) { @@ -46,10 +45,10 @@ public VardiffManager(IVardiffConfig vardiffConfig, IShareManager shareManager) shareManager.ShareSubmitted += OnShare; - _variance = vardiffConfig.TargetTime*((float)vardiffConfig.VariancePercent/100); + var variance = vardiffConfig.TargetTime*((float)vardiffConfig.VariancePercent/100); _bufferSize = vardiffConfig.RetargetTime/vardiffConfig.TargetTime*4; - _tMin = vardiffConfig.TargetTime - _variance; - _tMax = vardiffConfig.TargetTime + _variance; + _tMin = vardiffConfig.TargetTime - variance; + _tMax = vardiffConfig.TargetTime + variance; } private void OnShare(object sender, EventArgs e) diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs index 83463d625..f788a681f 100644 --- a/src/CoiniumServ/Payments/IPaymentConfig.cs +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Collections.Generic; using Coinium.Utils.Configuration; namespace Coinium.Payments diff --git a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs index 8fe75f3dd..7cbe311a6 100644 --- a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs @@ -21,12 +21,13 @@ // #endregion using Coinium.Daemon; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; namespace Coinium.Payments { public interface IPaymentProcessorFactory { - IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage); + IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig); } } diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs index 98f09de15..90aeaaa81 100644 --- a/src/CoiniumServ/Payments/PaymentConfig.cs +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -20,10 +20,9 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; +using JsonConfig; namespace Coinium.Payments { @@ -41,7 +40,7 @@ public PaymentConfig(dynamic config) Valid = false; return; } - + Enabled = config.enabled; Interval = config.interval; Minimum = config.minimum; diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 5565e537c..d77fa93da 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -27,6 +27,7 @@ using System.Threading; using Coinium.Daemon; using Coinium.Daemon.Exceptions; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Persistance.Blocks; using Serilog; @@ -49,13 +50,14 @@ public class PaymentProcessor : IPaymentProcessor private readonly object _paymentsLock = new object(); private readonly Stopwatch _stopWatch = new Stopwatch(); - private const string PoolAddress = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; + private readonly IWalletConfig _walletConfig; private string _poolAccount = string.Empty; - public PaymentProcessor(IDaemonClient daemonClient, IStorage storage) + public PaymentProcessor(IDaemonClient daemonClient, IStorage storage , IWalletConfig walletConfig) { _daemonClient = daemonClient; _storage = storage; + _walletConfig = walletConfig; } public void Initialize(IPaymentConfig config) @@ -268,7 +270,7 @@ private void CheckCandidates(IHashCandidate candidate) candidate.Amount = transaction.Details.Sum(output => (decimal)output.Amount); // get the output transaction that targets pools central wallet. - var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == PoolAddress); + var poolOutput = transaction.Details.FirstOrDefault(output => output.Address == _walletConfig.Adress); // make sure output for the pool central wallet exists if (poolOutput == null) @@ -319,19 +321,19 @@ private IList GetPaymentRounds(IEnumerable block private void GetPoolAccount() { - var result = _daemonClient.GetAccount(PoolAddress); + var result = _daemonClient.GetAccount(_walletConfig.Adress); _poolAccount = result; } private bool ValidatePoolAddress() { - var result = _daemonClient.ValidateAddress(PoolAddress); + var result = _daemonClient.ValidateAddress(_walletConfig.Adress); // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. if (result.IsValid && result.IsMine) return true; - Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", PoolAddress); + Log.ForContext().Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", _walletConfig.Adress); return false; } diff --git a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs index 00c9c0f15..7211de271 100644 --- a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs @@ -21,6 +21,7 @@ // #endregion using Coinium.Daemon; +using Coinium.Mining.Pools.Config; using Coinium.Persistance; using Coinium.Repository.Context; using Nancy.TinyIoc; @@ -43,12 +44,13 @@ public PaymentProcessorFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; } - public IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage) + public IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig) { var @params = new NamedParameterOverloads { {"daemonClient", daemonClient}, - {"storage", storage} + {"storage", storage}, + {"walletConfig", walletConfig} }; return _applicationContext.Container.Resolve(@params); diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index c570e588c..64ce53d7a 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -29,6 +29,7 @@ using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Jobs; +using Coinium.Mining.Pools.Config; using Coinium.Transactions.Script; using Coinium.Utils.Helpers.Time; using Gibbed.IO; @@ -112,13 +113,14 @@ public UInt32 InputsCount /// The extra nonce. /// The daemon client. /// The block template. + /// /// if set to true [support tx messages]. /// /// Reference implementations: /// https://github.com/zone117x/node-stratum-pool/blob/b24151729d77e0439e092fe3a1cdbba71ca5d12e/lib/transactions.js /// https://github.com/Crypto-Expert/stratum-mining/blob/master/lib/coinbasetx.py /// - public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, IBlockTemplate blockTemplate, bool supportTxMessages = false) + public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, IBlockTemplate blockTemplate, IWalletConfig walletConfig, IRewardsConfig rewardsConfig, bool supportTxMessages = false) { DaemonClient = daemonClient; BlockTemplate = blockTemplate; @@ -155,15 +157,8 @@ public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, double blockReward = BlockTemplate.Coinbasevalue; // the amount rewarded by the block. - const string poolWallet = "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY"; // pool's central wallet address. - - var rewardRecipients = new Dictionary // reward recipients addresses. - { - {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t", 1} // pool fee - }; - // generate output transactions for recipients (set in config). - foreach (var pair in rewardRecipients) + foreach (var pair in rewardsConfig) { var amount = blockReward * pair.Value / 100; // calculate the amount he recieves based on the percent of his shares. blockReward -= amount; @@ -172,7 +167,7 @@ public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, } // send the remaining coins to pool's central wallet. - Outputs.AddPool(poolWallet, blockReward); + Outputs.AddPool(walletConfig.Adress, blockReward); } public void Create() diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index e307a48ad..aea3bafae 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -3,8 +3,8 @@ "coin": "litecoin.json", - # pool configuration - "pool" : { + # central wallet configuration + "wallet" : { "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" }, @@ -16,14 +16,16 @@ "password": "password" }, + # rewards configuration + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + # payment processing configuration "payments": { "enabled": false, "interval": 60, - "minimum": 1, - "rewards": { - "myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1 - } + "minimum": 1 }, # stratum server configuration @@ -44,9 +46,9 @@ # vanilla server configuration "vanilla": { - "enabled": true, + "enabled": false, "bind": "localhost", - "port": 3334 + "port": 2223 }, # mpos compat mode configuration - not implemented yet! diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 462878654..bbabacbf3 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -159,8 +159,11 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // initialize the miner manager. _minerManagerFactory.Get(_daemonClient); - // payment processor - _paymentProcessorFactory.Get(_daemonClient, _storage); + var walletConfig = Substitute.For(); + var rewardsConfig = Substitute.For(); + + // payment processor + _paymentProcessorFactory.Get(_daemonClient, _storage, walletConfig); // initialize storage manager _storageFactory.Get(Storages.Redis, poolConfig); @@ -176,7 +179,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _vardiffManagerFactory.Get(vardiffConfig, _shareManager); // initalize job manager. - _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm).Returns(_jobManager); + _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig,rewardsConfig).Returns(_jobManager); _jobManager.Initialize(pool.InstanceId); // init daemon client diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index 83dad05db..33d66c911 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -26,6 +26,7 @@ using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Jobs; +using Coinium.Mining.Pools.Config; using Coinium.Server.Mining.Stratum.Notifications; using Coinium.Transactions; using Coinium.Transactions.Script; @@ -134,7 +135,9 @@ public JobTests() _jobCounter = Substitute.For(); // generation transaction. - _generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate); + var walletConfig = Substitute.For(); + var rewardsConfig = Substitute.For(); + _generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate, walletConfig, rewardsConfig); _generationTransaction.Inputs.First().SignatureScript = _signatureScript; _generationTransaction.Outputs = _outputs; _generationTransaction.Create(); diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index 4e4df87b3..d2443c4d4 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -25,6 +25,7 @@ using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Jobs; +using Coinium.Mining.Pools.Config; using Coinium.Transactions; using Coinium.Transactions.Script; using Coinium.Utils.Extensions; @@ -118,7 +119,9 @@ public GenerationTransactionTests() public void CreateGenerationTransactionTest() { // create the test object. - var generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate); + var walletConfig = Substitute.For(); + var rewardsConfig = Substitute.For(); + var generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate, walletConfig, rewardsConfig); // use the exactly same input script data within our sample data. generationTransaction.Inputs.First().SignatureScript = _signatureScript; From 6a563d53b4c64d721b7efe9af98b2f0e1c010254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 16 Jul 2014 22:14:54 +0300 Subject: [PATCH 073/230] Fixed tests. --- .../Transactions/GenerationTransaction.cs | 2 +- src/CoiniumServ/Transactions/IOutputs.cs | 2 +- src/CoiniumServ/Transactions/Outputs.cs | 2 +- src/Tests/Coin/Coinbase/SerializersTests.cs | 23 +++++++++++----- src/Tests/Mining/Pools/PoolTests.cs | 3 +++ src/Tests/Mining/Shares/ShareTests.cs | 21 ++++++++++----- .../Server/Stratum/Notifications/JobTests.cs | 22 ++++++++++------ .../GenerationTransactionTests.cs | 26 ++++++++++++------- src/Tests/Transactions/OutputsTests.cs | 2 +- 9 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 64ce53d7a..4c2770ffe 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -167,7 +167,7 @@ public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, } // send the remaining coins to pool's central wallet. - Outputs.AddPool(walletConfig.Adress, blockReward); + Outputs.AddPoolWallet(walletConfig.Adress, blockReward); } public void Create() diff --git a/src/CoiniumServ/Transactions/IOutputs.cs b/src/CoiniumServ/Transactions/IOutputs.cs index 8eaa7b4ae..b60755431 100644 --- a/src/CoiniumServ/Transactions/IOutputs.cs +++ b/src/CoiniumServ/Transactions/IOutputs.cs @@ -28,7 +28,7 @@ public interface IOutputs { List List { get; } - void AddPool(string address, double amount); + void AddPoolWallet(string address, double amount); void AddRecipient(string address, double amount); diff --git a/src/CoiniumServ/Transactions/Outputs.cs b/src/CoiniumServ/Transactions/Outputs.cs index 458d75642..5395d0d0d 100644 --- a/src/CoiniumServ/Transactions/Outputs.cs +++ b/src/CoiniumServ/Transactions/Outputs.cs @@ -44,7 +44,7 @@ public Outputs(IDaemonClient daemonClient) List = new List(); } - public void AddPool(string address, double amount) + public void AddPoolWallet(string address, double amount) { Add(address, amount, true); } diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index 2d80ee88a..af3f04ec9 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -21,12 +21,14 @@ // #endregion using System; +using System.Collections.Generic; using System.Linq; using Coinium.Coin.Coinbase; using Coinium.Crypto.Algorithms; using Coinium.Daemon; using Coinium.Daemon.Responses; using Coinium.Mining.Jobs; +using Coinium.Mining.Pools.Config; using Coinium.Server.Mining.Stratum.Notifications; using Coinium.Transactions; using Coinium.Transactions.Script; @@ -134,18 +136,25 @@ public SerializerTests() _outputs = Substitute.For(_daemonClient); double blockReward = 5000000000; // the amount rewarded by the block. - // sample recipient - const string recipient = "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji"; + // sample reward recipient + var rewardsConfig = Substitute.For(); var amount = blockReward * 0.01; blockReward -= amount; - _outputs.AddRecipient(recipient, amount); + var rewards = new Dictionary { { "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji", (float)amount } }; - // sample pool wallet - const string poolWallet = "mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"; - _outputs.AddPool(poolWallet, blockReward); + rewardsConfig.GetEnumerator().Returns(rewards.GetEnumerator()); + foreach (var pair in rewards) + { + _outputs.AddRecipient(pair.Key, pair.Value); + } + // sample pool wallet + var walletConfig = Substitute.For(); + walletConfig.Adress.Returns("mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"); + _outputs.AddPoolWallet(walletConfig.Adress, blockReward); + // generation transaction. - _generationTransaction = Substitute.For(_extraNonce, _daemonClient, _blockTemplate, false); + _generationTransaction = Substitute.For(_extraNonce, _daemonClient, _blockTemplate, walletConfig, rewardsConfig, false); _generationTransaction.Inputs.First().SignatureScript = _signatureScript; _generationTransaction.Outputs = _outputs; _generationTransaction.Create(); diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index bbabacbf3..8c86866c6 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -23,6 +23,7 @@ using System; using Coinium.Crypto.Algorithms; using Coinium.Daemon; +using Coinium.Daemon.Responses; using Coinium.Mining.Jobs.Manager; using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; @@ -184,6 +185,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // init daemon client _daemonClient.Initialize(poolConfig.Daemon); + _daemonClient.GetInfo().Returns(new Info()); + _daemonClient.GetMiningInfo().Returns(new MiningInfo()); // init server _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager).Returns(_miningServer); diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index 834126553..c7c283939 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Collections.Generic; using System.Linq; using Coinium.Coin.Config; using Coinium.Crypto.Algorithms; @@ -31,6 +32,7 @@ using Coinium.Mining.Jobs.Tracker; using Coinium.Mining.Miners; using Coinium.Mining.Pools; +using Coinium.Mining.Pools.Config; using Coinium.Mining.Shares; using Coinium.Server.Mining.Stratum; using Coinium.Server.Mining.Stratum.Notifications; @@ -122,18 +124,25 @@ public ShareTests() _outputs = Substitute.For(_daemonClient); double blockReward = 5000000000; // the amount rewarded by the block. - // sample recipient - const string recipient = "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji"; + // sample reward recipient + var rewardsConfig = Substitute.For(); var amount = blockReward * 0.01; blockReward -= amount; - _outputs.AddRecipient(recipient, amount); + var rewards = new Dictionary { { "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji", (float)amount } }; + + rewardsConfig.GetEnumerator().Returns(rewards.GetEnumerator()); + foreach (var pair in rewards) + { + _outputs.AddRecipient(pair.Key, pair.Value); + } // sample pool wallet - const string poolWallet = "mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"; - _outputs.AddPool(poolWallet, blockReward); + var walletConfig = Substitute.For(); + walletConfig.Adress.Returns("mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"); + _outputs.AddPoolWallet(walletConfig.Adress, blockReward); // generation transaction - _generationTransaction = Substitute.For(_extraNonce, _daemonClient, _blockTemplate, false); + _generationTransaction = Substitute.For(_extraNonce, _daemonClient, _blockTemplate, walletConfig,rewardsConfig, false); _generationTransaction.Inputs.First().SignatureScript = _signatureScript; _generationTransaction.Outputs = _outputs; _generationTransaction.Create(); diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index 33d66c911..d7bb47e56 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Collections.Generic; using System.Linq; using Coinium.Crypto.Algorithms; using Coinium.Daemon; @@ -118,25 +119,30 @@ public JobTests() "/nodeStratum/"); // outputs - _outputs = new Outputs(_daemonClient); + _outputs = Substitute.For(_daemonClient); double blockReward = 5000000000; // the amount rewarded by the block. - // sample recipient - const string recipient = "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji"; + // sample reward recipient + var rewardsConfig = Substitute.For(); var amount = blockReward * 0.01; blockReward -= amount; - _outputs.AddRecipient(recipient, amount); + var rewards = new Dictionary { {"mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji", (float) amount} }; + + rewardsConfig.GetEnumerator().Returns(rewards.GetEnumerator()); + foreach (var pair in rewards) + { + _outputs.AddRecipient(pair.Key, pair.Value); + } // sample pool wallet - const string poolWallet = "mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"; - _outputs.AddPool(poolWallet, blockReward); + var walletConfig = Substitute.For(); + walletConfig.Adress.Returns("mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"); + _outputs.AddPoolWallet(walletConfig.Adress, blockReward); // job counter _jobCounter = Substitute.For(); // generation transaction. - var walletConfig = Substitute.For(); - var rewardsConfig = Substitute.For(); _generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate, walletConfig, rewardsConfig); _generationTransaction.Inputs.First().SignatureScript = _signatureScript; _generationTransaction.Outputs = _outputs; diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index d2443c4d4..ce3bfec0b 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -21,6 +21,7 @@ // #endregion using System; +using System.Collections.Generic; using System.Linq; using Coinium.Daemon; using Coinium.Daemon.Responses; @@ -77,6 +78,8 @@ public class GenerationTransactionTests private readonly IExtraNonce _extraNonce; private readonly ISignatureScript _signatureScript; private readonly IOutputs _outputs; + private readonly IWalletConfig _walletConfig; + private readonly IRewardsConfig _rewardsConfig; public GenerationTransactionTests() { @@ -101,27 +104,32 @@ public GenerationTransactionTests() "/nodeStratum/"); // use the same output data within our sample data. - _outputs = new Outputs(_daemonClient); + _outputs = Substitute.For(_daemonClient); double blockReward = 5000000000; // the amount rewarded by the block. - // sample recipient - const string recipient = "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji"; + // sample reward recipient + _rewardsConfig = Substitute.For(); var amount = blockReward * 0.01; blockReward -= amount; - _outputs.AddRecipient(recipient, amount); + var rewards = new Dictionary { { "mrwhWEDnU6dUtHZJ2oBswTpEdbBHgYiMji", (float)amount } }; + + _rewardsConfig.GetEnumerator().Returns(rewards.GetEnumerator()); + foreach (var pair in rewards) + { + _outputs.AddRecipient(pair.Key, pair.Value); + } // sample pool wallet - const string poolWallet = "mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"; - _outputs.AddPool(poolWallet, blockReward); + _walletConfig = Substitute.For(); + _walletConfig.Adress.Returns("mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"); + _outputs.AddPoolWallet(_walletConfig.Adress, blockReward); } [Fact] public void CreateGenerationTransactionTest() { // create the test object. - var walletConfig = Substitute.For(); - var rewardsConfig = Substitute.For(); - var generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate, walletConfig, rewardsConfig); + var generationTransaction = new GenerationTransaction(_extraNonce, _daemonClient, _blockTemplate, _walletConfig, _rewardsConfig); // use the exactly same input script data within our sample data. generationTransaction.Inputs.First().SignatureScript = _signatureScript; diff --git a/src/Tests/Transactions/OutputsTests.cs b/src/Tests/Transactions/OutputsTests.cs index f29b2fd39..b9fd29a9e 100644 --- a/src/Tests/Transactions/OutputsTests.cs +++ b/src/Tests/Transactions/OutputsTests.cs @@ -72,7 +72,7 @@ public void TestOutputs() // sample pool wallet const string poolWallet = "mk8JqN1kNWju8o3DXEijiJyn7iqkwktAWq"; - outputs.AddPool(poolWallet, blockReward); + outputs.AddPoolWallet(poolWallet, blockReward); // test the recipient rewards outputs.List.Last().Value.Should().Equal((UInt64)0x0000000002faf080); // packInt64LE: 80f0fa0200000000 From 6f1a3ba9d2914db9387ebd7dfabd1496bf1a854c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 12:38:10 +0300 Subject: [PATCH 074/230] Fixed namespaces. --- src/CoiniumServ/Coin/Address/Base58.cs | 7 ++-- .../Exceptions/AddressFormatException.cs | 3 +- .../InvalidWalletAddressException.cs | 3 +- src/CoiniumServ/Coin/Coinbase/Serializers.cs | 9 +++-- src/CoiniumServ/Coin/Coinbase/Utils.cs | 11 +++--- src/CoiniumServ/Coin/Config/CoinConfig.cs | 2 +- .../Coin/Config/CoinConfigFactory.cs | 7 ++-- src/CoiniumServ/Coin/Config/ICoinConfig.cs | 5 ++- .../Coin/Config/ICoinConfigFactory.cs | 2 +- src/CoiniumServ/Coin/Helpers/Amount.cs | 2 +- src/CoiniumServ/Coin/Helpers/Hashrate.cs | 3 +- src/CoiniumServ/CoiniumServ.csproj | 4 +- .../Crypto/Algorithms/Algorithms.cs | 2 +- .../Crypto/Algorithms/HashAlgorithmFactory.cs | 6 +-- .../Crypto/Algorithms/IHashAlgorithm.cs | 5 ++- .../Algorithms/IHashAlgorithmFactory.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/Scrypt.cs | 5 ++- src/CoiniumServ/Crypto/Hash.cs | 5 ++- src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs | 3 +- src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs | 3 +- src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs | 5 ++- src/CoiniumServ/Crypto/Merkle/MerkleTree.cs | 7 ++-- src/CoiniumServ/Crypto/Utils.cs | 3 +- src/CoiniumServ/Daemon/Config/DaemonConfig.cs | 2 +- .../Daemon/Config/IDaemonConfig.cs | 5 ++- src/CoiniumServ/Daemon/DaemonBase.cs | 9 +++-- src/CoiniumServ/Daemon/DaemonClient.cs | 8 ++-- src/CoiniumServ/Daemon/DaemonErrorResponse.cs | 3 +- src/CoiniumServ/Daemon/DaemonRequest.cs | 3 +- src/CoiniumServ/Daemon/DaemonResponse.cs | 3 +- .../Daemon/Exceptions/RpcException.cs | 3 +- src/CoiniumServ/Daemon/IDaemonBase.cs | 5 ++- src/CoiniumServ/Daemon/IDaemonClient.cs | 7 ++-- .../Daemon/Requests/CreateRawTransaction.cs | 3 +- .../Requests/CreateRawTransactionInput.cs | 3 +- .../Daemon/Requests/SignRawTransaction.cs | 3 +- .../Requests/SignRawTransactionInput.cs | 3 +- .../Daemon/Responses/AddedNodeInfo.cs | 3 +- src/CoiniumServ/Daemon/Responses/Block.cs | 3 +- .../Daemon/Responses/BlockTemplate.cs | 3 +- .../Responses/BlockTemplateTransaction.cs | 2 +- .../Daemon/Responses/DecodedRawTransaction.cs | 3 +- .../Daemon/Responses/IBlockTemplate.cs | 3 +- src/CoiniumServ/Daemon/Responses/Info.cs | 2 +- .../ListReceivedByAccountTransaction.cs | 2 +- .../ListReceivedByAddressTransaction.cs | 2 +- .../Daemon/Responses/ListTransaction.cs | 2 +- .../Daemon/Responses/MiningInfo.cs | 3 +- .../Daemon/Responses/MultisigAddress.cs | 2 +- .../Daemon/Responses/NodeAddress.cs | 2 +- src/CoiniumServ/Daemon/Responses/PeerInfo.cs | 2 +- .../Daemon/Responses/SignedRawTransaction.cs | 2 +- .../Daemon/Responses/Transaction.cs | 4 +- .../Daemon/Responses/TransactionDetail.cs | 2 +- .../Daemon/Responses/TransactionSinceBlock.cs | 2 +- .../Responses/TransactionsSinceBlock.cs | 3 +- .../Daemon/Responses/TxOutSetInfo.cs | 2 +- .../Daemon/Responses/UnspentTransaction.cs | 2 +- .../Daemon/Responses/ValidateAddress.cs | 3 +- src/CoiniumServ/Daemon/Responses/Work.cs | 2 +- src/CoiniumServ/Mining/Jobs/ExtraNonce.cs | 5 ++- src/CoiniumServ/Mining/Jobs/IExtraNonce.cs | 3 +- src/CoiniumServ/Mining/Jobs/IJobCounter.cs | 6 +-- src/CoiniumServ/Mining/Jobs/JobCounter.cs | 3 +- .../Mining/Jobs/Manager/IJobManager.cs | 3 +- .../Mining/Jobs/Manager/IJobManagerFactory.cs | 15 ++++---- .../Mining/Jobs/Manager/JobManager.cs | 21 +++++----- .../Mining/Jobs/Manager/JobManagerFactory.cs | 17 +++++---- .../Mining/Jobs/Tracker/IJobTracker.cs | 5 ++- .../Mining/Jobs/Tracker/IJobTrackerFactory.cs | 6 +-- .../Mining/Jobs/Tracker/JobTracker.cs | 5 ++- .../Mining/Jobs/Tracker/JobTrackerFactory.cs | 5 ++- src/CoiniumServ/Mining/Miners/IMiner.cs | 7 ++-- .../Mining/Miners/IMinerManager.cs | 7 ++-- .../Mining/Miners/IMinerManagerFactory.cs | 5 ++- .../Mining/Miners/MinerEventArgs.cs | 3 +- src/CoiniumServ/Mining/Miners/MinerManager.cs | 9 +++-- .../Mining/Miners/MinerManagerFactory.cs | 8 ++-- .../Mining/Pools/Config/IPoolConfig.cs | 17 +++++---- .../Mining/Pools/Config/IPoolConfigFactory.cs | 2 +- .../Mining/Pools/Config/IRewardsConfig.cs | 4 +- .../Mining/Pools/Config/IWalletConfig.cs | 2 +- .../Mining/Pools/Config/PoolConfig.cs | 13 ++++--- .../Mining/Pools/Config/PoolConfigFactory.cs | 7 ++-- .../Mining/Pools/Config/RewardsConfig.cs | 2 +- .../Mining/Pools/Config/WalletConfig.cs | 2 +- src/CoiniumServ/Mining/Pools/IPool.cs | 7 ++-- src/CoiniumServ/Mining/Pools/IPoolFactory.cs | 5 ++- src/CoiniumServ/Mining/Pools/IPoolManager.cs | 7 ++-- .../Mining/Pools/IPoolManagerFactory.cs | 2 +- src/CoiniumServ/Mining/Pools/Pool.cs | 35 ++++++++--------- src/CoiniumServ/Mining/Pools/PoolFactory.cs | 7 ++-- src/CoiniumServ/Mining/Pools/PoolManager.cs | 11 +++--- .../Mining/Pools/PoolManagerFactory.cs | 5 ++- .../Mining/Pools/Statistics/Algorithms.cs | 3 +- .../Mining/Pools/Statistics/Blocks.cs | 4 +- .../Mining/Pools/Statistics/Global.cs | 3 +- .../Mining/Pools/Statistics/IAlgorithms.cs | 3 +- .../Mining/Pools/Statistics/IBlocks.cs | 2 +- .../Mining/Pools/Statistics/IGlobal.cs | 3 +- .../Mining/Pools/Statistics/IJsonResponse.cs | 2 +- .../Mining/Pools/Statistics/ILatestBlocks.cs | 4 +- .../Mining/Pools/Statistics/IPerAlgorithm.cs | 3 +- .../Mining/Pools/Statistics/IPerPool.cs | 3 +- .../Mining/Pools/Statistics/IPools.cs | 3 +- .../Mining/Pools/Statistics/IStatistics.cs | 2 +- .../Statistics/IStatisticsObjectFactory.cs | 13 ++++--- .../Pools/Statistics/IStatisticsProvider.cs | 2 +- .../Mining/Pools/Statistics/LatestBlocks.cs | 6 +-- .../Mining/Pools/Statistics/PerAlgorithm.cs | 2 +- .../Mining/Pools/Statistics/PerPool.cs | 15 ++++---- .../Mining/Pools/Statistics/Pools.cs | 3 +- .../Mining/Pools/Statistics/Statistics.cs | 3 +- .../Statistics/StatisticsObjectFactory.cs | 15 ++++---- src/CoiniumServ/Mining/Shares/IShare.cs | 13 ++++--- .../Mining/Shares/IShareManager.cs | 7 ++-- .../Mining/Shares/IShareManagerFactory.cs | 9 +++-- src/CoiniumServ/Mining/Shares/Share.cs | 19 +++++----- src/CoiniumServ/Mining/Shares/ShareError.cs | 2 +- .../Mining/Shares/ShareEventArgs.cs | 4 +- src/CoiniumServ/Mining/Shares/ShareManager.cs | 17 +++++---- .../Mining/Shares/ShareManagerFactory.cs | 11 +++--- .../Mining/Vardiff/IVardiffConfig.cs | 2 +- .../Mining/Vardiff/IVardiffManager.cs | 2 +- .../Mining/Vardiff/IVardiffManagerFactory.cs | 4 +- .../Mining/Vardiff/IVardiffMiner.cs | 4 +- .../Mining/Vardiff/VardiffConfig.cs | 2 +- .../Mining/Vardiff/VardiffManager.cs | 8 ++-- .../Mining/Vardiff/VardiffManagerFactory.cs | 6 +-- .../Net/Server/Http/Basic/HttpServer.cs | 3 +- .../Net/Server/Http/Web/ErrorConfiguration.cs | 3 +- .../Net/Server/Http/Web/HttpServer.cs | 5 ++- .../Net/Server/Http/Web/NancyBootstrapper.cs | 5 ++- .../Net/Server/Http/Web/RootPathProvider.cs | 5 ++- src/CoiniumServ/Net/Server/IServer.cs | 2 +- .../Net/Server/Sockets/Connection.cs | 3 +- .../Server/Sockets/ConnectionDataEventArgs.cs | 3 +- .../Net/Server/Sockets/ConnectionEventArgs.cs | 3 +- src/CoiniumServ/Net/Server/Sockets/IClient.cs | 2 +- .../Net/Server/Sockets/IConnection.cs | 3 +- .../Net/Server/Sockets/SocketServer.cs | 5 ++- src/CoiniumServ/Payments/IPaymentConfig.cs | 6 +-- src/CoiniumServ/Payments/IPaymentProcessor.cs | 2 +- .../Payments/IPaymentProcessorFactory.cs | 9 +++-- src/CoiniumServ/Payments/IPaymentRound.cs | 5 ++- src/CoiniumServ/Payments/IWorkerBalance.cs | 2 +- src/CoiniumServ/Payments/PaymentConfig.cs | 5 +-- src/CoiniumServ/Payments/PaymentProcessor.cs | 13 ++++--- .../Payments/PaymentProcessorFactory.cs | 11 +++--- src/CoiniumServ/Payments/PaymentRound.cs | 5 ++- src/CoiniumServ/Payments/WorkerBalance.cs | 3 +- .../Persistance/Blocks/BlockStatus.cs | 2 +- .../Persistance/Blocks/ConfirmedBlock.cs | 2 +- .../Persistance/Blocks/HashCandidate.cs | 2 +- .../Persistance/Blocks/IConfirmedBlock.cs | 7 +--- .../Persistance/Blocks/IFinalizedBlock.cs | 2 +- .../Persistance/Blocks/IHashCandidate.cs | 2 +- .../Persistance/Blocks/IKickedBlock.cs | 7 +--- .../Persistance/Blocks/IOrphanedBlock.cs | 7 +--- .../Persistance/Blocks/IPendingBlock.cs | 3 +- .../Persistance/Blocks/IPersistedBlock.cs | 3 +- .../Persistance/Blocks/KickedBlock.cs | 2 +- .../Persistance/Blocks/OrphanedBlock.cs | 2 +- .../Persistance/Blocks/PendingBlock.cs | 4 +- src/CoiniumServ/Persistance/IStorage.cs | 9 +++-- .../Persistance/IStorageFactory.cs | 5 ++- src/CoiniumServ/Persistance/Redis/IRedis.cs | 3 +- .../Persistance/Redis/IRedisConfig.cs | 3 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 18 ++++----- .../Persistance/Redis/RedisConfig.cs | 3 +- src/CoiniumServ/Persistance/StorageFactory.cs | 7 ++-- src/CoiniumServ/Persistance/Storages.cs | 2 +- src/CoiniumServ/Program.cs | 20 +++++----- src/CoiniumServ/Properties/AssemblyInfo.cs | 2 +- src/CoiniumServ/Repository/Bootstrapper.cs | 5 ++- .../Repository/Context/ApplicationContext.cs | 3 +- .../Repository/Context/IApplicationContext.cs | 3 +- .../Repository/Registries/ClassRegistry.cs | 23 +++++------ .../Repository/Registries/FactoryRegistry.cs | 35 ++++++++--------- .../Repository/Registries/IRegistry.cs | 2 +- .../Repository/Registries/ManagerRegistry.cs | 15 ++++---- .../Repository/Registries/Registry.cs | 7 ++-- .../Repository/Registries/ServerRegistry.cs | 15 ++++---- .../Repository/Registries/ServiceRegistry.cs | 11 +++--- src/CoiniumServ/Server/Commands/Server.cs | 5 ++- src/CoiniumServ/Server/Commands/Stats.cs | 5 ++- src/CoiniumServ/Server/Commands/Uptime.cs | 5 ++- src/CoiniumServ/Server/Commands/Version.cs | 5 ++- src/CoiniumServ/Server/IServerFactory.cs | 13 ++++--- .../Server/Mining/IMiningServer.cs | 5 ++- .../Server/Mining/IMiningServerConfig.cs | 5 ++- .../Server/Mining/Service/IRpcService.cs | 2 +- .../Server/Mining/Service/IServiceFactory.cs | 6 +-- .../Server/Mining/Service/ServiceFactory.cs | 8 ++-- .../Server/Mining/Service/Services.cs | 2 +- .../Stratum/Config/IStratumServerConfig.cs | 5 ++- .../Stratum/Config/StratumServerConfig.cs | 7 ++-- .../Stratum/Errors/AuthenticationError.cs | 3 +- .../Stratum/Errors/DuplicateShareError.cs | 3 +- .../Mining/Stratum/Errors/IStratumError.cs | 2 +- .../Mining/Stratum/Errors/JobNotFoundError.cs | 3 +- .../Stratum/Errors/LowDifficultyShare.cs | 3 +- .../Stratum/Errors/NotSubscriberError.cs | 3 +- .../Mining/Stratum/Errors/OtherError.cs | 3 +- .../Server/Mining/Stratum/IStratumMiner.cs | 7 ++-- .../Stratum/Notifications/Difficulty.cs | 2 +- .../Mining/Stratum/Notifications/IJob.cs | 13 ++++--- .../Mining/Stratum/Notifications/Job.cs | 19 +++++----- .../Stratum/Responses/SubscribeResponse.cs | 3 +- .../Stratum/Service/SocketServiceContext.cs | 4 +- .../Stratum/Service/SocketServiceRequest.cs | 2 +- .../Mining/Stratum/Service/StratumService.cs | 10 ++--- .../Server/Mining/Stratum/StratumMiner.cs | 19 +++++----- .../Server/Mining/Stratum/StratumServer.cs | 11 +++--- .../Vanilla/Config/IVanillaServerConfig.cs | 2 +- .../Vanilla/Config/VanillaServerConfig.cs | 5 ++- .../Vanilla/Service/HttpServiceContext.cs | 4 +- .../Vanilla/Service/HttpServiceRequest.cs | 2 +- .../Mining/Vanilla/Service/VanillaService.cs | 10 ++--- .../Server/Mining/Vanilla/VanillaMiner.cs | 13 ++++--- .../Server/Mining/Vanilla/VanillaServer.cs | 11 +++--- src/CoiniumServ/Server/ServerFactory.cs | 17 ++++----- src/CoiniumServ/Server/Servers.cs | 2 +- src/CoiniumServ/Server/Web/IWebServer.cs | 6 +-- .../Server/Web/IWebServerConfig.cs | 3 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 9 ++--- src/CoiniumServ/Server/Web/Modules/Index.cs | 7 ++-- .../Server/Web/Modules/Models/Error.cs | 2 +- .../Server/Web/Modules/Models/JsonError.cs | 2 +- src/CoiniumServ/Server/Web/Modules/Pool.cs | 7 ++-- src/CoiniumServ/Server/Web/WebServer.cs | 11 +++--- src/CoiniumServ/Server/Web/WebServerConfig.cs | 2 +- .../Transactions/GenerationTransaction.cs | 19 +++++----- .../Transactions/IGenerationTransaction.cs | 3 +- src/CoiniumServ/Transactions/IOutputs.cs | 3 +- src/CoiniumServ/Transactions/OutPoint.cs | 5 ++- src/CoiniumServ/Transactions/Outputs.cs | 9 +++-- .../Transactions/Script/ISignatureScript.cs | 2 +- .../Transactions/Script/SignatureScript.cs | 9 +++-- src/CoiniumServ/Transactions/TxIn.cs | 5 ++- src/CoiniumServ/Transactions/TxOut.cs | 3 +- .../Transactions/Utils/TransactionUtils.cs | 9 +++-- src/CoiniumServ/Utils/Buffers/IRingBuffer.cs | 2 +- src/CoiniumServ/Utils/Buffers/RingBuffer.cs | 2 +- .../Utils/Commands/CommandAttributes.cs | 3 +- .../Utils/Commands/CommandGroup.cs | 3 +- .../Utils/Commands/CommandManager.cs | 3 +- .../Configuration/GlobalConfigFactory.cs | 9 +++-- .../Utils/Configuration/IConfig.cs | 2 +- .../Configuration/IGlobalConfigFactory.cs | 7 ++-- .../Utils/Configuration/JsonConfigReader.cs | 3 +- src/CoiniumServ/Utils/ConsoleWindow.cs | 2 +- .../Utils/Extensions/ArrayExtensions.cs | 3 +- .../Utils/Extensions/EnumerableExtensions.cs | 3 +- .../Utils/Extensions/JsonExtensions.cs | 3 +- .../Utils/Extensions/StringExtensions.cs | 3 +- .../Utils/Helpers/Arrays/ArrayHelpers.cs | 3 +- .../Utils/Helpers/IO/FileHelpers.cs | 3 +- src/CoiniumServ/Utils/Helpers/Misc/Range.cs | 3 +- .../Utils/Helpers/Time/TimeHelpers.cs | 3 +- .../Utils/Helpers/Validation/Enforce.cs | 3 +- src/CoiniumServ/Utils/Logging.cs | 2 +- src/CoiniumServ/Utils/Numerics/BigInteger.cs | 3 +- src/CoiniumServ/Utils/Numerics/BigRational.cs | 3 +- src/CoiniumServ/Utils/Platform/Framework.cs | 2 +- .../Utils/Platform/PlatformManager.cs | 3 +- src/CoiniumServ/Utils/Versions/VersionInfo.cs | 2 +- src/CoiniumServ/web/default/index.cshtml | 4 +- src/CoiniumServ/web/default/pool.cshtml | 8 ++-- src/Tests/Coin/AmountTests.cs | 5 ++- src/Tests/Coin/Base58Test.cs | 7 ++-- src/Tests/Coin/Coinbase/SerializersTests.cs | 27 ++++++------- src/Tests/Coin/Coinbase/UtilsTests.cs | 5 +-- src/Tests/Crypto/Merkle/MerkleRootTests.cs | 7 ++-- src/Tests/Crypto/Merkle/MerkleTreeTests.cs | 13 ++++--- src/Tests/Daemon/BlockTemplateTests.cs | 7 ++-- src/Tests/Mining/Pools/PoolTests.cs | 38 ++++++++++--------- src/Tests/Mining/Shares/ShareTests.cs | 34 ++++++++--------- .../Server/Stratum/Notifications/JobTests.cs | 23 +++++------ src/Tests/Tests.csproj | 2 +- .../GenerationTransactionTests.cs | 17 +++++---- src/Tests/Transactions/OutputsTests.cs | 11 +++--- .../Script/SignatureScriptTests.cs | 13 ++++--- .../Utils/TransactionUtilsTests.cs | 7 ++-- .../Utils/Extensions/ArrayExtensionsTests.cs | 5 ++- .../Utils/Extensions/StringExtensionsTests.cs | 5 ++- 286 files changed, 924 insertions(+), 781 deletions(-) diff --git a/src/CoiniumServ/Coin/Address/Base58.cs b/src/CoiniumServ/Coin/Address/Base58.cs index 3d10d591c..e4f6a9cc0 100644 --- a/src/CoiniumServ/Coin/Address/Base58.cs +++ b/src/CoiniumServ/Coin/Address/Base58.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Linq; using System.Text; -using Coinium.Coin.Address.Exceptions; -using Coinium.Crypto; +using CoiniumServ.Coin.Address.Exceptions; +using CoiniumServ.Crypto; using Org.BouncyCastle.Math; -namespace Coinium.Coin.Address +namespace CoiniumServ.Coin.Address { /// diff --git a/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs b/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs index 5a48cd658..2ba7c1e5f 100644 --- a/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs +++ b/src/CoiniumServ/Coin/Address/Exceptions/AddressFormatException.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Coin.Address.Exceptions +namespace CoiniumServ.Coin.Address.Exceptions { /// /// Original implementation: https://github.com/CoiniumServ/BitcoinSharp/blob/55ca27107d200ede9896c1064de76b04d4daf9ef/src/Core/AddressFormatException.cs diff --git a/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs b/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs index bd6b6d170..9086fce28 100644 --- a/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs +++ b/src/CoiniumServ/Coin/Address/Exceptions/InvalidWalletAddressException.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Coin.Address.Exceptions +namespace CoiniumServ.Coin.Address.Exceptions { public class InvalidWalletAddressException : Exception { diff --git a/src/CoiniumServ/Coin/Coinbase/Serializers.cs b/src/CoiniumServ/Coin/Coinbase/Serializers.cs index bd6cd69e1..103564914 100644 --- a/src/CoiniumServ/Coin/Coinbase/Serializers.cs +++ b/src/CoiniumServ/Coin/Coinbase/Serializers.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; using System.Text; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Utils.Extensions; -using Coinium.Utils.Helpers.Arrays; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Helpers.Arrays; using Gibbed.IO; -namespace Coinium.Coin.Coinbase +namespace CoiniumServ.Coin.Coinbase { public static class Serializers { diff --git a/src/CoiniumServ/Coin/Coinbase/Utils.cs b/src/CoiniumServ/Coin/Coinbase/Utils.cs index bf30d16e8..608f1b1f5 100644 --- a/src/CoiniumServ/Coin/Coinbase/Utils.cs +++ b/src/CoiniumServ/Coin/Coinbase/Utils.cs @@ -20,17 +20,18 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; using System.Linq; -using Coinium.Coin.Address; -using Coinium.Crypto; -using Coinium.Utils.Extensions; -using Coinium.Utils.Numerics; +using CoiniumServ.Coin.Address; +using CoiniumServ.Crypto; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Numerics; using Gibbed.IO; using Serilog; -namespace Coinium.Coin.Coinbase +namespace CoiniumServ.Coin.Coinbase { /// /// Provides helper functions for "serialized CSscript formatting" as defined here: https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki#specification diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index 88218ab9c..32d8f1b82 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Coin.Config +namespace CoiniumServ.Coin.Config { public class CoinConfig : ICoinConfig { diff --git a/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs b/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs index c0cfe6f4c..f56e83dbb 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -using Coinium.Utils.Configuration; -namespace Coinium.Coin.Config +using CoiniumServ.Repository.Context; +using CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Coin.Config { public class CoinConfigFactory : ICoinConfigFactory { diff --git a/src/CoiniumServ/Coin/Config/ICoinConfig.cs b/src/CoiniumServ/Coin/Config/ICoinConfig.cs index 3915e6320..20bd25704 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfig.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Utils.Configuration; -namespace Coinium.Coin.Config +using CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Coin.Config { public interface ICoinConfig:IConfig { diff --git a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs b/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs index bd7ad24ec..f31052ffc 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Coin.Config +namespace CoiniumServ.Coin.Config { public interface ICoinConfigFactory { diff --git a/src/CoiniumServ/Coin/Helpers/Amount.cs b/src/CoiniumServ/Coin/Helpers/Amount.cs index 4b2e4d2b7..e471ae832 100644 --- a/src/CoiniumServ/Coin/Helpers/Amount.cs +++ b/src/CoiniumServ/Coin/Helpers/Amount.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Coin.Helpers +namespace CoiniumServ.Coin.Helpers { /// /// Amount helper class. diff --git a/src/CoiniumServ/Coin/Helpers/Hashrate.cs b/src/CoiniumServ/Coin/Helpers/Hashrate.cs index 1c65a5d01..bfaa9d422 100644 --- a/src/CoiniumServ/Coin/Helpers/Hashrate.cs +++ b/src/CoiniumServ/Coin/Helpers/Hashrate.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Coin.Helpers +namespace CoiniumServ.Coin.Helpers { public static class Hashrate { diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 1c05132ac..977fb864e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -7,7 +7,7 @@ {5FCA1E48-0751-4625-9532-CB804DF55DB5} Exe Properties - Coinium + CoiniumServ CoiniumServ v4.5 512 @@ -40,7 +40,7 @@ false - Coinium.Program + CoiniumServ.Program Coinium.ico diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs index f35030112..ca197c708 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Crypto.Algorithms +namespace CoiniumServ.Crypto.Algorithms { public static class Algorithms { diff --git a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs index 6425d9feb..d943e6de1 100644 --- a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs @@ -20,10 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -using Serilog; -namespace Coinium.Crypto.Algorithms +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Crypto.Algorithms { public class HashAlgorithmFactory : IHashAlgorithmFactory { diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs index 0826544cb..0a3885c9c 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Numerics; +using CoiniumServ.Utils.Numerics; -namespace Coinium.Crypto.Algorithms +namespace CoiniumServ.Crypto.Algorithms { public interface IHashAlgorithm { diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs index c66bf0f7e..e33b696de 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Crypto.Algorithms +namespace CoiniumServ.Crypto.Algorithms { public interface IHashAlgorithmFactory { diff --git a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs index 28e063a15..255bf412d 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Globalization; -using Coinium.Utils.Numerics; +using CoiniumServ.Utils.Numerics; using CryptSharp.Utility; -namespace Coinium.Crypto.Algorithms +namespace CoiniumServ.Crypto.Algorithms { public class Scrypt : IHashAlgorithm { diff --git a/src/CoiniumServ/Crypto/Hash.cs b/src/CoiniumServ/Crypto/Hash.cs index 8fd13e656..d036c8bd8 100644 --- a/src/CoiniumServ/Crypto/Hash.cs +++ b/src/CoiniumServ/Crypto/Hash.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Diagnostics; using System.Linq; -using Coinium.Utils.Extensions; +using CoiniumServ.Utils.Extensions; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities.Encoders; // originally from: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Sha256Hash.cs -namespace Coinium.Crypto +namespace CoiniumServ.Crypto { /// /// A Hash just wraps a byte[] so that equals and hashcode work correctly, allowing it to be used as keys in a diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs index 2fa75a1e9..9429bfab6 100644 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs +++ b/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Crypto.Merkle +namespace CoiniumServ.Crypto.Merkle { public interface IMerkleRoot { diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs index 2beaf5f16..245e9d83f 100644 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs +++ b/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Crypto.Merkle +namespace CoiniumServ.Crypto.Merkle { /// /// Merkle tree builder. diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs index ae9288710..b7824c61e 100644 --- a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs +++ b/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Utils.Extensions; +using CoiniumServ.Utils.Extensions; -namespace Coinium.Crypto.Merkle +namespace CoiniumServ.Crypto.Merkle { /// /// Merkle tree builder. diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs index 56df2955d..d548f756f 100644 --- a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs +++ b/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Linq; -using Coinium.Utils.Extensions; -using Coinium.Utils.Helpers.Misc; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Helpers.Misc; -namespace Coinium.Crypto.Merkle +namespace CoiniumServ.Crypto.Merkle { /// /// Merkle tree builder. diff --git a/src/CoiniumServ/Crypto/Utils.cs b/src/CoiniumServ/Crypto/Utils.cs index 30e367007..12da9b77b 100644 --- a/src/CoiniumServ/Crypto/Utils.cs +++ b/src/CoiniumServ/Crypto/Utils.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Security.Cryptography; -namespace Coinium.Crypto +namespace CoiniumServ.Crypto { public static class Utils { diff --git a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs index c63cfa718..5c330b2f0 100644 --- a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Config +namespace CoiniumServ.Daemon.Config { public class DaemonConfig:IDaemonConfig { diff --git a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs index a356f24bd..f3a6e3a07 100644 --- a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Configuration; +using CoiniumServ.Utils.Configuration; -namespace Coinium.Daemon.Config +namespace CoiniumServ.Daemon.Config { public interface IDaemonConfig:IConfig { diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index c0fd05f99..035a9e8b1 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -20,17 +20,18 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; using System.Net; using System.Text; -using Coinium.Daemon.Config; -using Coinium.Daemon.Exceptions; -using Coinium.Utils.Extensions; +using CoiniumServ.Daemon.Config; +using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Serilog; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { public class DaemonBase : IDaemonBase { diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 901950344..ac9308ae5 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -20,12 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Daemon.Requests; -using Coinium.Daemon.Responses; - /* This file is based on https://github.com/BitKoot/BitcoinRpcSharp */ /* Possible alternative implementations: @@ -37,8 +35,10 @@ // Original bitcoin api call list: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list // Rpc error codes: https://github.com/bitcoin/bitcoin/blob/master/src/rpcprotocol.h#L34 +using CoiniumServ.Daemon.Requests; +using CoiniumServ.Daemon.Responses; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { /// /// RPC client for coind's. diff --git a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs index 7995b6661..5910ddac4 100644 --- a/src/CoiniumServ/Daemon/DaemonErrorResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonErrorResponse.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using Newtonsoft.Json; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { public class DaemonErrorResponse { diff --git a/src/CoiniumServ/Daemon/DaemonRequest.cs b/src/CoiniumServ/Daemon/DaemonRequest.cs index 345d5a7e8..185896fbf 100644 --- a/src/CoiniumServ/Daemon/DaemonRequest.cs +++ b/src/CoiniumServ/Daemon/DaemonRequest.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { /// /// Class containing data sent to the Bitcoin wallet as a JSON RPC call. diff --git a/src/CoiniumServ/Daemon/DaemonResponse.cs b/src/CoiniumServ/Daemon/DaemonResponse.cs index 01154a4ea..05078f6a6 100644 --- a/src/CoiniumServ/Daemon/DaemonResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonResponse.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Newtonsoft.Json; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { /// /// Class containing the information contained in a JSON RPC response received from diff --git a/src/CoiniumServ/Daemon/Exceptions/RpcException.cs b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs index 66b53b17f..26b62531b 100644 --- a/src/CoiniumServ/Daemon/Exceptions/RpcException.cs +++ b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Daemon.Exceptions +namespace CoiniumServ.Daemon.Exceptions { public class RpcException : Exception { diff --git a/src/CoiniumServ/Daemon/IDaemonBase.cs b/src/CoiniumServ/Daemon/IDaemonBase.cs index a6de9a2fe..9786e798f 100644 --- a/src/CoiniumServ/Daemon/IDaemonBase.cs +++ b/src/CoiniumServ/Daemon/IDaemonBase.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Daemon.Config; +using CoiniumServ.Daemon.Config; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { public interface IDaemonBase { diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index c759d54a2..0ee3f6be2 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Daemon.Config; -using Coinium.Daemon.Responses; +using CoiniumServ.Daemon.Config; +using CoiniumServ.Daemon.Responses; -namespace Coinium.Daemon +namespace CoiniumServ.Daemon { public interface IDaemonClient { diff --git a/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs b/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs index 48f24d1fd..be7308761 100644 --- a/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Requests/CreateRawTransaction.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Requests +namespace CoiniumServ.Daemon.Requests { public class CreateRawTransaction { diff --git a/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs b/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs index 2ad10c1e3..7d623967d 100644 --- a/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs +++ b/src/CoiniumServ/Daemon/Requests/CreateRawTransactionInput.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Newtonsoft.Json; -namespace Coinium.Daemon.Requests +namespace CoiniumServ.Daemon.Requests { public class CreateRawTransactionInput { diff --git a/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs b/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs index 96b1bb6a7..9f94ae690 100644 --- a/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Requests/SignRawTransaction.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Requests +namespace CoiniumServ.Daemon.Requests { public class SignRawTransaction { diff --git a/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs b/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs index b77394844..b4ef5f234 100644 --- a/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs +++ b/src/CoiniumServ/Daemon/Requests/SignRawTransactionInput.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Newtonsoft.Json; -namespace Coinium.Daemon.Requests +namespace CoiniumServ.Daemon.Requests { public class SignRawTransactionInput { diff --git a/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs b/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs index dbe3e2e05..e51e9b579 100644 --- a/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/AddedNodeInfo.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class AddedNodeInfo { diff --git a/src/CoiniumServ/Daemon/Responses/Block.cs b/src/CoiniumServ/Daemon/Responses/Block.cs index ea4519d36..1360df323 100644 --- a/src/CoiniumServ/Daemon/Responses/Block.cs +++ b/src/CoiniumServ/Daemon/Responses/Block.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class Block { diff --git a/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs b/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs index 66b618d22..9c5330fd2 100644 --- a/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs +++ b/src/CoiniumServ/Daemon/Responses/BlockTemplate.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { /// /// getblocktemplate is the new decentralized Bitcoin mining protocol, openly developed by the Bitcoin community over mid 2012. It supercedes the old getwork mining protocol. diff --git a/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs b/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs index 75927f5ba..04173446a 100644 --- a/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/BlockTemplateTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { /// /// diff --git a/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs b/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs index e40c96958..b75c98081 100644 --- a/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/DecodedRawTransaction.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class DecodedRawTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs b/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs index 8f8cc39a0..ecad39baa 100644 --- a/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs +++ b/src/CoiniumServ/Daemon/Responses/IBlockTemplate.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public interface IBlockTemplate { diff --git a/src/CoiniumServ/Daemon/Responses/Info.cs b/src/CoiniumServ/Daemon/Responses/Info.cs index 8d2c355a4..2b1db3041 100644 --- a/src/CoiniumServ/Daemon/Responses/Info.cs +++ b/src/CoiniumServ/Daemon/Responses/Info.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class Info { diff --git a/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs index af698c8ec..69bd42aa1 100644 --- a/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListReceivedByAccountTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class ListReceivedByAccountTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs index 491783123..94d5e24c2 100644 --- a/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListReceivedByAddressTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class ListReceivedByAddressTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/ListTransaction.cs b/src/CoiniumServ/Daemon/Responses/ListTransaction.cs index bf2d88b96..2d5cf37e4 100644 --- a/src/CoiniumServ/Daemon/Responses/ListTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/ListTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class ListTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs index 0423f8a10..5b94cdc64 100644 --- a/src/CoiniumServ/Daemon/Responses/MiningInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/MiningInfo.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class MiningInfo { diff --git a/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs b/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs index dc39e9e34..9fcf3bde3 100644 --- a/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/MultisigAddress.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class MultisigAddress { diff --git a/src/CoiniumServ/Daemon/Responses/NodeAddress.cs b/src/CoiniumServ/Daemon/Responses/NodeAddress.cs index 89d4aeaf4..6af2e8c5a 100644 --- a/src/CoiniumServ/Daemon/Responses/NodeAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/NodeAddress.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class NodeAddress { diff --git a/src/CoiniumServ/Daemon/Responses/PeerInfo.cs b/src/CoiniumServ/Daemon/Responses/PeerInfo.cs index ce7621831..3513ca72b 100644 --- a/src/CoiniumServ/Daemon/Responses/PeerInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/PeerInfo.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class PeerInfo { diff --git a/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs b/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs index f3d02e542..43e628807 100644 --- a/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/SignedRawTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class SignedRawTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/Transaction.cs b/src/CoiniumServ/Daemon/Responses/Transaction.cs index c22110b76..b69d200d7 100644 --- a/src/CoiniumServ/Daemon/Responses/Transaction.cs +++ b/src/CoiniumServ/Daemon/Responses/Transaction.cs @@ -20,10 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; + using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class Transaction { diff --git a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs index f3f660c6f..d7cd11efb 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionDetail.cs @@ -22,7 +22,7 @@ #endregion /* This file is based on https://github.com/BitKoot/BitcoinRpcSharp */ -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class TransactionDetail { diff --git a/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs b/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs index 53edb8c77..c85357453 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionSinceBlock.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class TransactionSinceBlock { diff --git a/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs b/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs index d210ef8c5..e633e937c 100644 --- a/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs +++ b/src/CoiniumServ/Daemon/Responses/TransactionsSinceBlock.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class TransactionsSinceBlock { diff --git a/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs b/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs index 99876093f..6443a771c 100644 --- a/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs +++ b/src/CoiniumServ/Daemon/Responses/TxOutSetInfo.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class TxOutSetInfo { diff --git a/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs b/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs index ebdfe4525..622cccdaa 100644 --- a/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs +++ b/src/CoiniumServ/Daemon/Responses/UnspentTransaction.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class UnspentTransaction { diff --git a/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs b/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs index 06bae4219..46036810a 100644 --- a/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs +++ b/src/CoiniumServ/Daemon/Responses/ValidateAddress.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { public class ValidateAddress { diff --git a/src/CoiniumServ/Daemon/Responses/Work.cs b/src/CoiniumServ/Daemon/Responses/Work.cs index ffd67c55a..04b3e5618 100644 --- a/src/CoiniumServ/Daemon/Responses/Work.cs +++ b/src/CoiniumServ/Daemon/Responses/Work.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Daemon.Responses +namespace CoiniumServ.Daemon.Responses { // Documentation: // https://en.bitcoin.it/wiki/Getwork diff --git a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs index ce46fedd4..c80b4a77a 100644 --- a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Extensions; +using CoiniumServ.Utils.Extensions; -namespace Coinium.Mining.Jobs +namespace CoiniumServ.Mining.Jobs { /// /// Counter for extra nonce. diff --git a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs index 864bfd7c8..f5161cd14 100644 --- a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Jobs +namespace CoiniumServ.Mining.Jobs { // Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) public interface IExtraNonce diff --git a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs b/src/CoiniumServ/Mining/Jobs/IJobCounter.cs index 38c5fcb40..61c979ac0 100644 --- a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs +++ b/src/CoiniumServ/Mining/Jobs/IJobCounter.cs @@ -20,12 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace Coinium.Mining.Jobs +namespace CoiniumServ.Mining.Jobs { public interface IJobCounter { diff --git a/src/CoiniumServ/Mining/Jobs/JobCounter.cs b/src/CoiniumServ/Mining/Jobs/JobCounter.cs index 7f2bada54..f108f0625 100644 --- a/src/CoiniumServ/Mining/Jobs/JobCounter.cs +++ b/src/CoiniumServ/Mining/Jobs/JobCounter.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Jobs +namespace CoiniumServ.Mining.Jobs { /// /// Counter for job id's. diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs index 75ee95019..2b19cf716 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Jobs.Manager +namespace CoiniumServ.Mining.Jobs.Manager { public interface IJobManager { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs index 69baaff95..03b92bd26 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Shares; -namespace Coinium.Mining.Jobs.Manager +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; + +namespace CoiniumServ.Mining.Jobs.Manager { public interface IJobManagerFactory { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index f9224b4e0..f935c3d56 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -20,20 +20,21 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Threading; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Daemon.Exceptions; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Shares; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Transactions; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Transactions; using Serilog; -namespace Coinium.Mining.Jobs.Manager +namespace CoiniumServ.Mining.Jobs.Manager { public class JobManager : IJobManager { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs index bcf18a244..e1548781d 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Shares; -using Coinium.Repository.Context; + +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Mining.Jobs.Manager +namespace CoiniumServ.Mining.Jobs.Manager { public class JobManagerFactory : IJobManagerFactory { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs index 2f73d2ee1..acaee2530 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Server.Mining.Stratum.Notifications; +using CoiniumServ.Server.Mining.Stratum.Notifications; -namespace Coinium.Mining.Jobs.Tracker +namespace CoiniumServ.Mining.Jobs.Tracker { public interface IJobTracker { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs index 96047fa8c..0b9bac211 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs @@ -20,12 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace Coinium.Mining.Jobs.Tracker +namespace CoiniumServ.Mining.Jobs.Tracker { public interface IJobTrackerFactory { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs index c755ab7d3..8f92be3d3 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Server.Mining.Stratum.Notifications; +using CoiniumServ.Server.Mining.Stratum.Notifications; -namespace Coinium.Mining.Jobs.Tracker +namespace CoiniumServ.Mining.Jobs.Tracker { public class JobTracker:IJobTracker { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs index 23b348ff1..0ac401a9f 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -namespace Coinium.Mining.Jobs.Tracker +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Mining.Jobs.Tracker { public class JobTrackerFactory:IJobTrackerFactory { diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Mining/Miners/IMiner.cs index 8120c87aa..97673537a 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Mining/Miners/IMiner.cs @@ -21,11 +21,10 @@ // #endregion -using System; -using Coinium.Mining.Pools; -using Coinium.Server.Mining.Stratum.Notifications; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Server.Mining.Stratum.Notifications; -namespace Coinium.Mining.Miners +namespace CoiniumServ.Mining.Miners { /// /// Miner interface that any implementations should extend. diff --git a/src/CoiniumServ/Mining/Miners/IMinerManager.cs b/src/CoiniumServ/Mining/Miners/IMinerManager.cs index 90b18443e..d7a98b810 100644 --- a/src/CoiniumServ/Mining/Miners/IMinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/IMinerManager.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Mining.Pools; -using Coinium.Net.Server.Sockets; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Sockets; -namespace Coinium.Mining.Miners +namespace CoiniumServ.Mining.Miners { public interface IMinerManager { diff --git a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs index 2cae2adeb..346a0027d 100644 --- a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs +++ b/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -namespace Coinium.Mining.Miners +using CoiniumServ.Daemon; + +namespace CoiniumServ.Mining.Miners { public interface IMinerManagerFactory { diff --git a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs b/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs index 7bb40fa3d..153038b02 100644 --- a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs +++ b/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Miners +namespace CoiniumServ.Mining.Miners { public class MinerEventArgs:EventArgs { diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index ea6730bec..23a00bf2e 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Daemon; -using Coinium.Mining.Pools; -using Coinium.Net.Server.Sockets; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Sockets; using Serilog; -namespace Coinium.Mining.Miners +namespace CoiniumServ.Mining.Miners { public class MinerManager : IMinerManager { diff --git a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs index 547367a2d..da07fc1f4 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs @@ -20,12 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Repository.Context; + +using CoiniumServ.Daemon; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -using Serilog; -namespace Coinium.Mining.Miners +namespace CoiniumServ.Mining.Miners { public class MinerManagerFactory : IMinerManagerFactory { diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 683dae55c..c4cab9154 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Coin.Config; -using Coinium.Daemon.Config; -using Coinium.Payments; -using Coinium.Server.Mining.Stratum.Config; -using Coinium.Server.Mining.Vanilla.Config; -using Coinium.Utils.Configuration; - -namespace Coinium.Mining.Pools.Config + +using CoiniumServ.Coin.Config; +using CoiniumServ.Daemon.Config; +using CoiniumServ.Payments; +using CoiniumServ.Server.Mining.Stratum.Config; +using CoiniumServ.Server.Mining.Vanilla.Config; +using CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Mining.Pools.Config { public interface IPoolConfig:IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs index bee5d40ce..2bcd773cd 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { /// /// Returns an instance of IPoolConfig based on the parsed config file diff --git a/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs index e4e5ca1e5..7bdc89d01 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs @@ -22,9 +22,9 @@ #endregion using System.Collections.Generic; -using Coinium.Utils.Configuration; +using CoiniumServ.Utils.Configuration; -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { public interface IRewardsConfig :IEnumerable>, IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs index f42e52534..5c3deba42 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { public interface IWalletConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 6766a9957..8f5f2cfdf 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.IO; -using Coinium.Coin.Config; -using Coinium.Daemon.Config; -using Coinium.Payments; -using Coinium.Server.Mining.Stratum.Config; -using Coinium.Server.Mining.Vanilla.Config; +using CoiniumServ.Coin.Config; +using CoiniumServ.Daemon.Config; +using CoiniumServ.Payments; +using CoiniumServ.Server.Mining.Stratum.Config; +using CoiniumServ.Server.Mining.Vanilla.Config; -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { /// /// Reads and serves the configuration for a pool. diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs index c83fbfbe6..d16957be2 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Coin.Config; -using Coinium.Repository.Context; + +using CoiniumServ.Coin.Config; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { public class PoolConfigFactory : IPoolConfigFactory { diff --git a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs index daeeb9d1c..c9b420f69 100644 --- a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using JsonConfig; -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { public class RewardsConfig:IRewardsConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs index 201737487..c5d1dbe07 100644 --- a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Pools.Config +namespace CoiniumServ.Mining.Pools.Config { public class WalletConfig:IWalletConfig { diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index 907802daa..3c39d1dd7 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -namespace Coinium.Mining.Pools +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; + +namespace CoiniumServ.Mining.Pools { public interface IPool { diff --git a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolFactory.cs index 3cab87213..df21f089f 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolFactory.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools.Config; -namespace Coinium.Mining.Pools +using CoiniumServ.Mining.Pools.Config; + +namespace CoiniumServ.Mining.Pools { public interface IPoolFactory { diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index 4375d022c..f63792f72 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; -namespace Coinium.Mining.Pools +namespace CoiniumServ.Mining.Pools { public interface IPoolManager { diff --git a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs index 88fe1a9b6..7fe05a678 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Mining.Pools +namespace CoiniumServ.Mining.Pools { public interface IPoolManagerFactory { diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 18b96fed5..3b7186c8d 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -20,29 +20,30 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; -using Coinium.Coin.Helpers; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -using Coinium.Mining.Shares; -using Coinium.Mining.Vardiff; -using Coinium.Payments; -using Coinium.Persistance; -using Coinium.Server; -using Coinium.Server.Mining; -using Coinium.Server.Mining.Service; -using Coinium.Utils.Helpers.Validation; +using CoiniumServ.Coin.Helpers; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Payments; +using CoiniumServ.Persistance; +using CoiniumServ.Server; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Utils.Helpers.Validation; using Serilog; -namespace Coinium.Mining.Pools +namespace CoiniumServ.Mining.Pools { /// /// Contains pool services and server. diff --git a/src/CoiniumServ/Mining/Pools/PoolFactory.cs b/src/CoiniumServ/Mining/Pools/PoolFactory.cs index 7c627d17e..96583ddb9 100644 --- a/src/CoiniumServ/Mining/Pools/PoolFactory.cs +++ b/src/CoiniumServ/Mining/Pools/PoolFactory.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools.Config; -using Coinium.Repository.Context; -namespace Coinium.Mining.Pools +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Mining.Pools { public class PoolFactory : IPoolFactory { diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index a9bf83e7c..77e8d44dc 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -using Coinium.Utils.Configuration; -using Coinium.Utils.Helpers.IO; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Utils.Configuration; +using CoiniumServ.Utils.Helpers.IO; using Serilog; -namespace Coinium.Mining.Pools +namespace CoiniumServ.Mining.Pools { public class PoolManager : IPoolManager { diff --git a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs index 6ec5c19f5..54d8abfba 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -namespace Coinium.Mining.Pools +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Mining.Pools { public class PoolManagerFactory:IPoolManagerFactory { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs index 44fb12f8b..5f39d3413 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections; using System.Collections.Generic; using Newtonsoft.Json; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class Algorithms : IAlgorithms { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs index f1c6c0c46..797897354 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs @@ -21,9 +21,9 @@ // #endregion -using Coinium.Persistance; +using CoiniumServ.Persistance; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class Blocks:IBlocks { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs index 6fd911a40..65cdd2daa 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Global.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Dynamic; using Newtonsoft.Json; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class Global : IGlobal { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs index b165be861..6d777f362 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IAlgorithms: IEnumerable>, IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs index 5a9bf204c..0088be6c8 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IBlocks : IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs index 742254c42..07b7edc36 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IGlobal: IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs b/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs index f821da5ae..1af108a76 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IJsonResponse { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs index 7fcf0ee90..b31e17d20 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs @@ -22,9 +22,9 @@ #endregion using System.Collections.Generic; -using Coinium.Persistance.Blocks; +using CoiniumServ.Persistance.Blocks; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface ILatestBlocks: IEnumerable, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs index d103d2410..4dbf027ec 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IPerAlgorithm:IJsonResponse { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs index 36ea1eb1f..86caacc22 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IPerPool:IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs index f47f07f63..84d1b40ce 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IPools : IEnumerable>,IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs index 0412c5ba3..dfad1f911 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IStatistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 83c2f7bd7..2a8284be3 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -namespace Coinium.Mining.Pools.Statistics +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; + +namespace CoiniumServ.Mining.Pools.Statistics { public interface IStatisticsObjectFactory { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs index 3e6bc5c3e..5cf1596ef 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public interface IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs b/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs index ab3f9a4ed..6768ae523 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs @@ -24,10 +24,10 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Coinium.Persistance; -using Coinium.Persistance.Blocks; +using CoiniumServ.Persistance; +using CoiniumServ.Persistance.Blocks; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class LatestBlocks:ILatestBlocks { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs index d23b0f356..c5fbdbb29 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs @@ -25,7 +25,7 @@ using System.Dynamic; using Newtonsoft.Json; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class PerAlgorithm:IPerAlgorithm { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs index 95df5b362..065ce1e1f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs @@ -20,18 +20,19 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Dynamic; using System.Linq; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -using Coinium.Utils.Helpers.Time; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; +using CoiniumServ.Utils.Helpers.Time; using Newtonsoft.Json; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class PerPool:IPerPool { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs index d2eb1f18b..d7e169ad6 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections; using System.Collections.Generic; using System.Dynamic; using Newtonsoft.Json; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class Pools:IPools { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index 7b90b7d62..c647aa4e1 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Threading; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class Statistics:IStatistics, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index 5ceb7450b..b386b69d0 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -using Coinium.Repository.Context; + +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Mining.Pools.Statistics +namespace CoiniumServ.Mining.Pools.Statistics { public class StatististicsObjectFactory : IStatisticsObjectFactory { diff --git a/src/CoiniumServ/Mining/Shares/IShare.cs b/src/CoiniumServ/Mining/Shares/IShare.cs index 5637d1436..a024e636e 100644 --- a/src/CoiniumServ/Mining/Shares/IShare.cs +++ b/src/CoiniumServ/Mining/Shares/IShare.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Crypto; -using Coinium.Daemon.Responses; -using Coinium.Mining.Miners; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Utils.Numerics; +using CoiniumServ.Crypto; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Utils.Numerics; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public interface IShare { diff --git a/src/CoiniumServ/Mining/Shares/IShareManager.cs b/src/CoiniumServ/Mining/Shares/IShareManager.cs index 605cc1c82..9fbef7268 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManager.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Server.Mining.Stratum; -using Coinium.Server.Mining.Vanilla; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Vanilla; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public interface IShareManager { diff --git a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs index 7b21a72e4..e3327cbbb 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Persistance; -namespace Coinium.Mining.Shares +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Persistance; + +namespace CoiniumServ.Mining.Shares { public interface IShareManagerFactory { diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index a21c30122..aa6f24e8a 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -20,18 +20,19 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Coin.Coinbase; -using Coinium.Crypto; -using Coinium.Daemon.Responses; -using Coinium.Mining.Miners; -using Coinium.Server.Mining.Stratum; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Utils.Extensions; -using Coinium.Utils.Numerics; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Crypto; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Numerics; using Serilog; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public class Share : IShare { diff --git a/src/CoiniumServ/Mining/Shares/ShareError.cs b/src/CoiniumServ/Mining/Shares/ShareError.cs index d10f31561..8e6a7e69a 100644 --- a/src/CoiniumServ/Mining/Shares/ShareError.cs +++ b/src/CoiniumServ/Mining/Shares/ShareError.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public enum ShareError { diff --git a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs index 84cc3df94..43e0b5df3 100644 --- a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs +++ b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs @@ -22,9 +22,9 @@ #endregion using System; -using Coinium.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Stratum; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public class ShareEventArgs:EventArgs { diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 53d63abc2..3c2faa62a 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -20,18 +20,19 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using AustinHarris.JsonRpc; -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Persistance; -using Coinium.Server.Mining.Stratum; -using Coinium.Server.Mining.Stratum.Errors; -using Coinium.Server.Mining.Vanilla; -using Coinium.Utils.Extensions; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Persistance; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Stratum.Errors; +using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Utils.Extensions; using Serilog; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public class ShareManager : IShareManager { diff --git a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs index 799830808..dacd2df62 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Persistance; -using Coinium.Repository.Context; + +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Persistance; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Mining.Shares +namespace CoiniumServ.Mining.Shares { public class ShareManagerFactory : IShareManagerFactory { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs index e76c2c696..c4f9e3509 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public interface IVardiffConfig { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs index e85d4637d..3d6125b4d 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public interface IVardiffManager { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs index a55eb0270..f628968f4 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs @@ -21,9 +21,9 @@ // #endregion -using Coinium.Mining.Shares; +using CoiniumServ.Mining.Shares; -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public interface IVardiffManagerFactory { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs index f2fe0b05c..e74b54f2f 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs @@ -21,9 +21,9 @@ // #endregion -using Coinium.Utils.Buffers; +using CoiniumServ.Utils.Buffers; -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public interface IVardiffMiner { diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs index 5a46a59d5..6cca10977 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public class VardiffConfig:IVardiffConfig { diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index 0f15aa6bc..cd6bb325f 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -22,11 +22,11 @@ #endregion using System; -using Coinium.Mining.Shares; -using Coinium.Utils.Buffers; -using Coinium.Utils.Helpers.Time; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Utils.Buffers; +using CoiniumServ.Utils.Helpers.Time; -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public class VardiffManager:IVardiffManager { diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs index c0dbc1a0d..4699c92e6 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs @@ -21,11 +21,11 @@ // #endregion -using Coinium.Mining.Shares; -using Coinium.Repository.Context; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Mining.Vardiff +namespace CoiniumServ.Mining.Vardiff { public class VardiffManagerFactory : IVardiffManagerFactory { diff --git a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs index 93974b54a..e810e2292 100644 --- a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Net; @@ -27,7 +28,7 @@ // source from: http://stackoverflow.com/a/4673210/170181 -namespace Coinium.Net.Server.Http.Basic +namespace CoiniumServ.Net.Server.Http.Basic { public class HttpServer : IServer, IDisposable { diff --git a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs index ed6c185c6..2364c3802 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/ErrorConfiguration.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Nancy; using Nancy.CustomErrors; -namespace Coinium.Net.Server.Http.Web +namespace CoiniumServ.Net.Server.Http.Web { public class ErrorConfiguration : CustomErrorsConfiguration { diff --git a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index 56fd1b29e..e0ca37d00 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Repository.Context; +using CoiniumServ.Repository.Context; using Nancy.Bootstrapper; using Nancy.Hosting.Self; using Serilog; -namespace Coinium.Net.Server.Http.Web +namespace CoiniumServ.Net.Server.Http.Web { public class HttpServer : IServer, IDisposable { diff --git a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs index 7395a3aa9..d694967f8 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs @@ -20,7 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; + +using CoiniumServ.Repository.Context; using Nancy; using Nancy.Bootstrapper; using Nancy.Conventions; @@ -28,7 +29,7 @@ using Nancy.Diagnostics; using Nancy.TinyIoc; -namespace Coinium.Net.Server.Http.Web +namespace CoiniumServ.Net.Server.Http.Web { public class NancyBootstrapper : DefaultNancyBootstrapper { diff --git a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs index ca4b19b4b..57326fdbc 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.IO; using System.Reflection; -using Coinium.Utils.Platform; +using CoiniumServ.Utils.Platform; using Nancy; -namespace Coinium.Net.Server.Http.Web +namespace CoiniumServ.Net.Server.Http.Web { public class CustomRootPathProvider : IRootPathProvider { diff --git a/src/CoiniumServ/Net/Server/IServer.cs b/src/CoiniumServ/Net/Server/IServer.cs index b0c8fb10a..891f63402 100644 --- a/src/CoiniumServ/Net/Server/IServer.cs +++ b/src/CoiniumServ/Net/Server/IServer.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Net.Server +namespace CoiniumServ.Net.Server { /// /// Server interface that any implementations should extend. diff --git a/src/CoiniumServ/Net/Server/Sockets/Connection.cs b/src/CoiniumServ/Net/Server/Sockets/Connection.cs index b44632966..3833ff725 100644 --- a/src/CoiniumServ/Net/Server/Sockets/Connection.cs +++ b/src/CoiniumServ/Net/Server/Sockets/Connection.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { public class Connection : IConnection { diff --git a/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs b/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs index 54fa6e9b5..8e7461b65 100644 --- a/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs +++ b/src/CoiniumServ/Net/Server/Sockets/ConnectionDataEventArgs.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Linq; -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { public sealed class ConnectionDataEventArgs : ConnectionEventArgs { diff --git a/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs b/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs index bdaf232c1..8d1a25a7b 100644 --- a/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs +++ b/src/CoiniumServ/Net/Server/Sockets/ConnectionEventArgs.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { public class ConnectionEventArgs : EventArgs { diff --git a/src/CoiniumServ/Net/Server/Sockets/IClient.cs b/src/CoiniumServ/Net/Server/Sockets/IClient.cs index 7735a6cf6..2aac33e9d 100644 --- a/src/CoiniumServ/Net/Server/Sockets/IClient.cs +++ b/src/CoiniumServ/Net/Server/Sockets/IClient.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { /// /// Client interface. diff --git a/src/CoiniumServ/Net/Server/Sockets/IConnection.cs b/src/CoiniumServ/Net/Server/Sockets/IConnection.cs index cfb71b694..1642bec6e 100644 --- a/src/CoiniumServ/Net/Server/Sockets/IConnection.cs +++ b/src/CoiniumServ/Net/Server/Sockets/IConnection.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Net; using System.Net.Sockets; -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { /// /// Connection interface. diff --git a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs index c55727d21..ac6209c1e 100644 --- a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; -using Coinium.Utils.Extensions; +using CoiniumServ.Utils.Extensions; using Serilog; -namespace Coinium.Net.Server.Sockets +namespace CoiniumServ.Net.Server.Sockets { public class SocketServer : IServer, IDisposable { diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs index f788a681f..b932274e8 100644 --- a/src/CoiniumServ/Payments/IPaymentConfig.cs +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -20,11 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using System.Collections.Generic; -using Coinium.Utils.Configuration; +using CoiniumServ.Utils.Configuration; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public interface IPaymentConfig:IConfig { diff --git a/src/CoiniumServ/Payments/IPaymentProcessor.cs b/src/CoiniumServ/Payments/IPaymentProcessor.cs index bc8da694d..d880772a7 100644 --- a/src/CoiniumServ/Payments/IPaymentProcessor.cs +++ b/src/CoiniumServ/Payments/IPaymentProcessor.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Payments +namespace CoiniumServ.Payments { public interface IPaymentProcessor { diff --git a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs index 7cbe311a6..046b8b497 100644 --- a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -namespace Coinium.Payments +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; + +namespace CoiniumServ.Payments { public interface IPaymentProcessorFactory { diff --git a/src/CoiniumServ/Payments/IPaymentRound.cs b/src/CoiniumServ/Payments/IPaymentRound.cs index 170552850..e7626a098 100644 --- a/src/CoiniumServ/Payments/IPaymentRound.cs +++ b/src/CoiniumServ/Payments/IPaymentRound.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Persistance.Blocks; +using CoiniumServ.Persistance.Blocks; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public interface IPaymentRound { diff --git a/src/CoiniumServ/Payments/IWorkerBalance.cs b/src/CoiniumServ/Payments/IWorkerBalance.cs index eab13680b..c97392b85 100644 --- a/src/CoiniumServ/Payments/IWorkerBalance.cs +++ b/src/CoiniumServ/Payments/IWorkerBalance.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Payments +namespace CoiniumServ.Payments { public interface IWorkerBalance { diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs index 90aeaaa81..05bfd810c 100644 --- a/src/CoiniumServ/Payments/PaymentConfig.cs +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -21,10 +21,7 @@ // #endregion -using System.Collections.Generic; -using JsonConfig; - -namespace Coinium.Payments +namespace CoiniumServ.Payments { public class PaymentConfig:IPaymentConfig { diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index d77fa93da..83ae465ac 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -20,19 +20,20 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; -using Coinium.Daemon; -using Coinium.Daemon.Exceptions; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -using Coinium.Persistance.Blocks; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; +using CoiniumServ.Persistance.Blocks; using Serilog; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public class PaymentProcessor : IPaymentProcessor { diff --git a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs index 7211de271..d5aa29171 100644 --- a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs +++ b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Mining.Pools.Config; -using Coinium.Persistance; -using Coinium.Repository.Context; + +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public class PaymentProcessorFactory : IPaymentProcessorFactory { diff --git a/src/CoiniumServ/Payments/PaymentRound.cs b/src/CoiniumServ/Payments/PaymentRound.cs index b39af8b84..6961a3801 100644 --- a/src/CoiniumServ/Payments/PaymentRound.cs +++ b/src/CoiniumServ/Payments/PaymentRound.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Linq; -using Coinium.Persistance.Blocks; +using CoiniumServ.Persistance.Blocks; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public class PaymentRound:IPaymentRound { diff --git a/src/CoiniumServ/Payments/WorkerBalance.cs b/src/CoiniumServ/Payments/WorkerBalance.cs index a2ea3f0fa..81375565d 100644 --- a/src/CoiniumServ/Payments/WorkerBalance.cs +++ b/src/CoiniumServ/Payments/WorkerBalance.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Payments +namespace CoiniumServ.Payments { public class WorkerBalance:IWorkerBalance { diff --git a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs index 3be792c4e..1fe25c1c1 100644 --- a/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs +++ b/src/CoiniumServ/Persistance/Blocks/BlockStatus.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public enum BlockStatus { diff --git a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs index b17a6d069..9402d8f74 100644 --- a/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/ConfirmedBlock.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public class ConfirmedBlock:IConfirmedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs index 9d0e1d1e3..93b6ec30d 100644 --- a/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs +++ b/src/CoiniumServ/Persistance/Blocks/HashCandidate.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public class HashCandidate : IHashCandidate { diff --git a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs index 94c2e0cd9..48110a899 100644 --- a/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IConfirmedBlock.cs @@ -20,13 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IConfirmedBlock:IFinalizedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs index 9cbd8414e..c7b507f5b 100644 --- a/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IFinalizedBlock.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IFinalizedBlock:IPersistedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs index 0a4ce6ce8..f6fd48ae7 100644 --- a/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs +++ b/src/CoiniumServ/Persistance/Blocks/IHashCandidate.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IHashCandidate { diff --git a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs index 154910702..75957c8ff 100644 --- a/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IKickedBlock.cs @@ -20,13 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IKickedBlock:IFinalizedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs index 232d501f3..af81db90f 100644 --- a/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IOrphanedBlock.cs @@ -20,13 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IOrphanedBlock:IFinalizedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs index 9086ff925..f91adf0e3 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPendingBlock.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IPendingBlock: IPersistedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs index 079cbcc2a..9904db196 100644 --- a/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/IPersistedBlock.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public interface IPersistedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs index 988eb7ca6..6a5df9612 100644 --- a/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/KickedBlock.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public class KickedBlock:IKickedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs index aea263500..20f6e1f14 100644 --- a/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/OrphanedBlock.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public class OrphanedBlock:IOrphanedBlock { diff --git a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs index acf24c5b8..c942b5a37 100644 --- a/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs +++ b/src/CoiniumServ/Persistance/Blocks/PendingBlock.cs @@ -20,11 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; + using System.Collections.Generic; using System.Linq; -namespace Coinium.Persistance.Blocks +namespace CoiniumServ.Persistance.Blocks { public class PendingBlock : IPendingBlock { diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index e5ef0ca92..06eb89ce8 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Mining.Shares; -using Coinium.Payments; -using Coinium.Persistance.Blocks; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Payments; +using CoiniumServ.Persistance.Blocks; -namespace Coinium.Persistance +namespace CoiniumServ.Persistance { public interface IStorage { diff --git a/src/CoiniumServ/Persistance/IStorageFactory.cs b/src/CoiniumServ/Persistance/IStorageFactory.cs index 807376507..055df1729 100644 --- a/src/CoiniumServ/Persistance/IStorageFactory.cs +++ b/src/CoiniumServ/Persistance/IStorageFactory.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools.Config; -namespace Coinium.Persistance +using CoiniumServ.Mining.Pools.Config; + +namespace CoiniumServ.Persistance { public interface IStorageFactory { diff --git a/src/CoiniumServ/Persistance/Redis/IRedis.cs b/src/CoiniumServ/Persistance/Redis/IRedis.cs index 11a73039a..f0e51f794 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedis.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedis.cs @@ -20,9 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using System; -namespace Coinium.Persistance.Redis +namespace CoiniumServ.Persistance.Redis { public interface IRedis { diff --git a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs index 509857ef5..d7ca028f6 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Persistance.Redis +namespace CoiniumServ.Persistance.Redis { public interface IRedisConfig { diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index b6bc015ca..a03fc5114 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -20,24 +20,24 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Net.Sockets; -using Coinium.Daemon.Responses; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Shares; -using Coinium.Payments; -using Coinium.Persistance.Blocks; -using Coinium.Utils.Configuration; -using Coinium.Utils.Extensions; -using Coinium.Utils.Helpers.Time; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Payments; +using CoiniumServ.Persistance.Blocks; +using CoiniumServ.Utils.Configuration; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Helpers.Time; using Serilog; using StackExchange.Redis; -namespace Coinium.Persistance.Redis +namespace CoiniumServ.Persistance.Redis { public class Redis:IStorage, IRedis { diff --git a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs index 96e538b49..3a49e1f79 100644 --- a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Persistance.Redis +namespace CoiniumServ.Persistance.Redis { public class RedisConfig:IRedisConfig { diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs index 66672a2a5..371a10505 100644 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ b/src/CoiniumServ/Persistance/StorageFactory.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools.Config; -using Coinium.Repository.Context; + +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Persistance +namespace CoiniumServ.Persistance { public class StorageFactory:IStorageFactory { diff --git a/src/CoiniumServ/Persistance/Storages.cs b/src/CoiniumServ/Persistance/Storages.cs index 7e7ed64c1..6c6bc5023 100644 --- a/src/CoiniumServ/Persistance/Storages.cs +++ b/src/CoiniumServ/Persistance/Storages.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Persistance +namespace CoiniumServ.Persistance { public static class Storages { diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 27c0fefe5..0af1faadb 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -20,22 +20,22 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Globalization; using System.Reflection; using System.Threading; -using Coinium.Mining.Pools; -using Coinium.Repository; -using Coinium.Repository.Context; -using Coinium.Server.Web; -using Coinium.Utils; -using Coinium.Utils.Commands; -using Coinium.Utils.Configuration; -using Coinium.Utils.Platform; -using Serilog; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Repository; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils; +using CoiniumServ.Utils.Commands; +using CoiniumServ.Utils.Configuration; +using CoiniumServ.Utils.Platform; using Nancy.TinyIoc; +using Serilog; -namespace Coinium +namespace CoiniumServ { class Program { diff --git a/src/CoiniumServ/Properties/AssemblyInfo.cs b/src/CoiniumServ/Properties/AssemblyInfo.cs index 12a30bdfe..e3b2200f8 100644 --- a/src/CoiniumServ/Properties/AssemblyInfo.cs +++ b/src/CoiniumServ/Properties/AssemblyInfo.cs @@ -26,7 +26,7 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -using Coinium.Utils.Versions; +using CoiniumServ.Utils.Versions; [assembly: AssemblyTitle("CoiniumServ")] [assembly: AssemblyDescription("Crypto currency pool software")] diff --git a/src/CoiniumServ/Repository/Bootstrapper.cs b/src/CoiniumServ/Repository/Bootstrapper.cs index 0adf5aada..b41b277ae 100644 --- a/src/CoiniumServ/Repository/Bootstrapper.cs +++ b/src/CoiniumServ/Repository/Bootstrapper.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Registries; + +using CoiniumServ.Repository.Registries; using Nancy.TinyIoc; -namespace Coinium.Repository +namespace CoiniumServ.Repository { /// /// IOC & DI registry. diff --git a/src/CoiniumServ/Repository/Context/ApplicationContext.cs b/src/CoiniumServ/Repository/Context/ApplicationContext.cs index 0c29960b1..34b230e05 100644 --- a/src/CoiniumServ/Repository/Context/ApplicationContext.cs +++ b/src/CoiniumServ/Repository/Context/ApplicationContext.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Nancy.TinyIoc; -namespace Coinium.Repository.Context +namespace CoiniumServ.Repository.Context { public class ApplicationContext : IApplicationContext { diff --git a/src/CoiniumServ/Repository/Context/IApplicationContext.cs b/src/CoiniumServ/Repository/Context/IApplicationContext.cs index 334af0ab7..cb697fb30 100644 --- a/src/CoiniumServ/Repository/Context/IApplicationContext.cs +++ b/src/CoiniumServ/Repository/Context/IApplicationContext.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using Nancy.TinyIoc; -namespace Coinium.Repository.Context +namespace CoiniumServ.Repository.Context { public interface IApplicationContext { diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 78e13b095..a64311f45 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -20,18 +20,19 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Pools; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -using Coinium.Payments; -using Coinium.Persistance; -using Coinium.Persistance.Redis; -using Coinium.Repository.Context; -namespace Coinium.Repository.Registries +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Payments; +using CoiniumServ.Persistance; +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Repository.Registries { public class ClassRegistry : IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index ec95a7187..3bf47fd8d 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -20,24 +20,25 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Coin.Config; -using Coinium.Crypto.Algorithms; -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -using Coinium.Mining.Shares; -using Coinium.Mining.Vardiff; -using Coinium.Payments; -using Coinium.Persistance; -using Coinium.Repository.Context; -using Coinium.Server; -using Coinium.Server.Mining.Service; -using Coinium.Utils.Configuration; -namespace Coinium.Repository.Registries +using CoiniumServ.Coin.Config; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Payments; +using CoiniumServ.Persistance; +using CoiniumServ.Repository.Context; +using CoiniumServ.Server; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Repository.Registries { public class FactoryRegistry : IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/IRegistry.cs b/src/CoiniumServ/Repository/Registries/IRegistry.cs index 3c2d068b5..8141e42d4 100644 --- a/src/CoiniumServ/Repository/Registries/IRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/IRegistry.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Repository.Registries +namespace CoiniumServ.Repository.Registries { public interface IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 960852396..7b4345e4e 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Mining.Shares; -using Coinium.Mining.Vardiff; -using Coinium.Repository.Context; -namespace Coinium.Repository.Registries +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Repository.Registries { public class ManagerRegistry : IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index f53147a29..ac95fe133 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Net.Server.Http.Web; -using Coinium.Repository.Context; +using CoiniumServ.Net.Server.Http.Web; +using CoiniumServ.Repository.Context; using Nancy.Bootstrapper; using Nancy.TinyIoc; -namespace Coinium.Repository.Registries +namespace CoiniumServ.Repository.Registries { public class Registry : IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs index 8c4485818..04a93fbc5 100644 --- a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -using Coinium.Server; -using Coinium.Server.Mining; -using Coinium.Server.Mining.Stratum; -using Coinium.Server.Mining.Vanilla; -using Coinium.Server.Web; -namespace Coinium.Repository.Registries +using CoiniumServ.Repository.Context; +using CoiniumServ.Server; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Server.Web; + +namespace CoiniumServ.Repository.Registries { public class ServerRegistry : IRegistry { diff --git a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs index 990948c19..889408715 100644 --- a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Repository.Context; -using Coinium.Server.Mining.Service; -using Coinium.Server.Mining.Stratum.Service; -using Coinium.Server.Mining.Vanilla.Service; -namespace Coinium.Repository.Registries +using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Server.Mining.Stratum.Service; +using CoiniumServ.Server.Mining.Vanilla.Service; + +namespace CoiniumServ.Repository.Registries { public class ServiceRegistry:IRegistry { diff --git a/src/CoiniumServ/Server/Commands/Server.cs b/src/CoiniumServ/Server/Commands/Server.cs index 74054ae07..6d7c6ad93 100644 --- a/src/CoiniumServ/Server/Commands/Server.cs +++ b/src/CoiniumServ/Server/Commands/Server.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Commands; +using CoiniumServ.Utils.Commands; -namespace Coinium.Server.Commands +namespace CoiniumServ.Server.Commands { [CommandGroup("server", "Allows you to control servers and start/stop them.")] public class ServerCommand : CommandGroup diff --git a/src/CoiniumServ/Server/Commands/Stats.cs b/src/CoiniumServ/Server/Commands/Stats.cs index cf2d7d87a..54c0795b8 100644 --- a/src/CoiniumServ/Server/Commands/Stats.cs +++ b/src/CoiniumServ/Server/Commands/Stats.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Diagnostics; using System.Text; -using Coinium.Utils.Commands; +using CoiniumServ.Utils.Commands; -namespace Coinium.Server.Commands +namespace CoiniumServ.Server.Commands { [CommandGroup("stats", "Renders statistics.\nUsage: stats [system].")] public class StatsCommand : CommandGroup diff --git a/src/CoiniumServ/Server/Commands/Uptime.cs b/src/CoiniumServ/Server/Commands/Uptime.cs index 2759595fe..495637d68 100644 --- a/src/CoiniumServ/Server/Commands/Uptime.cs +++ b/src/CoiniumServ/Server/Commands/Uptime.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Commands; +using CoiniumServ.Utils.Commands; -namespace Coinium.Server.Commands +namespace CoiniumServ.Server.Commands { [CommandGroup("uptime", "Renders uptime statistics.")] public class UptimeCommand : CommandGroup diff --git a/src/CoiniumServ/Server/Commands/Version.cs b/src/CoiniumServ/Server/Commands/Version.cs index f9f34b2b2..ab92b7c3f 100644 --- a/src/CoiniumServ/Server/Commands/Version.cs +++ b/src/CoiniumServ/Server/Commands/Version.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Reflection; -using Coinium.Utils.Commands; +using CoiniumServ.Utils.Commands; -namespace Coinium.Server.Commands +namespace CoiniumServ.Server.Commands { [CommandGroup("version", "Renders software version.")] public class VersionCommand : CommandGroup diff --git a/src/CoiniumServ/Server/IServerFactory.cs b/src/CoiniumServ/Server/IServerFactory.cs index c0f8fb08f..87c857216 100644 --- a/src/CoiniumServ/Server/IServerFactory.cs +++ b/src/CoiniumServ/Server/IServerFactory.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Server.Mining; -using Coinium.Server.Web; -namespace Coinium.Server +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Web; + +namespace CoiniumServ.Server { public interface IServerFactory { diff --git a/src/CoiniumServ/Server/Mining/IMiningServer.cs b/src/CoiniumServ/Server/Mining/IMiningServer.cs index d652f595b..1333af916 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServer.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServer.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Net.Server; -namespace Coinium.Server.Mining +using CoiniumServ.Net.Server; + +namespace CoiniumServ.Server.Mining { /// /// diff --git a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs index 1dc707d5f..e29caa9fd 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Utils.Configuration; +using CoiniumServ.Utils.Configuration; -namespace Coinium.Server.Mining +namespace CoiniumServ.Server.Mining { public interface IServerConfig:IConfig { diff --git a/src/CoiniumServ/Server/Mining/Service/IRpcService.cs b/src/CoiniumServ/Server/Mining/Service/IRpcService.cs index dd410bb9b..5e01a0ca9 100644 --- a/src/CoiniumServ/Server/Mining/Service/IRpcService.cs +++ b/src/CoiniumServ/Server/Mining/Service/IRpcService.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server.Mining.Service +namespace CoiniumServ.Server.Mining.Service { public interface IRpcService { } diff --git a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs index 32c91f836..1bf6362cb 100644 --- a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs @@ -21,10 +21,10 @@ // #endregion -using Coinium.Daemon; -using Coinium.Mining.Shares; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Shares; -namespace Coinium.Server.Mining.Service +namespace CoiniumServ.Server.Mining.Service { public interface IServiceFactory { diff --git a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs index 2bf1d0276..0196c267d 100644 --- a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs @@ -21,12 +21,12 @@ // #endregion -using Coinium.Daemon; -using Coinium.Mining.Shares; -using Coinium.Repository.Context; +using CoiniumServ.Daemon; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Repository.Context; using Nancy.TinyIoc; -namespace Coinium.Server.Mining.Service +namespace CoiniumServ.Server.Mining.Service { public class ServiceFactory : IServiceFactory { diff --git a/src/CoiniumServ/Server/Mining/Service/Services.cs b/src/CoiniumServ/Server/Mining/Service/Services.cs index 091dd6b8b..17660eb58 100644 --- a/src/CoiniumServ/Server/Mining/Service/Services.cs +++ b/src/CoiniumServ/Server/Mining/Service/Services.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server.Mining.Service +namespace CoiniumServ.Server.Mining.Service { public static class Services { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index 89fdd11c9..88c724a6c 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Mining.Vardiff; +using CoiniumServ.Mining.Vardiff; -namespace Coinium.Server.Mining.Stratum.Config +namespace CoiniumServ.Server.Mining.Stratum.Config { public interface IStratumServerConfig : IServerConfig { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index f35bd4a6a..7ce850f3a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Mining.Vardiff; -using Coinium.Server.Mining.Service; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Server.Mining.Service; -namespace Coinium.Server.Mining.Stratum.Config +namespace CoiniumServ.Server.Mining.Stratum.Config { public class StratumServerConfig:IStratumServerConfig { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs index 7d7a0ecd9..299e5d26b 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/AuthenticationError.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs index 51be9bb38..7f14bb95b 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/DuplicateShareError.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs index 9797b084a..e778c2194 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/IStratumError.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { public interface IStratumError { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs index f3ba7723a..c5445506a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/JobNotFoundError.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs index 377ab50d1..2bbeb3d42 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/LowDifficultyShare.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs index e94e99a89..55fd45692 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/NotSubscriberError.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs b/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs index ef3653636..e674da547 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Errors/OtherError.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using AustinHarris.JsonRpc; -namespace Coinium.Server.Mining.Stratum.Errors +namespace CoiniumServ.Server.Mining.Stratum.Errors { // defined in: http://mining.bitcoin.cz/stratum-mining diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index d57caf99e..653543de6 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Mining.Miners; -using Coinium.Mining.Vardiff; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Vardiff; -namespace Coinium.Server.Mining.Stratum +namespace CoiniumServ.Server.Mining.Stratum { public interface IStratumMiner:IMiner, IVardiffMiner { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs index de404937f..5e03dbaba 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace Coinium.Server.Mining.Stratum.Notifications +namespace CoiniumServ.Server.Mining.Stratum.Notifications { // TODO: can we get rid of this? diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs index 7a2ace7fb..7efb2530d 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -using Coinium.Crypto.Algorithms; -using Coinium.Crypto.Merkle; -using Coinium.Daemon.Responses; -using Coinium.Transactions; -using Coinium.Utils.Numerics; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Transactions; +using CoiniumServ.Utils.Numerics; -namespace Coinium.Server.Mining.Stratum.Notifications +namespace CoiniumServ.Server.Mining.Stratum.Notifications { public interface IJob : IEnumerable { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs index 503d261f3..77a1131ef 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs @@ -20,22 +20,23 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections; using System.Collections.Generic; using System.Globalization; -using Coinium.Coin.Coinbase; -using Coinium.Crypto.Algorithms; -using Coinium.Crypto.Merkle; -using Coinium.Daemon.Responses; -using Coinium.Transactions; -using Coinium.Transactions.Utils; -using Coinium.Utils.Extensions; -using Coinium.Utils.Numerics; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Transactions; +using CoiniumServ.Transactions.Utils; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Numerics; using Gibbed.IO; using Newtonsoft.Json; -namespace Coinium.Server.Mining.Stratum.Notifications +namespace CoiniumServ.Server.Mining.Stratum.Notifications { [JsonArray] public class Job : IJob diff --git a/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs b/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs index 78236c256..52c4de143 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Responses/SubscribeResponse.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections; using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json; -namespace Coinium.Server.Mining.Stratum.Responses +namespace CoiniumServ.Server.Mining.Stratum.Responses { [JsonArray] public class SubscribeResponse:IEnumerable diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs index b5ce134ad..c63b70ae1 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs @@ -21,9 +21,9 @@ // #endregion -using Coinium.Mining.Miners; +using CoiniumServ.Mining.Miners; -namespace Coinium.Server.Mining.Stratum.Service +namespace CoiniumServ.Server.Mining.Stratum.Service { public class SocketServiceContext { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs index 6f86345c6..f0f894a7d 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceRequest.cs @@ -23,7 +23,7 @@ using Newtonsoft.Json; -namespace Coinium.Server.Mining.Stratum.Service +namespace CoiniumServ.Server.Mining.Stratum.Service { /// /// JsonRpc 2.0 over sockets request. diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 544046b2b..83dc03058 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -22,12 +22,12 @@ #endregion using AustinHarris.JsonRpc; -using Coinium.Mining.Jobs; -using Coinium.Mining.Shares; -using Coinium.Server.Mining.Service; -using Coinium.Server.Mining.Stratum.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Server.Mining.Stratum.Responses; -namespace Coinium.Server.Mining.Stratum.Service +namespace CoiniumServ.Server.Mining.Stratum.Service { /// /// Stratum protocol implementation. diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index e7eda68c3..62c23e190 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -20,21 +20,22 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Text; using AustinHarris.JsonRpc; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Net.Server.Sockets; -using Coinium.Server.Mining.Stratum.Errors; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Server.Mining.Stratum.Service; -using Coinium.Utils.Buffers; -using Coinium.Utils.Extensions; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Server.Mining.Stratum.Errors; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Server.Mining.Stratum.Service; +using CoiniumServ.Utils.Buffers; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Serilog; -namespace Coinium.Server.Mining.Stratum +namespace CoiniumServ.Server.Mining.Stratum { public class StratumMiner : IClient, IStratumMiner { diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index 644ad3fda..b0da0c021 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Net.Server.Sockets; + +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Sockets; using Serilog; // stratum server uses json-rpc 2.0 (over raw sockets) & json-rpc.net (http://jsonrpc2.codeplex.com/) // classic server handles getwork & getblocktemplate miners over http. -namespace Coinium.Server.Mining.Stratum +namespace CoiniumServ.Server.Mining.Stratum { /// /// Stratum protocol server implementation. diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs index 9cac24aa0..3594f2a7c 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/IVanillaServerConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server.Mining.Vanilla.Config +namespace CoiniumServ.Server.Mining.Vanilla.Config { public interface IVanillaServerConfig : IServerConfig { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs index 6ba4fc3b0..05ffa376d 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Server.Mining.Service; +using CoiniumServ.Server.Mining.Service; -namespace Coinium.Server.Mining.Vanilla.Config +namespace CoiniumServ.Server.Mining.Vanilla.Config { public class VanillaServerConfig : IVanillaServerConfig { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs index ab96bb41f..2171b3d5c 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs @@ -21,9 +21,9 @@ // #endregion -using Coinium.Mining.Miners; +using CoiniumServ.Mining.Miners; -namespace Coinium.Server.Mining.Vanilla.Service +namespace CoiniumServ.Server.Mining.Vanilla.Service { public class HttpServiceContext { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs index 43bae7e7b..88e0236f0 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceRequest.cs @@ -24,7 +24,7 @@ using System.Net; using Newtonsoft.Json; -namespace Coinium.Server.Mining.Vanilla.Service +namespace CoiniumServ.Server.Mining.Vanilla.Service { /// /// JsonRpc 1.0 over http request. diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index a316aecf2..578df0783 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -22,13 +22,13 @@ #endregion using AustinHarris.JsonRpc; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Shares; -using Coinium.Server.Mining.Service; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Server.Mining.Service; using Serilog; -namespace Coinium.Server.Mining.Vanilla.Service +namespace CoiniumServ.Server.Mining.Vanilla.Service { /// /// Stratum protocol implementation. diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 7183ddefd..3df77b4d2 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -20,19 +20,20 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; using System.Net; using System.Text; using AustinHarris.JsonRpc; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Server.Mining.Vanilla.Service; -using Coinium.Utils.Extensions; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Server.Mining.Vanilla.Service; +using CoiniumServ.Utils.Extensions; using Serilog; -namespace Coinium.Server.Mining.Vanilla +namespace CoiniumServ.Server.Mining.Vanilla { public class VanillaMiner : IMiner { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index 21ebce8f7..1a3802769 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Net; -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Net.Server.Http.Basic; // classic server uses json-rpc 1.0 (over http) & json-rpc.net (http://jsonrpc2.codeplex.com/) +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Http.Basic; -namespace Coinium.Server.Mining.Vanilla +namespace CoiniumServ.Server.Mining.Vanilla { public class VanillaServer : HttpServer, IMiningServer { diff --git a/src/CoiniumServ/Server/ServerFactory.cs b/src/CoiniumServ/Server/ServerFactory.cs index f94a0f8f3..0433a9321 100644 --- a/src/CoiniumServ/Server/ServerFactory.cs +++ b/src/CoiniumServ/Server/ServerFactory.cs @@ -20,17 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Net.Server; -using Coinium.Repository.Context; -using Coinium.Server.Mining; -using Coinium.Server.Web; + +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Web; using Nancy.TinyIoc; -using Serilog; -namespace Coinium.Server +namespace CoiniumServ.Server { public class ServerFactory : IServerFactory { diff --git a/src/CoiniumServ/Server/Servers.cs b/src/CoiniumServ/Server/Servers.cs index 7a7ee34f2..e50f61704 100644 --- a/src/CoiniumServ/Server/Servers.cs +++ b/src/CoiniumServ/Server/Servers.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server +namespace CoiniumServ.Server { public class Servers { diff --git a/src/CoiniumServ/Server/Web/IWebServer.cs b/src/CoiniumServ/Server/Web/IWebServer.cs index e3012f866..22f3aa33e 100644 --- a/src/CoiniumServ/Server/Web/IWebServer.cs +++ b/src/CoiniumServ/Server/Web/IWebServer.cs @@ -20,10 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Net.Server; -using Coinium.Server.Mining; -namespace Coinium.Server.Web +using CoiniumServ.Net.Server; + +namespace CoiniumServ.Server.Web { public interface IWebServer: IServer { diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index 1bffdb9cf..a09196924 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Server.Web +namespace CoiniumServ.Server.Web { public interface IWebServerConfig { diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index aab9e2948..b41e2d56d 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -21,14 +21,13 @@ // #endregion -using System.Dynamic; -using Coinium.Mining.Pools; -using Coinium.Mining.Pools.Statistics; -using Coinium.Server.Web.Modules.Models; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Server.Web.Modules.Models; using Nancy; using Newtonsoft.Json; -namespace Coinium.Server.Web.Modules +namespace CoiniumServ.Server.Web.Modules { public class ApiModule: NancyModule { diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index 0816661bf..6af90f436 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Mining.Pools; -using Coinium.Mining.Pools.Statistics; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Statistics; using Nancy; -namespace Coinium.Server.Web.Modules +namespace CoiniumServ.Server.Web.Modules { public class IndexModule : NancyModule { diff --git a/src/CoiniumServ/Server/Web/Modules/Models/Error.cs b/src/CoiniumServ/Server/Web/Modules/Models/Error.cs index dd460024d..3140a3f19 100644 --- a/src/CoiniumServ/Server/Web/Modules/Models/Error.cs +++ b/src/CoiniumServ/Server/Web/Modules/Models/Error.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Server.Web.Modules.Models +namespace CoiniumServ.Server.Web.Modules.Models { public class Error { diff --git a/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs b/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs index a8f50fce1..0610ae5c2 100644 --- a/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs +++ b/src/CoiniumServ/Server/Web/Modules/Models/JsonError.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Server.Web.Modules.Models +namespace CoiniumServ.Server.Web.Modules.Models { public class JsonError { diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index 3607a1bf7..afc63aa17 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools; -using Coinium.Server.Web.Modules.Models; + +using CoiniumServ.Mining.Pools; +using CoiniumServ.Server.Web.Modules.Models; using Nancy; -namespace Coinium.Server.Web.Modules +namespace CoiniumServ.Server.Web.Modules { public class PoolModule : NancyModule { diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index beff42fe7..8ea8f7f8c 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Mining.Pools; -using Coinium.Net.Server.Http.Web; -using Coinium.Repository.Context; -using Coinium.Utils.Configuration; -namespace Coinium.Server.Web +using CoiniumServ.Mining.Pools; +using CoiniumServ.Net.Server.Http.Web; +using CoiniumServ.Repository.Context; +using CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Server.Web { public class WebServer : HttpServer, IWebServer { diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index 077c46ce2..e175bd542 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Server.Web +namespace CoiniumServ.Server.Web { public class WebServerConfig : IWebServerConfig { diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 4c2770ffe..183509a36 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -20,21 +20,22 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Coinium.Coin.Coinbase; -using Coinium.Crypto; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Mining.Pools.Config; -using Coinium.Transactions.Script; -using Coinium.Utils.Helpers.Time; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Crypto; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Transactions.Script; +using CoiniumServ.Utils.Helpers.Time; using Gibbed.IO; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { /// /// A generation transaction. diff --git a/src/CoiniumServ/Transactions/IGenerationTransaction.cs b/src/CoiniumServ/Transactions/IGenerationTransaction.cs index bdebff3ff..a5cd155c3 100644 --- a/src/CoiniumServ/Transactions/IGenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/IGenerationTransaction.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { public interface IGenerationTransaction { diff --git a/src/CoiniumServ/Transactions/IOutputs.cs b/src/CoiniumServ/Transactions/IOutputs.cs index b60755431..225c6e822 100644 --- a/src/CoiniumServ/Transactions/IOutputs.cs +++ b/src/CoiniumServ/Transactions/IOutputs.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { public interface IOutputs { diff --git a/src/CoiniumServ/Transactions/OutPoint.cs b/src/CoiniumServ/Transactions/OutPoint.cs index 9d06cf75c..e3a2651b3 100644 --- a/src/CoiniumServ/Transactions/OutPoint.cs +++ b/src/CoiniumServ/Transactions/OutPoint.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Crypto; +using CoiniumServ.Crypto; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { /// /// Structure: https://en.bitcoin.it/wiki/Protocol_specification#tx diff --git a/src/CoiniumServ/Transactions/Outputs.cs b/src/CoiniumServ/Transactions/Outputs.cs index 5395d0d0d..e230296cd 100644 --- a/src/CoiniumServ/Transactions/Outputs.cs +++ b/src/CoiniumServ/Transactions/Outputs.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Coinium.Coin.Address.Exceptions; -using Coinium.Coin.Coinbase; -using Coinium.Daemon; +using CoiniumServ.Coin.Address.Exceptions; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Daemon; using Gibbed.IO; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { public class Outputs : IOutputs { diff --git a/src/CoiniumServ/Transactions/Script/ISignatureScript.cs b/src/CoiniumServ/Transactions/Script/ISignatureScript.cs index 45b7b08b5..ff320685a 100644 --- a/src/CoiniumServ/Transactions/Script/ISignatureScript.cs +++ b/src/CoiniumServ/Transactions/Script/ISignatureScript.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Transactions.Script +namespace CoiniumServ.Transactions.Script { public interface ISignatureScript { diff --git a/src/CoiniumServ/Transactions/Script/SignatureScript.cs b/src/CoiniumServ/Transactions/Script/SignatureScript.cs index 970fe932f..844e187a8 100644 --- a/src/CoiniumServ/Transactions/Script/SignatureScript.cs +++ b/src/CoiniumServ/Transactions/Script/SignatureScript.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.IO; -using Coinium.Coin.Coinbase; -using Coinium.Transactions.Utils; -using Coinium.Utils.Extensions; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Transactions.Utils; +using CoiniumServ.Utils.Extensions; using Gibbed.IO; -namespace Coinium.Transactions.Script +namespace CoiniumServ.Transactions.Script { public class SignatureScript : ISignatureScript { diff --git a/src/CoiniumServ/Transactions/TxIn.cs b/src/CoiniumServ/Transactions/TxIn.cs index d7c9eabbe..6f547c45e 100644 --- a/src/CoiniumServ/Transactions/TxIn.cs +++ b/src/CoiniumServ/Transactions/TxIn.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Transactions.Script; +using CoiniumServ.Transactions.Script; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { /// /// Inputs for transaction. diff --git a/src/CoiniumServ/Transactions/TxOut.cs b/src/CoiniumServ/Transactions/TxOut.cs index fdb283ac2..f974f3666 100644 --- a/src/CoiniumServ/Transactions/TxOut.cs +++ b/src/CoiniumServ/Transactions/TxOut.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Transactions +namespace CoiniumServ.Transactions { /// /// Outpus for transaction. diff --git a/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs b/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs index 21f5ec69b..f47ff3eb2 100644 --- a/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs +++ b/src/CoiniumServ/Transactions/Utils/TransactionUtils.cs @@ -20,14 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Coin.Coinbase; -using Coinium.Daemon.Responses; -using Coinium.Utils.Extensions; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Utils.Extensions; -namespace Coinium.Transactions.Utils +namespace CoiniumServ.Transactions.Utils { public static class TransactionUtils { diff --git a/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs b/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs index 1f0901473..f41440147 100644 --- a/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs +++ b/src/CoiniumServ/Utils/Buffers/IRingBuffer.cs @@ -21,7 +21,7 @@ // #endregion -namespace Coinium.Utils.Buffers +namespace CoiniumServ.Utils.Buffers { public interface IRingBuffer { diff --git a/src/CoiniumServ/Utils/Buffers/RingBuffer.cs b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs index c31a18369..3831498c1 100644 --- a/src/CoiniumServ/Utils/Buffers/RingBuffer.cs +++ b/src/CoiniumServ/Utils/Buffers/RingBuffer.cs @@ -23,7 +23,7 @@ using System.Linq; -namespace Coinium.Utils.Buffers +namespace CoiniumServ.Utils.Buffers { public class RingBuffer:IRingBuffer { diff --git a/src/CoiniumServ/Utils/Commands/CommandAttributes.cs b/src/CoiniumServ/Utils/Commands/CommandAttributes.cs index 022c775dd..3c8ddbbaa 100644 --- a/src/CoiniumServ/Utils/Commands/CommandAttributes.cs +++ b/src/CoiniumServ/Utils/Commands/CommandAttributes.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Utils.Commands +namespace CoiniumServ.Utils.Commands { /// /// Marks a class as an command group. diff --git a/src/CoiniumServ/Utils/Commands/CommandGroup.cs b/src/CoiniumServ/Utils/Commands/CommandGroup.cs index 0ee199cdd..15a4b0098 100644 --- a/src/CoiniumServ/Utils/Commands/CommandGroup.cs +++ b/src/CoiniumServ/Utils/Commands/CommandGroup.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; using System.Linq; using System.Reflection; using Serilog; -namespace Coinium.Utils.Commands +namespace CoiniumServ.Utils.Commands { public class CommandGroup { diff --git a/src/CoiniumServ/Utils/Commands/CommandManager.cs b/src/CoiniumServ/Utils/Commands/CommandManager.cs index 5bb9bd663..a43d93ffd 100644 --- a/src/CoiniumServ/Utils/Commands/CommandManager.cs +++ b/src/CoiniumServ/Utils/Commands/CommandManager.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Serilog; -namespace Coinium.Utils.Commands +namespace CoiniumServ.Utils.Commands { public static class CommandManager { diff --git a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs index 3c2276df7..4bac7f765 100644 --- a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Persistance.Redis; -using Coinium.Repository.Context; -using Coinium.Server.Web; -namespace Coinium.Utils.Configuration +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Web; + +namespace CoiniumServ.Utils.Configuration { public class GlobalConfigFactory : IGlobalConfigFactory { diff --git a/src/CoiniumServ/Utils/Configuration/IConfig.cs b/src/CoiniumServ/Utils/Configuration/IConfig.cs index 7dfb9605b..cf7655acb 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfig.cs +++ b/src/CoiniumServ/Utils/Configuration/IConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Utils.Configuration +namespace CoiniumServ.Utils.Configuration { public interface IConfig { diff --git a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs index 900f48db6..839dc110d 100644 --- a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs @@ -21,11 +21,10 @@ // #endregion -using Coinium.Mining.Vardiff; -using Coinium.Persistance.Redis; -using Coinium.Server.Web; +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Server.Web; -namespace Coinium.Utils.Configuration +namespace CoiniumServ.Utils.Configuration { public interface IGlobalConfigFactory { diff --git a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs b/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs index 688cfe1bc..3363f28f3 100644 --- a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs +++ b/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using JsonConfig; using Serilog; -namespace Coinium.Utils.Configuration +namespace CoiniumServ.Utils.Configuration { public static class JsonConfigReader { diff --git a/src/CoiniumServ/Utils/ConsoleWindow.cs b/src/CoiniumServ/Utils/ConsoleWindow.cs index 6093f198b..09119233f 100644 --- a/src/CoiniumServ/Utils/ConsoleWindow.cs +++ b/src/CoiniumServ/Utils/ConsoleWindow.cs @@ -23,7 +23,7 @@ using System; -namespace Coinium.Utils +namespace CoiniumServ.Utils { /// /// Utility class to handle console window stuff. diff --git a/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs b/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs index 8d3a089a9..be5a90a36 100644 --- a/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/ArrayExtensions.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.IO; using System.Linq; using Gibbed.IO; -namespace Coinium.Utils.Extensions +namespace CoiniumServ.Utils.Extensions { public static class ArrayExtensions { diff --git a/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs b/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs index c4d8bac93..79d44d867 100644 --- a/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/EnumerableExtensions.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; using System.Text; -namespace Coinium.Utils.Extensions +namespace CoiniumServ.Utils.Extensions { public static class EnumerableExtensions { diff --git a/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs b/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs index bc537e65c..418f50cb1 100644 --- a/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/JsonExtensions.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Text; -namespace Coinium.Utils.Extensions +namespace CoiniumServ.Utils.Extensions { /// /// Utility class to format a given JSON string so it is more readable and nicely indented. diff --git a/src/CoiniumServ/Utils/Extensions/StringExtensions.cs b/src/CoiniumServ/Utils/Extensions/StringExtensions.cs index 46c1dfcc5..276568a28 100644 --- a/src/CoiniumServ/Utils/Extensions/StringExtensions.cs +++ b/src/CoiniumServ/Utils/Extensions/StringExtensions.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Utils.Extensions +namespace CoiniumServ.Utils.Extensions { public static class StringExtensions { diff --git a/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs b/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs index 59cd46fed..e4002b26b 100644 --- a/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/Arrays/ArrayHelpers.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Utils.Helpers.Arrays +namespace CoiniumServ.Utils.Helpers.Arrays { public static class ArrayHelpers { diff --git a/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs b/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs index be375a9d7..48cc509fd 100644 --- a/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/IO/FileHelpers.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -namespace Coinium.Utils.Helpers.IO +namespace CoiniumServ.Utils.Helpers.IO { public static class FileHelpers { diff --git a/src/CoiniumServ/Utils/Helpers/Misc/Range.cs b/src/CoiniumServ/Utils/Helpers/Misc/Range.cs index eedf52c50..21b596879 100644 --- a/src/CoiniumServ/Utils/Helpers/Misc/Range.cs +++ b/src/CoiniumServ/Utils/Helpers/Misc/Range.cs @@ -20,10 +20,11 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections; using System.Collections.Generic; -namespace Coinium.Utils.Helpers.Misc +namespace CoiniumServ.Utils.Helpers.Misc { /// /// Port of python's range from diff --git a/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs b/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs index 425076f49..9235e7141 100644 --- a/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs +++ b/src/CoiniumServ/Utils/Helpers/Time/TimeHelpers.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Utils.Helpers.Time +namespace CoiniumServ.Utils.Helpers.Time { public static class TimeHelpers { diff --git a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs index 03735a38b..fe88f9a9d 100644 --- a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs +++ b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq.Expressions; -namespace Coinium.Utils.Helpers.Validation +namespace CoiniumServ.Utils.Helpers.Validation { /// /// The enforce. diff --git a/src/CoiniumServ/Utils/Logging.cs b/src/CoiniumServ/Utils/Logging.cs index b2d352122..c5dc6f252 100644 --- a/src/CoiniumServ/Utils/Logging.cs +++ b/src/CoiniumServ/Utils/Logging.cs @@ -29,7 +29,7 @@ using Serilog.Core; using Serilog.Events; -namespace Coinium.Utils +namespace CoiniumServ.Utils { /// /// Controls the logging facilities. diff --git a/src/CoiniumServ/Utils/Numerics/BigInteger.cs b/src/CoiniumServ/Utils/Numerics/BigInteger.cs index 4a2e7805c..6d736c5de 100644 --- a/src/CoiniumServ/Utils/Numerics/BigInteger.cs +++ b/src/CoiniumServ/Utils/Numerics/BigInteger.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Globalization; @@ -41,7 +42,7 @@ Optimize BitScanBackward Schoolbook multiply is O(n^2), use Karatsuba /Toom-3 for large numbers */ -namespace Coinium.Utils.Numerics +namespace CoiniumServ.Utils.Numerics { // // System.Numerics.BigInteger diff --git a/src/CoiniumServ/Utils/Numerics/BigRational.cs b/src/CoiniumServ/Utils/Numerics/BigRational.cs index 73c4e8fa7..1eef9f8cf 100644 --- a/src/CoiniumServ/Utils/Numerics/BigRational.cs +++ b/src/CoiniumServ/Utils/Numerics/BigRational.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Globalization; using System.Runtime.InteropServices; @@ -27,7 +28,7 @@ using System.Security.Permissions; using System.Text; -namespace Coinium.Utils.Numerics +namespace CoiniumServ.Utils.Numerics { /* Most mono versions doesn't include a proper BigInteger implementation, so we just include one that's complete from the latest mono repository diff --git a/src/CoiniumServ/Utils/Platform/Framework.cs b/src/CoiniumServ/Utils/Platform/Framework.cs index fcd1430b4..1d7ab1fa3 100644 --- a/src/CoiniumServ/Utils/Platform/Framework.cs +++ b/src/CoiniumServ/Utils/Platform/Framework.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Utils.Platform +namespace CoiniumServ.Utils.Platform { /// /// .Net frameworks. diff --git a/src/CoiniumServ/Utils/Platform/PlatformManager.cs b/src/CoiniumServ/Utils/Platform/PlatformManager.cs index 3248a7850..584dd2975 100644 --- a/src/CoiniumServ/Utils/Platform/PlatformManager.cs +++ b/src/CoiniumServ/Utils/Platform/PlatformManager.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -namespace Coinium.Utils.Platform +namespace CoiniumServ.Utils.Platform { /// /// Platform Manager that identifies platforms & manages them. diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index f011fa720..84eb42df9 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace Coinium.Utils.Versions +namespace CoiniumServ.Utils.Versions { /// /// Supported Versions Info. diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index 1fc3c2416..54c82ef12 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -1,5 +1,5 @@ -@using Coinium.Coin.Helpers -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@using CoiniumServ.Coin.Helpers +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 70da3e96d..e518ea735 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -1,10 +1,8 @@ @using System @using System.Linq -@using Coinium.Coin.Helpers -@using Coinium.Daemon.Responses -@using Coinium.Persistance -@using Coinium.Persistance.Blocks -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@using CoiniumServ.Coin.Helpers +@using CoiniumServ.Persistance.Blocks +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } diff --git a/src/Tests/Coin/AmountTests.cs b/src/Tests/Coin/AmountTests.cs index b97794ef3..f78d39901 100644 --- a/src/Tests/Coin/AmountTests.cs +++ b/src/Tests/Coin/AmountTests.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Coin.Helpers; + +using CoiniumServ.Coin.Helpers; using Should.Fluent; using Xunit; -namespace Tests.Coin +namespace CoiniumServ.Tests.Coin { public class AmountTests { diff --git a/src/Tests/Coin/Base58Test.cs b/src/Tests/Coin/Base58Test.cs index 1c771a3ad..ed44f27ee 100644 --- a/src/Tests/Coin/Base58Test.cs +++ b/src/Tests/Coin/Base58Test.cs @@ -20,15 +20,16 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Text; -using Coinium.Coin.Address; -using Coinium.Coin.Address.Exceptions; +using CoiniumServ.Coin.Address; +using CoiniumServ.Coin.Address.Exceptions; using Org.BouncyCastle.Math; using Should.Fluent; using Xunit; -namespace Tests.Coin +namespace CoiniumServ.Tests.Coin { public class Base58Test { diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index af3f04ec9..bece1ef84 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -20,19 +20,20 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Coin.Coinbase; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Mining.Pools.Config; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Transactions; -using Coinium.Transactions.Script; -using Coinium.Utils.Extensions; +using CoiniumServ.Coin.Coinbase; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Transactions; +using CoiniumServ.Transactions.Script; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using NSubstitute; using Should.Fluent; @@ -95,7 +96,7 @@ 2014-06-25 13:24:04 [Pool] [litecoin] (Thread 1) Block found: e242093d92f4c98bfd5dd1f9f6489652d1165f5ce4eed1f28747d2b8e3efd8b6 */ -namespace Tests.Coin.Coinbase +namespace CoiniumServ.Tests.Coin.Coinbase { public class SerializerTests { @@ -190,7 +191,7 @@ public void SerializeHeaderTest() // create the coinbase. var coinbase = Serializers.SerializeCoinbase(_job, extraNonce1, extraNonce2); - var coinbaseHash = Coinium.Coin.Coinbase.Utils.HashCoinbase(coinbase); + var coinbaseHash = CoiniumServ.Coin.Coinbase.Utils.HashCoinbase(coinbase); // create the merkle root. var merkleRoot = _job.MerkleTree.WithFirst(coinbaseHash).ReverseBuffer(); @@ -212,7 +213,7 @@ public void SerializeBlockTest() // create the coinbase. var coinbase = Serializers.SerializeCoinbase(_job, extraNonce1, extraNonce2); - var coinbaseHash = Coinium.Coin.Coinbase.Utils.HashCoinbase(coinbase); + var coinbaseHash = CoiniumServ.Coin.Coinbase.Utils.HashCoinbase(coinbase); // create the merkle root. var merkleRoot = _job.MerkleTree.WithFirst(coinbaseHash).ReverseBuffer(); diff --git a/src/Tests/Coin/Coinbase/UtilsTests.cs b/src/Tests/Coin/Coinbase/UtilsTests.cs index a31f8810a..102c9deb4 100644 --- a/src/Tests/Coin/Coinbase/UtilsTests.cs +++ b/src/Tests/Coin/Coinbase/UtilsTests.cs @@ -20,11 +20,8 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Coin.Coinbase; -using Should.Fluent; -using Xunit; -namespace Tests.Coin.Coinbase +namespace CoiniumServ.Tests.Coin.Coinbase { public class UtilsTests { diff --git a/src/Tests/Crypto/Merkle/MerkleRootTests.cs b/src/Tests/Crypto/Merkle/MerkleRootTests.cs index 878d67bb9..bdc015efc 100644 --- a/src/Tests/Crypto/Merkle/MerkleRootTests.cs +++ b/src/Tests/Crypto/Merkle/MerkleRootTests.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Crypto.Merkle; -using Coinium.Utils.Extensions; +using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Utils.Extensions; using Should.Fluent; using Xunit; -namespace Tests.Crypto.Merkle +namespace CoiniumServ.Tests.Crypto.Merkle { public class MerkleRootTests { diff --git a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs b/src/Tests/Crypto/Merkle/MerkleTreeTests.cs index c882027f5..4cfe3d58b 100644 --- a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs +++ b/src/Tests/Crypto/Merkle/MerkleTreeTests.cs @@ -20,17 +20,18 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Linq; -using Coinium.Crypto.Merkle; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Transactions.Utils; -using Coinium.Utils.Extensions; +using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Transactions.Utils; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Should.Fluent; using Xunit; -namespace Tests.Crypto.Merkle +namespace CoiniumServ.Tests.Crypto.Merkle { public class MerkleTreeTests { diff --git a/src/Tests/Daemon/BlockTemplateTests.cs b/src/Tests/Daemon/BlockTemplateTests.cs index 81d4ec0a1..217dcca5c 100644 --- a/src/Tests/Daemon/BlockTemplateTests.cs +++ b/src/Tests/Daemon/BlockTemplateTests.cs @@ -20,9 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Collections.Generic; -using Coinium.Daemon; -using Coinium.Daemon.Responses; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; using Newtonsoft.Json; using Should.Fluent; using Xunit; @@ -71,7 +72,7 @@ } */ -namespace Tests.Daemon +namespace CoiniumServ.Tests.Daemon { public class BlockTemplateTests { diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 8c86866c6..7418116fe 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -20,27 +20,29 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Pools.Statistics; -using Coinium.Mining.Shares; -using Coinium.Mining.Vardiff; -using Coinium.Payments; -using Coinium.Persistance; -using Coinium.Server; -using Coinium.Server.Mining; -using Coinium.Server.Mining.Service; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Payments; +using CoiniumServ.Persistance; +using CoiniumServ.Server; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Service; using NSubstitute; using Should.Fluent; using Xunit; -namespace Tests.Mining.Pools +namespace CoiniumServ.Tests.Mining.Pools { public class PoolTests { @@ -106,7 +108,7 @@ public PoolTests() [Fact] public void ConstructorTest_NonNullParams_ShouldSucceed() { - var pool = new Coinium.Mining.Pools.Pool( + var pool = new Pool( _hashAlgorithmFactory, _serverFactory, _serviceFactory, @@ -131,7 +133,7 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() [Fact] public void InitializationTest_NonNullParams_ShouldSuccess() { - var pool = new Coinium.Mining.Pools.Pool( + var pool = new Pool( _hashAlgorithmFactory, _serverFactory, _serviceFactory, diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index c7c283939..a25eef841 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -20,32 +20,30 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Coin.Config; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Mining.Jobs.Manager; -using Coinium.Mining.Jobs.Tracker; -using Coinium.Mining.Miners; -using Coinium.Mining.Pools; -using Coinium.Mining.Pools.Config; -using Coinium.Mining.Shares; -using Coinium.Server.Mining.Stratum; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Transactions; -using Coinium.Transactions.Script; -using Coinium.Utils.Extensions; -using Coinium.Utils.Numerics; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Transactions; +using CoiniumServ.Transactions.Script; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Numerics; using Newtonsoft.Json; using NSubstitute; using Should.Fluent; using Xunit; -namespace Tests.Mining.Shares +namespace CoiniumServ.Tests.Mining.Shares { public class ShareTests { diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index d7bb47e56..8d9d73cee 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -20,21 +20,22 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Crypto.Algorithms; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Mining.Pools.Config; -using Coinium.Server.Mining.Stratum.Notifications; -using Coinium.Transactions; -using Coinium.Transactions.Script; -using Should.Fluent; -using Xunit; +using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Transactions; +using CoiniumServ.Transactions.Script; using Newtonsoft.Json; using NSubstitute; +using Should.Fluent; +using Xunit; /* sample data previousblockhash: 22a9174d9db64f1919febc9577167764c301b755768b675291f7d34454561e9e previousblockhashreversed: 54561e9e91f7d344768b6752c301b7557716776419febc959db64f1922a9174d @@ -82,7 +83,7 @@ ] */ -namespace Tests.Server.Stratum.Notifications +namespace CoiniumServ.Tests.Server.Stratum.Notifications { public class JobTests { diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index a6c06f26d..7a436b161 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -7,7 +7,7 @@ {73CE2C0A-12E6-42FD-8021-C75827D014E3} Library Properties - Tests + CoiniumServ.Tests CoiniumServ.Tests v4.5 512 diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index ce3bfec0b..15cadd299 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -20,16 +20,17 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Collections.Generic; using System.Linq; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Mining.Pools.Config; -using Coinium.Transactions; -using Coinium.Transactions.Script; -using Coinium.Utils.Extensions; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Transactions; +using CoiniumServ.Transactions.Script; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using NSubstitute; using Should.Fluent; @@ -68,7 +69,7 @@ p2: 0d2f6e6f64655374726174756d2f000000000280010b27010000001976a914329035234168b8da5af106ceb20560401236849888ac80f0fa02000000001976a9147d576fbfca48b899dc750167dd2a2a6572fff49588ac00000000 */ -namespace Tests.Transactions +namespace CoiniumServ.Tests.Transactions { public class GenerationTransactionTests { diff --git a/src/Tests/Transactions/OutputsTests.cs b/src/Tests/Transactions/OutputsTests.cs index b9fd29a9e..54188e32b 100644 --- a/src/Tests/Transactions/OutputsTests.cs +++ b/src/Tests/Transactions/OutputsTests.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; using System.Linq; -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Transactions; -using Coinium.Utils.Extensions; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Transactions; +using CoiniumServ.Utils.Extensions; using NSubstitute; using Should.Fluent; using Xunit; @@ -43,7 +44,7 @@ outputTransactions: 0280010b27010000001976a914329035234168b8da5af106ceb20560401236849888ac80f0fa02000000001976a9147d576fbfca48b899dc750167dd2a2a6572fff49588ac */ -namespace Tests.Transactions +namespace CoiniumServ.Tests.Transactions { public class OutputsTests { diff --git a/src/Tests/Transactions/Script/SignatureScriptTests.cs b/src/Tests/Transactions/Script/SignatureScriptTests.cs index 1408985d2..5267397bc 100644 --- a/src/Tests/Transactions/Script/SignatureScriptTests.cs +++ b/src/Tests/Transactions/Script/SignatureScriptTests.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Daemon; -using Coinium.Daemon.Responses; -using Coinium.Mining.Jobs; -using Coinium.Transactions.Script; -using Coinium.Utils.Extensions; + +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Jobs; +using CoiniumServ.Transactions.Script; +using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Should.Fluent; using Xunit; @@ -40,7 +41,7 @@ scriptSigPart2: /nodeStratum/ serialized: 0d2f6e6f64655374726174756d2f */ -namespace Tests.Transactions.Script +namespace CoiniumServ.Tests.Transactions.Script { public class SignatureScriptTests { diff --git a/src/Tests/Transactions/Utils/TransactionUtilsTests.cs b/src/Tests/Transactions/Utils/TransactionUtilsTests.cs index 74f94528e..237ebb4dc 100644 --- a/src/Tests/Transactions/Utils/TransactionUtilsTests.cs +++ b/src/Tests/Transactions/Utils/TransactionUtilsTests.cs @@ -20,13 +20,14 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System; -using Coinium.Transactions.Utils; -using Coinium.Utils.Extensions; +using CoiniumServ.Transactions.Utils; +using CoiniumServ.Utils.Extensions; using Should.Fluent; using Xunit; -namespace Tests.Transactions.Utils +namespace CoiniumServ.Tests.Transactions.Utils { public class TransactionUtilsTests { diff --git a/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs b/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs index 34bf18736..3268b4dce 100644 --- a/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs +++ b/src/Tests/Utils/Extensions/ArrayExtensionsTests.cs @@ -20,12 +20,13 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + using System.Linq; -using Coinium.Utils.Extensions; +using CoiniumServ.Utils.Extensions; using Should.Fluent; using Xunit; -namespace Tests.Utils.Extensions +namespace CoiniumServ.Tests.Utils.Extensions { public class ArrayExtensionsTests { diff --git a/src/Tests/Utils/Extensions/StringExtensionsTests.cs b/src/Tests/Utils/Extensions/StringExtensionsTests.cs index 7a4213d10..136523ac8 100644 --- a/src/Tests/Utils/Extensions/StringExtensionsTests.cs +++ b/src/Tests/Utils/Extensions/StringExtensionsTests.cs @@ -20,11 +20,12 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -using Coinium.Utils.Extensions; + +using CoiniumServ.Utils.Extensions; using Should.Fluent; using Xunit; -namespace Tests.Utils.Extensions +namespace CoiniumServ.Tests.Utils.Extensions { public class StringExtensionsTests { From 437d49fe68b6cac6961e878d97f696a2a196399f Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 13:22:10 +0300 Subject: [PATCH 075/230] Multiple pools fix. --- src/CoiniumServ/Mining/Pools/Pool.cs | 4 ++-- src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs | 5 +++-- src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs | 5 ++++- .../Server/Mining/Stratum/Service/StratumService.cs | 4 +++- .../Server/Mining/Vanilla/Service/VanillaService.cs | 4 +++- src/Tests/Mining/Pools/PoolTests.cs | 2 +- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 3b7186c8d..6589f72a5 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -200,7 +200,7 @@ private void InitServers() if (Config.Stratum != null) { var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager); - var stratumService = _serviceFactory.Get("Stratum", _shareManager, _daemonClient); + var stratumService = _serviceFactory.Get("Stratum", Config.Coin, _shareManager, _daemonClient); stratumServer.Initialize(Config.Stratum); _servers.Add(stratumServer, stratumService); @@ -209,7 +209,7 @@ private void InitServers() if (Config.Vanilla != null) { var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager); - var vanillaService = _serviceFactory.Get("Vanilla", _shareManager, _daemonClient); + var vanillaService = _serviceFactory.Get("Vanilla", Config.Coin, _shareManager, _daemonClient); vanillaServer.Initialize(Config.Vanilla); diff --git a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs index 1bf6362cb..b8b798213 100644 --- a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Mining.Shares; @@ -32,10 +33,10 @@ public interface IServiceFactory /// Gets the specified service name. /// /// Name of the service. - /// The job manager. + /// /// The share manager. /// The daemon client. /// - IRpcService Get(string serviceName, IShareManager shareManager, IDaemonClient daemonClient); + IRpcService Get(string serviceName, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient); } } diff --git a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs index 0196c267d..16187d1f3 100644 --- a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs +++ b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Mining.Shares; using CoiniumServ.Repository.Context; @@ -47,13 +48,15 @@ public ServiceFactory(IApplicationContext applicationContext) /// Gets the specified service name. /// /// Name of the service. + /// /// The share manager. /// The daemon client. /// - public IRpcService Get(string serviceName, IShareManager shareManager, IDaemonClient daemonClient) + public IRpcService Get(string serviceName, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient) { var @params = new NamedParameterOverloads { + {"coinConfig", coinConfig}, {"shareManager", shareManager}, {"daemonClient", daemonClient} }; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 83dc03058..5fee9ce3c 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -22,6 +22,7 @@ #endregion using AustinHarris.JsonRpc; +using CoiniumServ.Coin.Config; using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Shares; using CoiniumServ.Server.Mining.Service; @@ -36,7 +37,8 @@ public class StratumService : JsonRpcService, IRpcService { private readonly IShareManager _shareManager; - public StratumService(IShareManager shareManager) + public StratumService(ICoinConfig coinConfig, IShareManager shareManager): + base(string.Format("stratum-{0}", coinConfig.Name)) { _shareManager = shareManager; } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index 578df0783..ac905a190 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -22,6 +22,7 @@ #endregion using AustinHarris.JsonRpc; +using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Shares; @@ -39,7 +40,8 @@ public class VanillaService : JsonRpcService, IRpcService private readonly IShareManager _shareManager; - public VanillaService(IShareManager shareManager, IDaemonClient daemonClient) + public VanillaService(ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient): + base(string.Format("vanilla-{0}", coinConfig.Name)) { _daemonClient = daemonClient; _shareManager = shareManager; diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 7418116fe..cbdd42432 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -194,7 +194,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager).Returns(_miningServer); // init service - _serviceFactory.Get(Services.Stratum, _shareManager, _daemonClient).Returns(_rpcService); + _serviceFactory.Get(Services.Stratum, poolConfig.Coin, _shareManager, _daemonClient).Returns(_rpcService); // initalize the server. _miningServer.Initialize(poolConfig.Stratum); From ff247bfe821ef105a3ce4f1b5ff1e1d4c7f0370c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 16:40:24 +0300 Subject: [PATCH 076/230] Fixed the issue with multiple pools running together. --- src/CoiniumServ/Mining/Miners/MinerManager.cs | 2 +- src/CoiniumServ/Mining/Shares/ShareManager.cs | 8 ++++---- src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs | 2 +- .../Server/Mining/Stratum/Service/StratumService.cs | 2 +- src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index 23a00bf2e..a15c621f0 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -98,7 +98,7 @@ public void Authenticate(IMiner miner) { miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; - Log.ForContext().Information(miner.Authenticated ? "Authenticated miner: {0} [{1}]" : "Unauthenticated miner: {0} [{1}]", + Log.ForContext().Information(miner.Authenticated ? "Authenticated miner: {0:l} [{1:l}]" : "Unauthenticated miner: {0:l} [{1:l}]", miner.Username, ((IClient) miner).Connection.RemoteEndPoint); if (miner.Authenticated) // if miner authenticated successfully. diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 3c2faa62a..1532912b4 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -146,15 +146,15 @@ private bool SubmitBlock(Share share) Log.ForContext() .Information( isAccepted - ? "Found block [{0}] with hash: {1}." - : "Submitted block [{0}] but got denied: {1}.", + ? "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) { - Log.ForContext().Error(e, "Submit block failed - height: {0}, hash: {1}", share.Height, share.BlockHash); + Log.ForContext().Error(e, "Submit block failed - height: {0}, hash: {1:l}", share.Height, share.BlockHash); return false; } } @@ -169,7 +169,7 @@ private bool CheckIfBlockAccepted(Share share) } catch (Exception e) { - Log.ForContext().Error(e, "Get block failed - height: {0}, hash: {1}", share.Height, share.BlockHash); + Log.ForContext().Error(e, "Get block failed - height: {0}, hash: {1:l}", share.Height, share.BlockHash); return false; } } diff --git a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index e0ca37d00..e8e2f8dcc 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -59,7 +59,7 @@ public HttpServer(IApplicationContext applicationContext) public bool Start() { var uri = new Uri(string.Format("http://{0}:{1}", BindIP, Port)); - Log.ForContext().Information("Web-server listening on: {0}", uri); + Log.ForContext().Information("Web-server listening on: {0:l}", uri); var hostConfiguration = new HostConfiguration(); hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 5fee9ce3c..843bf43d5 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -38,7 +38,7 @@ public class StratumService : JsonRpcService, IRpcService private readonly IShareManager _shareManager; public StratumService(ICoinConfig coinConfig, IShareManager shareManager): - base(string.Format("stratum-{0}", coinConfig.Name)) + base(coinConfig.Name) { _shareManager = shareManager; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 62c23e190..054a3f170 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -161,7 +161,7 @@ public void Parse(ConnectionDataEventArgs e) var rpcContext = new SocketServiceContext(this, rpcRequest); var async = new JsonRpcStateAsync(rpcResultHandler, rpcContext) { JsonRpc = line }; - JsonRpcProcessor.Process(async, rpcContext); + JsonRpcProcessor.Process(Pool.Config.Coin.Name, async, rpcContext); } /// From 73244a50f1a5646714e54c51b926cfd24f33af40 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 16:59:25 +0300 Subject: [PATCH 077/230] enabled fields for service configs are now correctly honored. --- src/CoiniumServ/Mining/Pools/Pool.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 6589f72a5..1dd0b489f 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -195,9 +195,10 @@ private void InitServers() { _servers = new Dictionary(); - // we don't need here a server config list as a pool can host only one instance of stratum and one vanilla server. + // TODO: we don't need here a server config list as a pool can host only one instance of stratum and one vanilla server. // we must be dictative here, using a server list may cause situations we don't want (multiple stratum configs etc..) - if (Config.Stratum != null) + + if (Config.Stratum != null && Config.Stratum.Enabled) { var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager); var stratumService = _serviceFactory.Get("Stratum", Config.Coin, _shareManager, _daemonClient); @@ -206,7 +207,7 @@ private void InitServers() _servers.Add(stratumServer, stratumService); } - if (Config.Vanilla != null) + if (Config.Vanilla != null && Config.Vanilla.Enabled) { var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager); var vanillaService = _serviceFactory.Get("Vanilla", Config.Coin, _shareManager, _daemonClient); From eeacb453bb0fbf693d66add53b6e0cfe16fe697c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 17:05:42 +0300 Subject: [PATCH 078/230] Removed unnecessary field Statistics from PoolManager. --- src/CoiniumServ/Mining/Pools/IPoolManager.cs | 2 -- src/CoiniumServ/Mining/Pools/PoolManager.cs | 10 +--------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index f63792f72..bdc37a8e6 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -23,13 +23,11 @@ using System.Collections.Generic; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; namespace CoiniumServ.Mining.Pools { public interface IPoolManager { - IStatistics NewStatistics { get; } IList GetPools(); diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 77e8d44dc..0be839cae 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -25,7 +25,6 @@ using System.Collections.Generic; using System.Linq; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; using CoiniumServ.Utils.Configuration; using CoiniumServ.Utils.Helpers.IO; using Serilog; @@ -34,28 +33,21 @@ namespace CoiniumServ.Mining.Pools { public class PoolManager : IPoolManager { - public IStatistics NewStatistics { get; private set; } - private readonly List _pools = new List(); private readonly IPoolFactory _poolFactory; private readonly IPoolConfigFactory _poolConfigFactory; - private readonly IStatisticsObjectFactory _objectFactory; - - public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory, IStatisticsObjectFactory objectFactory) + public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory) { _poolFactory = poolFactory; _poolConfigFactory = poolConfigFactory; - _objectFactory = objectFactory; } public void Run() { LoadConfigs(); - - NewStatistics = _objectFactory.GetStatistics(); } public void LoadConfigs() From bb06f2f696d820dd31059c8b219f86bbca171eb7 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 17 Jul 2014 18:44:36 +0300 Subject: [PATCH 079/230] Misc fixes & improvements. Renamed work.cs as getwork.cs. Fixed httpserver.cs - it does now correctly listen on configured ip & port. Pools are now started by pool manager now. Fixed creation of new vanilla miners. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- src/CoiniumServ/Daemon/DaemonClient.cs | 4 +-- src/CoiniumServ/Daemon/IDaemonClient.cs | 2 +- .../Daemon/Responses/{Work.cs => Getwork.cs} | 17 ++++++----- src/CoiniumServ/Mining/Pools/PoolManager.cs | 7 +++++ .../Net/Server/Http/Basic/HttpServer.cs | 13 ++++----- src/CoiniumServ/Program.cs | 6 ---- .../Stratum/Service/SocketServiceContext.cs | 2 +- .../Mining/Stratum/Service/StratumService.cs | 2 +- .../Server/Mining/Stratum/StratumMiner.cs | 5 ++-- .../Server/Mining/Stratum/StratumServer.cs | 1 - .../Vanilla/Service/HttpServiceContext.cs | 2 +- .../Mining/Vanilla/Service/VanillaService.cs | 28 +++++++++---------- .../Server/Mining/Vanilla/VanillaMiner.cs | 13 +++++---- .../Server/Mining/Vanilla/VanillaServer.cs | 9 ++++-- 15 files changed, 59 insertions(+), 54 deletions(-) rename src/CoiniumServ/Daemon/Responses/{Work.cs => Getwork.cs} (83%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 977fb864e..896b2d551 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -324,7 +324,7 @@ - + diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index ac9308ae5..b1f50d6ad 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -467,9 +467,9 @@ public TxOutSetInfo GetTxOutSetInfo() /// "target" : little endian hash target /// If [data] is specified, tries to solve the block and returns true if it was successful. /// - public Work Getwork() + public Getwork Getwork() { - return MakeRequest("getwork", null); + return MakeRequest("getwork", null); } /// diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 0ee3f6be2..96762cdcd 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -37,7 +37,7 @@ public interface IDaemonClient Block GetBlock(string hash); - Work Getwork(); + Getwork Getwork(); bool Getwork(string data); diff --git a/src/CoiniumServ/Daemon/Responses/Work.cs b/src/CoiniumServ/Daemon/Responses/Getwork.cs similarity index 83% rename from src/CoiniumServ/Daemon/Responses/Work.cs rename to src/CoiniumServ/Daemon/Responses/Getwork.cs index 04b3e5618..e6d517525 100644 --- a/src/CoiniumServ/Daemon/Responses/Work.cs +++ b/src/CoiniumServ/Daemon/Responses/Getwork.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + namespace CoiniumServ.Daemon.Responses { // Documentation: @@ -27,28 +28,30 @@ namespace CoiniumServ.Daemon.Responses // https://github.com/sinisterchipmunk/bitpool/wiki/Bitcoin-Mining-Pool-Developer's-Reference // https://bitcointalk.org/index.php?topic=51281.0 - public class Work - { + // Note: Do not rename member field names with uppercase ones as it will break getwork protocol @ json-rpc 1.0. + + public class Getwork + { /// /// This should be advertised iff the miner supports generating its own midstates. In this case, the pool may decide to omit the now-deprecated "midstate" and "hash1" fields in the work response. /// - public string MidState { get; set; } + public string midstate { get; set; } /// /// Pre-processed SHA-2 input chunks, in little-endian order, as a hexadecimal-encoded string /// - public string Data { get; set; } + public string data { get; set; } - public string Hash1 { get; set; } + public string hash1 { get; set; } /// /// Proof-of-work hash target as a hexadecimal-encoded string /// - public string Target { get; set; } + public string target { get; set; } /// /// Brief specification of proof-of-work algorithm. Not provided by bitcoind or most poolservers. /// - public string Algorithm { get; set; } + public string algorithm { get; set; } } } diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 0be839cae..fa6371557 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -47,7 +47,14 @@ public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactor public void Run() { + // load pool configs. LoadConfigs(); + + // run pools. + foreach (var pool in _pools) + { + pool.Start(); + } } public void LoadConfigs() diff --git a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs index e810e2292..0a6c2c198 100644 --- a/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Basic/HttpServer.cs @@ -35,18 +35,20 @@ public class HttpServer : IServer, IDisposable /// /// The IP address of the interface the server binded. /// - public string BindIP { get; private set; } + public string BindIP { get; protected set; } /// /// The listening port for the server. /// - public int Port { get; private set; } + public int Port { get; protected set; } /// /// Is server currently listening for connections? /// public bool IsListening { get; private set; } + public event Action ProcessRequest; + private HttpListener _listener; private Thread _listenerThread; private Thread[] _workers; @@ -59,13 +61,11 @@ public class HttpServer : IServer, IDisposable /// The port. /// The maximum threads. /// HttpListener not supported. Switch to mono provided one. - public void Initialize(int port, int maxThreads = 5) + public void Initialize(int maxThreads = 5) { if (!HttpListener.IsSupported) throw new NotSupportedException("HttpListener not supported."); - Port = port; - _workers = new Thread[maxThreads]; _queue = new Queue(); _stop = new ManualResetEvent(false); @@ -76,7 +76,6 @@ public void Initialize(int port, int maxThreads = 5) public bool Start() { - BindIP = "localhost"; _listener.Prefixes.Add(String.Format(@"http://{0}:{1}/", BindIP, Port)); _listener.Start(); _listenerThread.Start(); @@ -159,8 +158,6 @@ private void Worker() } } - public event Action ProcessRequest; - public void Dispose() { Stop(); diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 0af1faadb..a260b07c1 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -84,12 +84,6 @@ static void Main(string[] args) var poolManager = kernel.Resolve().Get(); poolManager.Run(); - // run pools. - foreach (var pool in poolManager.GetPools()) - { - pool.Start(); - } - // start web server. var webServer = kernel.Resolve("Web"); diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs index c63b70ae1..b20601691 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs @@ -29,7 +29,7 @@ public class SocketServiceContext { public IMiner Miner { get; private set; } - public SocketServiceRequest Request { get; private set; } + public SocketServiceRequest Request { get; private set; } // todo - do we really need this? public SocketServiceContext(IMiner miner, SocketServiceRequest request) { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 843bf43d5..9f43899aa 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -50,7 +50,7 @@ public StratumService(ICoinConfig coinConfig, IShareManager shareManager): [JsonRpcMethod("mining.subscribe")] public SubscribeResponse SubscribeMiner(string signature) { - var context = (SocketServiceContext)JsonRpcContext.Current().Value; + var context = (SocketServiceContext) JsonRpcContext.Current().Value; var miner = (StratumMiner)(context.Miner); var response = new SubscribeResponse diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 054a3f170..edb35e818 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -99,6 +99,7 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo Connection = connection; // the underlying connection. _minerManager = minerManager; Pool = pool; + Difficulty = 16; // set miner difficulty. Subscribed = false; // miner has to subscribe. @@ -143,7 +144,7 @@ public void Parse(ConnectionDataEventArgs e) callback => { var asyncData = ((JsonRpcStateAsync)callback); - var result = asyncData.Result + "\n"; // quick hack. + var result = asyncData.Result + "\n"; var response = Encoding.UTF8.GetBytes(result); var context = (SocketServiceContext) asyncData.AsyncState; @@ -155,7 +156,7 @@ public void Parse(ConnectionDataEventArgs e) }); var line = e.Data.ToEncodedString(); - line = line.Replace("\n", ""); // quick hack! + line = line.Replace("\n", ""); var rpcRequest = new SocketServiceRequest(line); var rpcContext = new SocketServiceContext(this, rpcRequest); diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index b0da0c021..e9782cc0a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -66,7 +66,6 @@ public StratumServer(IPool pool, IMinerManager minerManager, IJobManager jobMana public void Initialize(IServerConfig config) { Config = config; - BindIP = config.BindInterface; Port = config.Port; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs index 2171b3d5c..29a8b3ec7 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs @@ -29,7 +29,7 @@ public class HttpServiceContext { public IMiner Miner { get; private set; } - public HttpServiceRequest Request { get; private set; } + public HttpServiceRequest Request { get; private set; } // todo - do we really need this? public HttpServiceContext(IMiner miner, HttpServiceRequest request) { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index ac905a190..648368f59 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -32,7 +32,7 @@ namespace CoiniumServ.Server.Mining.Vanilla.Service { /// - /// Stratum protocol implementation. + /// Vanilla protocol implementation. /// public class VanillaService : JsonRpcService, IRpcService { @@ -41,7 +41,7 @@ public class VanillaService : JsonRpcService, IRpcService private readonly IShareManager _shareManager; public VanillaService(ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient): - base(string.Format("vanilla-{0}", coinConfig.Name)) + base(coinConfig.Name) { _daemonClient = daemonClient; _shareManager = shareManager; @@ -58,25 +58,23 @@ public VanillaService(ICoinConfig coinConfig, IShareManager shareManager, IDaemo /// https://bitcointalk.org/index.php?topic=51281.0 /// [JsonRpcMethod("getwork")] - public Work Getwork(string data = null) + public Getwork Getwork(string data = null) { - var context = (HttpServiceContext)JsonRpcContext.Current().Value; - var miner = (VanillaMiner)(context.Miner); + var context = (HttpServiceContext) JsonRpcContext.Current().Value; + var miner = (VanillaMiner) (context.Miner); // TODO: fixme! instead use jobmanager and sharemanager. - if (data == null) - _daemonClient.Getwork(); - else - { - var result = _daemonClient.Getwork(data); - if(result) - Log.ForContext().Verbose("Found block!: {0}", data); + if (data == null) // if miner supplied no data + return _daemonClient.Getwork(); // that means he just wants work. - return null; - } + var result = _daemonClient.Getwork(data); // if he supplied a data + //TODO: fix this according https://bitcointalk.org/index.php?topic=51281.msg611897#msg611897 + + if (result) // check his work. + Log.ForContext().Verbose("Found block!: {0}", data); return null; - } + } } } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 3df77b4d2..384d99fe2 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -72,10 +72,12 @@ public class VanillaMiner : IMiner /// /// /// + /// /// - public VanillaMiner(int id, IMinerManager minerManager) + public VanillaMiner(int id, IPool pool, IMinerManager minerManager) { Id = id; // the id of the miner. + Pool = pool; _minerManager = minerManager; Difficulty = 16; @@ -108,20 +110,21 @@ public void Parse(HttpListenerContext httpContext) context.Request.Response.ContentType = "application/json"; context.Request.Response.ContentEncoding = Encoding.UTF8; context.Request.Response.ContentLength64 = response.Length; - context.Request.Response.OutputStream.Write(response, 0, response.Length); + context.Request.Response.OutputStream.Write(response, 0, response.Length); + + Log.ForContext().Verbose("Reply:\n{0}", result.PrettifyJson()); }); using (var reader = new StreamReader(httpRequest.InputStream, Encoding.UTF8)) { var line = reader.ReadToEnd(); - - Log.ForContext().Verbose(line.PrettifyJson()); + Log.ForContext().Verbose("Recv:\n{0}", line.PrettifyJson()); var rpcRequest = new HttpServiceRequest(line, httpContext); var rpcContext = new HttpServiceContext(this, rpcRequest); var async = new JsonRpcStateAsync(rpcResultHandler, rpcContext) { JsonRpc = line }; - JsonRpcProcessor.Process(async, rpcContext); + JsonRpcProcessor.Process(Pool.Config.Coin.Name, async, rpcContext); } } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index 1a3802769..13164caa6 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -48,10 +48,13 @@ public VanillaServer(IPool pool, IMinerManager minerManager, IJobManager jobMana _jobManager = jobManager; } - public void Initialize(IServerConfig serverConfig) + public void Initialize(IServerConfig config) { - Initialize(serverConfig.Port); - Config = serverConfig; + Config = config; + BindIP = config.BindInterface; + Port = config.Port; + + Initialize(); ProcessRequest += ProcessHttpRequest; } From 229b24a9fa01ca0c29900d664cda41c7c2bd95f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 02:27:42 +0300 Subject: [PATCH 080/230] Added pragma warning disable to BigInteger.cs and BigRational.cs. Added banning section to sample pool config. --- src/CoiniumServ/Coin/Coinbase/Serializers.cs | 6 +++--- src/CoiniumServ/Payments/PaymentProcessor.cs | 2 +- src/CoiniumServ/Utils/Numerics/BigInteger.cs | 2 ++ src/CoiniumServ/Utils/Numerics/BigRational.cs | 2 ++ src/CoiniumServ/config/pools/sample.json | 9 +++++++++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/CoiniumServ/Coin/Coinbase/Serializers.cs b/src/CoiniumServ/Coin/Coinbase/Serializers.cs index 103564914..8ac10500b 100644 --- a/src/CoiniumServ/Coin/Coinbase/Serializers.cs +++ b/src/CoiniumServ/Coin/Coinbase/Serializers.cs @@ -256,17 +256,17 @@ public static byte[] SerializeString(string input) if (input.Length < 0x10000) { stream.WriteValueU8(253); - stream.WriteValueU16(((UInt16)input.Length).LittleEndian()); // write packed lenght. + stream.WriteValueU16(((UInt16)input.Length).LittleEndian()); // write packed length. } else if (input.Length < 0x100000000) { stream.WriteValueU8(254); - stream.WriteValueU32(((UInt32)input.Length).LittleEndian()); // write packed lenght. + stream.WriteValueU32(((UInt32)input.Length).LittleEndian()); // write packed length. } else { stream.WriteValueU8(255); - stream.WriteValueU16(((UInt16)input.Length).LittleEndian()); // write packed lenght. + stream.WriteValueU16(((UInt16)input.Length).LittleEndian()); // write packed length. } stream.WriteString(input); diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 83ae465ac..3d2afa634 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -364,7 +364,7 @@ private bool DeterminePrecision() Log.ForContext().Error("Halted as getbalance call failed: {0}.", e.Message); return false; } - catch (Exception e) + catch (Exception) { Log.ForContext().Error("Halted as we can not determine satoshis in a coin - failed parsing: {0}", json); return false; diff --git a/src/CoiniumServ/Utils/Numerics/BigInteger.cs b/src/CoiniumServ/Utils/Numerics/BigInteger.cs index 6d736c5de..4052a5f37 100644 --- a/src/CoiniumServ/Utils/Numerics/BigInteger.cs +++ b/src/CoiniumServ/Utils/Numerics/BigInteger.cs @@ -42,6 +42,8 @@ Optimize BitScanBackward Schoolbook multiply is O(n^2), use Karatsuba /Toom-3 for large numbers */ +#pragma warning disable 3021 // disable CLSCompliant attribute warnings - http://msdn.microsoft.com/en-us/library/1x9049cy(v=vs.90).aspx + namespace CoiniumServ.Utils.Numerics { // diff --git a/src/CoiniumServ/Utils/Numerics/BigRational.cs b/src/CoiniumServ/Utils/Numerics/BigRational.cs index 1eef9f8cf..92af3855d 100644 --- a/src/CoiniumServ/Utils/Numerics/BigRational.cs +++ b/src/CoiniumServ/Utils/Numerics/BigRational.cs @@ -28,6 +28,8 @@ using System.Security.Permissions; using System.Text; +#pragma warning disable 3021 // disable CLSCompliant attribute warnings - http://msdn.microsoft.com/en-us/library/1x9049cy(v=vs.90).aspx + namespace CoiniumServ.Utils.Numerics { diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index aea3bafae..23290e685 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -51,6 +51,15 @@ "port": 2223 }, + # banning support + "banning": { + "enabled": true, + "duration": 600, + "percent": 50, + "threshold": 500, + "purge": 300 + }, + # mpos compat mode configuration - not implemented yet! "mpos": { "enabled": false, From 19805f6146374032c4a02c9a0b8b4052c774aefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 02:37:09 +0300 Subject: [PATCH 081/230] Implemented BanningConfig reader. --- src/CoiniumServ/CoiniumServ.csproj | 2 + .../Mining/Pools/Config/BanningConfig.cs | 43 +++++++++++++++++++ .../Mining/Pools/Config/IBanningConfig.cs | 38 ++++++++++++++++ .../Mining/Pools/Config/IPoolConfig.cs | 2 + .../Mining/Pools/Config/PoolConfig.cs | 4 ++ src/CoiniumServ/Mining/Pools/Pool.cs | 6 +-- src/CoiniumServ/config/pools/sample.json | 8 ++-- 7 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 896b2d551..6096d7f32 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,6 +110,8 @@ + + diff --git a/src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs b/src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs new file mode 100644 index 000000000..ac555f207 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs @@ -0,0 +1,43 @@ +#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.Mining.Pools.Config +{ + public class BanningConfig : IBanningConfig + { + public bool Enabled { get; private set; } + public int Duration { get; private set; } + public int InvalidPercent { get; private set; } + public int CheckThreshold { get; private set; } + public int PurgeInterval { get; private set; } + + public BanningConfig(dynamic config) + { + Enabled = config.enabled; + Duration = config.duration; + InvalidPercent = config.invalidPercent; + CheckThreshold = config.checkThreshold; + PurgeInterval = config.purgeInterval; + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs new file mode 100644 index 000000000..0c5a0ac0c --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs @@ -0,0 +1,38 @@ +#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.Mining.Pools.Config +{ + public interface IBanningConfig + { + bool Enabled { get; } + + int Duration { get; } + + int InvalidPercent { get; } + + int CheckThreshold { get; } + + int PurgeInterval { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index c4cab9154..55ad3e60d 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -50,5 +50,7 @@ public interface IPoolConfig:IConfig IRewardsConfig Rewards { get; } IPaymentConfig Payments { get; } + + IBanningConfig Banning { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 8f5f2cfdf..e008e5b7a 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -55,6 +55,8 @@ public class PoolConfig : IPoolConfig public IPaymentConfig Payments { get; private set; } + public IBanningConfig Banning { get; private set; } + /// /// Initializes a new instance of the class. /// @@ -109,6 +111,8 @@ public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) return; } + Banning = new BanningConfig(config.banning); + Valid = true; } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 1dd0b489f..dbf756f9d 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -65,7 +65,7 @@ public class Pool : IPool private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; - private readonly IVardiffManagerFactory _varddManagerFactory; + private readonly IVardiffManagerFactory _vardiffManagerFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -135,7 +135,7 @@ public Pool( _storageFactory = storageFactory; _paymentProcessorFactory = paymentProcessorFactory; _statisticsObjectFactory = statisticsObjectFactory; - _varddManagerFactory = vardiffManagerFactory; + _vardiffManagerFactory = vardiffManagerFactory; GenerateInstanceId(); } @@ -181,7 +181,7 @@ private void InitManagers() _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage); - _vardiffManager = _varddManagerFactory.Get(Config.Stratum.Vardiff, _shareManager); + _vardiffManager = _vardiffManagerFactory.Get(Config.Stratum.Vardiff, _shareManager); _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm, Config.Wallet, Config.Rewards); _jobManager.Initialize(InstanceId); diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index 23290e685..7a962a950 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -44,7 +44,7 @@ } }, - # vanilla server configuration + # vanilla server configuration - experimental! "vanilla": { "enabled": false, "bind": "localhost", @@ -55,9 +55,9 @@ "banning": { "enabled": true, "duration": 600, - "percent": 50, - "threshold": 500, - "purge": 300 + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 }, # mpos compat mode configuration - not implemented yet! From e83a2fe9a445632858ad36516fca9dc754b409e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 03:03:38 +0300 Subject: [PATCH 082/230] Cleaned IMiner.cs and moved stratum-only stuff to IStratumMiner.cs. Implemented IVanillaMiner.cs. --- src/CoiniumServ/Coin/Coinbase/Serializers.cs | 2 +- src/CoiniumServ/CoiniumServ.csproj | 1 + .../Mining/Jobs/Manager/JobManager.cs | 20 ++++++----- src/CoiniumServ/Mining/Miners/IMiner.cs | 24 ++------------ src/CoiniumServ/Mining/Miners/MinerManager.cs | 13 +++++--- .../Mining/Shares/IShareManager.cs | 4 +-- .../Mining/Shares/ShareEventArgs.cs | 4 +-- src/CoiniumServ/Mining/Shares/ShareManager.cs | 4 +-- .../Server/Mining/Stratum/IStratumMiner.cs | 20 +++++++++++ .../Mining/Stratum/Service/StratumService.cs | 6 ++-- .../Server/Mining/Stratum/StratumMiner.cs | 6 ---- .../Server/Mining/Vanilla/IVanillaMiner.cs | 31 +++++++++++++++++ .../Mining/Vanilla/Service/VanillaService.cs | 2 +- .../Server/Mining/Vanilla/VanillaMiner.cs | 33 +------------------ 14 files changed, 86 insertions(+), 84 deletions(-) create mode 100644 src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs diff --git a/src/CoiniumServ/Coin/Coinbase/Serializers.cs b/src/CoiniumServ/Coin/Coinbase/Serializers.cs index 8ac10500b..49e515bb4 100644 --- a/src/CoiniumServ/Coin/Coinbase/Serializers.cs +++ b/src/CoiniumServ/Coin/Coinbase/Serializers.cs @@ -258,7 +258,7 @@ public static byte[] SerializeString(string input) stream.WriteValueU8(253); stream.WriteValueU16(((UInt16)input.Length).LittleEndian()); // write packed length. } - else if (input.Length < 0x100000000) + else if ((long)input.Length < 0x100000000) { stream.WriteValueU8(254); stream.WriteValueU32(((UInt32)input.Length).LittleEndian()); // write packed length. diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 6096d7f32..77ef2920e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -183,6 +183,7 @@ + diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index f935c3d56..b5f00cb8e 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -30,7 +30,9 @@ using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Mining.Shares; +using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Server.Mining.Vanilla; using CoiniumServ.Transactions; using Serilog; @@ -114,10 +116,10 @@ private void OnMinerAuthenticated(object sender, EventArgs e) { var miner = ((MinerEventArgs) e).Miner; - if (miner != null) - { - var result = SendJobToMiner(miner, _jobTracker.Current); - } + if (miner == null) + return; + + var result = SendJobToMiner(miner, _jobTracker.Current); } private IJob GetNewJob() @@ -186,16 +188,18 @@ private Int32 Broadcast(IJob job) private bool SendJobToMiner(IMiner miner, IJob job) { - if (!miner.Authenticated) + if (miner is IVanillaMiner) // only stratum miners needs to be submitted new jobs. return false; - if (!miner.Subscribed) + var stratumMiner = (IStratumMiner) miner; + + if (!stratumMiner.Authenticated) return false; - if (!miner.SupportsJobNotifications) + if (!stratumMiner.Subscribed) return false; - miner.SendJob(job); + stratumMiner.SendJob(job); return true; } diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Mining/Miners/IMiner.cs index 97673537a..160f1b5a6 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Mining/Miners/IMiner.cs @@ -22,7 +22,6 @@ #endregion using CoiniumServ.Mining.Pools; -using CoiniumServ.Server.Mining.Stratum.Notifications; namespace CoiniumServ.Mining.Miners { @@ -42,19 +41,15 @@ public interface IMiner string Username { get; } /// - /// Is the miner subscribed? + /// The pool miner is connected to. /// - bool Subscribed { get; } + IPool Pool { get; } /// /// Is the miner authenticated. /// bool Authenticated { get; set; } - IPool Pool { get; } - - float Difficulty { get; set; } - /// /// Authenticates the miner. /// @@ -62,20 +57,5 @@ public interface IMiner /// /// bool Authenticate(string user, string password); - - /// - /// Can we send new mining job's to miner? - /// - bool SupportsJobNotifications { get; } - - /// - /// Sends difficulty to the miner. - /// - void SendDifficulty(); - - /// - /// Sends a new mining job to the miner. - /// - void SendJob(IJob job); } } diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index a15c621f0..740da5281 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -27,6 +27,7 @@ using CoiniumServ.Daemon; using CoiniumServ.Mining.Pools; using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Server.Mining.Stratum; using Serilog; namespace CoiniumServ.Mining.Miners @@ -101,11 +102,13 @@ public void Authenticate(IMiner miner) Log.ForContext().Information(miner.Authenticated ? "Authenticated miner: {0:l} [{1:l}]" : "Unauthenticated miner: {0:l} [{1:l}]", miner.Username, ((IClient) miner).Connection.RemoteEndPoint); - if (miner.Authenticated) // if miner authenticated successfully. - { - miner.SendDifficulty(); // send the initial difficulty. - OnMinerAuthenticated(new MinerEventArgs(miner)); // notify listeners about the new authenticated miner. - } + if (!miner.Authenticated) + return; + + if(miner is IStratumMiner) + (miner as IStratumMiner).SendDifficulty(); // send the initial difficulty. + + OnMinerAuthenticated(new MinerEventArgs(miner)); // notify listeners about the new authenticated miner. } protected virtual void OnMinerAuthenticated(MinerEventArgs e) diff --git a/src/CoiniumServ/Mining/Shares/IShareManager.cs b/src/CoiniumServ/Mining/Shares/IShareManager.cs index 9fbef7268..e7950e3f2 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/IShareManager.cs @@ -29,9 +29,9 @@ namespace CoiniumServ.Mining.Shares { public interface IShareManager { - IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, string nTimeString, string nonceString); + IShare ProcessShare(IStratumMiner miner, string jobId, string extraNonce2, string nTimeString, string nonceString); - IShare ProcessShare(VanillaMiner miner, string data); + IShare ProcessShare(IVanillaMiner miner, string data); event EventHandler BlockFound; diff --git a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs index 43e0b5df3..2a9b4fb70 100644 --- a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs +++ b/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs @@ -28,9 +28,9 @@ namespace CoiniumServ.Mining.Shares { public class ShareEventArgs:EventArgs { - public StratumMiner Miner { get; private set; } + public IStratumMiner Miner { get; private set; } - public ShareEventArgs(StratumMiner miner) + public ShareEventArgs(IStratumMiner miner) { Miner = miner; } diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 1532912b4..81988855a 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -68,7 +68,7 @@ public ShareManager(IDaemonClient daemonClient, IJobTracker jobTracker, IStorage /// The n time string. /// The nonce string. /// - public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, string nTimeString, string nonceString) + public IShare ProcessShare(IStratumMiner miner, string jobId, string extraNonce2, string nTimeString, string nonceString) { // check if the job exists var id = Convert.ToUInt64(jobId, 16); @@ -131,7 +131,7 @@ public IShare ProcessShare(StratumMiner miner, string jobId, string extraNonce2, return share; } - public IShare ProcessShare(VanillaMiner miner, string data) + public IShare ProcessShare(IVanillaMiner miner, string data) { throw new NotImplementedException(); } diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index 653543de6..9d82baea1 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -24,6 +24,7 @@ using System; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Server.Mining.Stratum.Notifications; namespace CoiniumServ.Server.Mining.Stratum { @@ -33,5 +34,24 @@ public interface IStratumMiner:IMiner, IVardiffMiner /// Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) /// UInt32 ExtraNonce { get; } + + /// + /// Is the miner subscribed? + /// + bool Subscribed { get; } + + float Difficulty { get; set; } + + /// + /// Sends difficulty to the miner. + /// + void SendDifficulty(); + + /// + /// Sends a new mining job to the miner. + /// + void SendJob(IJob job); + + void Subscribe(); } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 9f43899aa..c2ba66e26 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -51,7 +51,7 @@ public StratumService(ICoinConfig coinConfig, IShareManager shareManager): public SubscribeResponse SubscribeMiner(string signature) { var context = (SocketServiceContext) JsonRpcContext.Current().Value; - var miner = (StratumMiner)(context.Miner); + var miner = (IStratumMiner)(context.Miner); var response = new SubscribeResponse { @@ -73,7 +73,7 @@ public SubscribeResponse SubscribeMiner(string signature) public bool AuthorizeMiner(string user, string password) { var context = (SocketServiceContext)JsonRpcContext.Current().Value; - var miner = (StratumMiner)(context.Miner); + var miner = (IStratumMiner)(context.Miner); return miner.Authenticate(user, password); } @@ -90,7 +90,7 @@ public bool AuthorizeMiner(string user, string password) public bool SubmitWork(string user, string jobId, string extraNonce2, string nTime, string nonce) { var context = (SocketServiceContext)JsonRpcContext.Current().Value; - var miner = (StratumMiner)(context.Miner); + var miner = (IStratumMiner)(context.Miner); return _shareManager.ProcessShare(miner, jobId, extraNonce2, nTime, nonce).IsValid; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index edb35e818..45114cfdf 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -68,11 +68,6 @@ public class StratumMiner : IClient, IStratumMiner public float Difficulty { get; set; } - /// - /// Sends a new mining job to the miner. - /// - public bool SupportsJobNotifications { get; private set; } - /// /// Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) /// @@ -104,7 +99,6 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo Subscribed = false; // miner has to subscribe. Authenticated = false; // miner has to authenticate. - SupportsJobNotifications = true; // stratum miner'ssupports new mining job notifications. } /// diff --git a/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs new file mode 100644 index 000000000..1b0f7e223 --- /dev/null +++ b/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs @@ -0,0 +1,31 @@ +#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 CoiniumServ.Mining.Miners; + +namespace CoiniumServ.Server.Mining.Vanilla +{ + public interface IVanillaMiner : IMiner + { + } +} diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index 648368f59..f6ca4fb1f 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -61,7 +61,7 @@ public VanillaService(ICoinConfig coinConfig, IShareManager shareManager, IDaemo public Getwork Getwork(string data = null) { var context = (HttpServiceContext) JsonRpcContext.Current().Value; - var miner = (VanillaMiner) (context.Miner); + var miner = (IVanillaMiner) (context.Miner); // TODO: fixme! instead use jobmanager and sharemanager. diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 384d99fe2..28652f2a1 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -35,7 +35,7 @@ namespace CoiniumServ.Server.Mining.Vanilla { - public class VanillaMiner : IMiner + public class VanillaMiner : IVanillaMiner { /// /// Unique subscription id for identifying the miner. @@ -47,11 +47,6 @@ public class VanillaMiner : IMiner /// public string Username { get; private set; } - /// - /// Is the miner subscribed? - /// - public bool Subscribed { get; private set; } - /// /// Is the miner authenticated? /// @@ -59,13 +54,6 @@ public class VanillaMiner : IMiner public IPool Pool { get; private set; } - public float Difficulty { get; set; } - - /// - /// Can we send new mining job's to miner? - /// - public bool SupportsJobNotifications { get; private set; } - private readonly IMinerManager _minerManager; /// @@ -79,11 +67,8 @@ public VanillaMiner(int id, IPool pool, IMinerManager minerManager) Id = id; // the id of the miner. Pool = pool; _minerManager = minerManager; - Difficulty = 16; - Subscribed = true; // vanilla miners are subscribed by default. Authenticated = false; // miner has to authenticate. - SupportsJobNotifications = false; // vanilla miner's doesn't support new mining job notifications. } public bool Authenticate(string user, string password) @@ -127,21 +112,5 @@ public void Parse(HttpListenerContext httpContext) JsonRpcProcessor.Process(Pool.Config.Coin.Name, async, rpcContext); } } - - /// - /// Sends difficulty to the miner. - /// - public void SendDifficulty() - { - throw new NotSupportedException(); - } - - /// - /// Sends a new mining job to the miner. - /// - public void SendJob(IJob job) - { - throw new NotSupportedException(); - } } } From f13a4619421dfb3f936407593342c203d0c9de6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 04:32:39 +0300 Subject: [PATCH 083/230] Started implementing banning manager. Fixed a tiny bug in hashrate calculation. Implemented ISocketServer interface. Trying to fix multiple disconnection bug in socketserver.cs but may still need more debugging & work. --- src/CoiniumServ/Coin/Helpers/Hashrate.cs | 5 +- src/CoiniumServ/CoiniumServ.csproj | 5 + .../Mining/Banning/BanningManager.cs | 83 +++++++++++++ .../Mining/Banning/BanningManagerFactory.cs | 58 +++++++++ .../Mining/Banning/IBanningManager.cs | 32 +++++ .../Mining/Banning/IBanningManagerFactory.cs | 33 +++++ src/CoiniumServ/Mining/Miners/IMiner.cs | 4 + src/CoiniumServ/Mining/Pools/Pool.cs | 39 +++--- src/CoiniumServ/Mining/Shares/IShare.cs | 2 + src/CoiniumServ/Mining/Shares/Share.cs | 16 +-- src/CoiniumServ/Mining/Shares/ShareManager.cs | 116 ++++++++++-------- src/CoiniumServ/Net/Server/IServer.cs | 1 + .../Net/Server/Sockets/Connection.cs | 14 +-- .../Net/Server/Sockets/ISocketServer.cs | 38 ++++++ .../Net/Server/Sockets/SocketServer.cs | 56 +++++---- .../Repository/Registries/FactoryRegistry.cs | 2 + .../Repository/Registries/ManagerRegistry.cs | 2 + .../Server/Mining/Stratum/StratumMiner.cs | 3 + .../Server/Mining/Stratum/StratumServer.cs | 12 +- .../Server/Mining/Vanilla/VanillaMiner.cs | 4 +- src/CoiniumServ/Server/Web/WebServer.cs | 1 - src/Tests/Mining/Pools/PoolTests.cs | 17 ++- 22 files changed, 417 insertions(+), 126 deletions(-) create mode 100644 src/CoiniumServ/Mining/Banning/BanningManager.cs create mode 100644 src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs create mode 100644 src/CoiniumServ/Mining/Banning/IBanningManager.cs create mode 100644 src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs create mode 100644 src/CoiniumServ/Net/Server/Sockets/ISocketServer.cs diff --git a/src/CoiniumServ/Coin/Helpers/Hashrate.cs b/src/CoiniumServ/Coin/Helpers/Hashrate.cs index bfaa9d422..6113b588e 100644 --- a/src/CoiniumServ/Coin/Helpers/Hashrate.cs +++ b/src/CoiniumServ/Coin/Helpers/Hashrate.cs @@ -31,13 +31,14 @@ public static string GetReadableHashrate(this UInt64 hashrate) { var index = -1; double rate = hashrate; + var units = new[] { "KH/s", "MH/s", "GH/s", "TH/s", "PH/s" }; do { - rate = rate/1024; + rate = rate/1000; index++; - } while (rate > 1024); + } while (rate > 1000); return string.Format("{0:0.00} {1}", rate, units[index]); } diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 77ef2920e..334e20d56 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,6 +110,10 @@ + + + + @@ -158,6 +162,7 @@ + diff --git a/src/CoiniumServ/Mining/Banning/BanningManager.cs b/src/CoiniumServ/Mining/Banning/BanningManager.cs new file mode 100644 index 000000000..9fe1588a2 --- /dev/null +++ b/src/CoiniumServ/Mining/Banning/BanningManager.cs @@ -0,0 +1,83 @@ +#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 CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Server.Mining.Vanilla; + +namespace CoiniumServ.Mining.Banning +{ + public class BanningManager:IBanningManager + { + public IBanningConfig Config { get; private set; } + + public BanningManager(IBanningConfig banningConfig, IShareManager shareManager) + { + Config = banningConfig; + + if (!Config.Enabled) + return; + + shareManager.ShareSubmitted += OnShare; + } + + private void OnShare(object sender, EventArgs e) + { + var shareArgs = (ShareEventArgs)e; + var miner = shareArgs.Miner; + + if (miner == null) + return; + + var totalShares = miner.ValidShares + miner.InvalidShares; + + if (totalShares < Config.CheckThreshold) // check if we exceeded the threshold for checks. + return; + + var invalidPercentage = miner.InvalidShares/totalShares*100; + + if (invalidPercentage < Config.InvalidPercent) + // if the miner didn't reach the invalid share percentage, reset his stats. + { + miner.ValidShares = 0; + miner.InvalidShares = 0; + } + else // he needs a ban + Ban(miner); + } + + private void Ban(IMiner miner) + { + // todo: add ip to banlist. + + if (miner is IVanillaMiner) // as vanilla miners doesn't use persistent connections, we don't need to disconect him + return; // but just blacklist hip ip. + + var client = (IClient) miner; + client.Connection.Disconnect(); + } + } +} diff --git a/src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs b/src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs new file mode 100644 index 000000000..752c59eca --- /dev/null +++ b/src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs @@ -0,0 +1,58 @@ +#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 CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Repository.Context; +using Nancy.TinyIoc; + +namespace CoiniumServ.Mining.Banning +{ + public class BanningManagerFactory : IBanningManagerFactory + { + /// + /// The _kernel + /// + private readonly IApplicationContext _applicationContext; + + /// + /// Initializes a new instance of the class. + /// + /// The application context. + public BanningManagerFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public IBanningManager Get(IBanningConfig banningConfig, IShareManager shareManager) + { + var @params = new NamedParameterOverloads + { + {"banningConfig", banningConfig}, + {"shareManager", shareManager}, + }; + + return _applicationContext.Container.Resolve(@params); + } + } +} diff --git a/src/CoiniumServ/Mining/Banning/IBanningManager.cs b/src/CoiniumServ/Mining/Banning/IBanningManager.cs new file mode 100644 index 000000000..8b4150f54 --- /dev/null +++ b/src/CoiniumServ/Mining/Banning/IBanningManager.cs @@ -0,0 +1,32 @@ +#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 CoiniumServ.Mining.Pools.Config; + +namespace CoiniumServ.Mining.Banning +{ + public interface IBanningManager + { + IBanningConfig Config { get; } + } +} diff --git a/src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs b/src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs new file mode 100644 index 000000000..d05df876a --- /dev/null +++ b/src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs @@ -0,0 +1,33 @@ +#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 CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; + +namespace CoiniumServ.Mining.Banning +{ + public interface IBanningManagerFactory + { + IBanningManager Get(IBanningConfig banningConfig, IShareManager shareManager); + } +} diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Mining/Miners/IMiner.cs index 160f1b5a6..65923a2a4 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Mining/Miners/IMiner.cs @@ -50,6 +50,10 @@ public interface IMiner /// bool Authenticated { get; set; } + int ValidShares { get; set; } + + int InvalidShares { get; set; } + /// /// Authenticates the miner. /// diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index dbf756f9d..e05dfbff8 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -28,6 +28,7 @@ using CoiniumServ.Coin.Helpers; using CoiniumServ.Crypto.Algorithms; using CoiniumServ.Daemon; +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Miners; @@ -66,6 +67,7 @@ public class Pool : IPool private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; + private readonly IBanningManagerFactory _banningManagerFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -75,6 +77,7 @@ public class Pool : IPool private IHashAlgorithm _hashAlgorithm; private IPaymentProcessor _paymentProcessor; private IVardiffManager _vardiffManager; + private IBanningManager _banningManager; private Dictionary _servers; @@ -98,6 +101,7 @@ public class Pool : IPool /// /// /// + /// public Pool( IHashAlgorithmFactory hashAlgorithmFactory, IServerFactory serverFactory, @@ -110,7 +114,8 @@ public Pool( IStorageFactory storageFactory, IPaymentProcessorFactory paymentProcessorFactory, IStatisticsObjectFactory statisticsObjectFactory, - IVardiffManagerFactory vardiffManagerFactory) + IVardiffManagerFactory vardiffManagerFactory, + IBanningManagerFactory banningManagerFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); @@ -123,6 +128,7 @@ public Pool( Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); Enforce.ArgumentNotNull(vardiffManagerFactory, "IVardiffManagerFactory"); + Enforce.ArgumentNotNull(banningManagerFactory, "IBanningManagerFactory"); _daemonClient = client; _minerManagerFactory = minerManagerFactory; @@ -136,6 +142,7 @@ public Pool( _paymentProcessorFactory = paymentProcessorFactory; _statisticsObjectFactory = statisticsObjectFactory; _vardiffManagerFactory = vardiffManagerFactory; + _banningManagerFactory = banningManagerFactory; GenerateInstanceId(); } @@ -183,6 +190,8 @@ private void InitManagers() _vardiffManager = _vardiffManagerFactory.Get(Config.Stratum.Vardiff, _shareManager); + _banningManager = _banningManagerFactory.Get(Config.Banning, _shareManager); + _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, _hashAlgorithm, Config.Wallet, Config.Rewards); _jobManager.Initialize(InstanceId); @@ -218,20 +227,6 @@ private void InitServers() } } - public void Start() - { - if (!Config.Valid) - { - Log.ForContext().Error("Can't start pool as configuration is not valid."); - return; - } - - foreach (var server in _servers) - { - server.Key.Start(); - } - } - private void PrintPoolInfo() { var info = _daemonClient.GetInfo(); @@ -267,6 +262,20 @@ private void PrintPoolInfo() ); } + public void Start() + { + if (!Config.Valid) + { + Log.ForContext().Error("Can't start pool as configuration is not valid."); + return; + } + + foreach (var server in _servers) + { + server.Key.Start(); + } + } + public void Stop() { throw new NotImplementedException(); diff --git a/src/CoiniumServ/Mining/Shares/IShare.cs b/src/CoiniumServ/Mining/Shares/IShare.cs index a024e636e..76364045f 100644 --- a/src/CoiniumServ/Mining/Shares/IShare.cs +++ b/src/CoiniumServ/Mining/Shares/IShare.cs @@ -52,6 +52,8 @@ public interface IShare ShareError Error { get; } + UInt64 JobId { get; } + IJob Job { get; } int Height { get; } diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index aa6f24e8a..9ad5bac69 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -36,19 +36,13 @@ namespace CoiniumServ.Mining.Shares { public class Share : IShare { - public bool IsValid - { - get { return Error == ShareError.None; } - } + public bool IsValid { get { return Error == ShareError.None; } } public bool IsBlockCandidate { get; private set; } public Block Block { get; private set; } - - public bool IsBlockAccepted - { - get { return Block != null; } - } + public bool IsBlockAccepted { get { return Block != null; } } public IMiner Miner { get; private set; } public ShareError Error { get; private set; } + public UInt64 JobId { get; private set; } public IJob Job { get; private set; } public int Height { get; private set; } public UInt32 NTime { get; private set; } @@ -69,6 +63,7 @@ public bool IsBlockAccepted public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, string nTimeString, string nonceString) { Miner = miner; + JobId = jobId; Job = job; Error = ShareError.None; @@ -79,10 +74,9 @@ public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, st if (Job == null) { Error = ShareError.JobNotFound; - Log.ForContext().Warning("Job doesn't exist: {0}", jobId); + Log.ForContext().Warning("Job doesn't exist: {0}", JobId); return; } - // check miner supplied nTime. if (nTimeString.Length != 8) diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index 81988855a..39be5daec 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -78,53 +78,9 @@ public IShare ProcessShare(IStratumMiner miner, string jobId, string extraNonce2 var share = new Share(miner, id, job, extraNonce2, nTimeString, nonceString); if (share.IsValid) - { - _storage.AddShare(share); // commit the share. - - if (share.IsBlockCandidate) // if share contains a block candicate - { - Log.ForContext().Debug("Share with block candidate [{0}] accepted at {1:0.00}/{2} by miner {3:l}.", share.Height, share.Difficulty, miner.Difficulty, miner.Username); - - var accepted = SubmitBlock(share); // submit block to daemon. - - if (accepted) - { - OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. - _storage.AddBlock(share); // commit the block. - } - } - else - Log.ForContext().Debug("Share accepted at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); - } + HandleValidShare(share); else - { - switch (share.Error) - { - case ShareError.DuplicateShare: - JsonRpcContext.SetException(new DuplicateShareError(share.Nonce)); - break; - case ShareError.IncorrectExtraNonce2Size: - JsonRpcContext.SetException(new OtherError("Incorrect extranonce2 size")); - break; - case ShareError.IncorrectNTimeSize: - JsonRpcContext.SetException(new OtherError("Incorrect nTime size")); - break; - case ShareError.IncorrectNonceSize: - JsonRpcContext.SetException(new OtherError("Incorrect nonce size")); - break; - case ShareError.JobNotFound: - JsonRpcContext.SetException(new JobNotFoundError(id)); - break; - case ShareError.LowDifficultyShare: - JsonRpcContext.SetException(new LowDifficultyShare(share.Difficulty)); - break; - case ShareError.NTimeOutOfRange: - JsonRpcContext.SetException(new OtherError("nTime out of range")); - break; - } - - Log.ForContext().Debug("Share rejected at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); - } + HandleInvalidShare(share); OnShareSubmitted(new ShareEventArgs(miner)); // notify the listeners about the share. @@ -136,16 +92,74 @@ public IShare ProcessShare(IVanillaMiner miner, string data) throw new NotImplementedException(); } - private bool SubmitBlock(Share share) + private void HandleValidShare(IShare share) + { + var miner = (IStratumMiner) share.Miner; + miner.ValidShares++; + + _storage.AddShare(share); // commit the share. + + if (!share.IsBlockCandidate) + { + Log.ForContext().Debug("Share accepted at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); + return; + } + + // if share contains a block candicate + Log.ForContext().Debug("Share with block candidate [{0}] accepted at {1:0.00}/{2} by miner {3:l}.", share.Height, share.Difficulty, miner.Difficulty, miner.Username); + + var accepted = SubmitBlock(share); // submit block to daemon. + + if (!accepted) + return; + + OnBlockFound(EventArgs.Empty); // notify the listeners about the new block. + + _storage.AddBlock(share); // commit the block. + } + + private void HandleInvalidShare(IShare share) + { + var miner = (IStratumMiner)share.Miner; + miner.InvalidShares++; + + switch (share.Error) + { + case ShareError.DuplicateShare: + JsonRpcContext.SetException(new DuplicateShareError(share.Nonce)); + break; + case ShareError.IncorrectExtraNonce2Size: + JsonRpcContext.SetException(new OtherError("Incorrect extranonce2 size")); + break; + case ShareError.IncorrectNTimeSize: + JsonRpcContext.SetException(new OtherError("Incorrect nTime size")); + break; + case ShareError.IncorrectNonceSize: + JsonRpcContext.SetException(new OtherError("Incorrect nonce size")); + break; + case ShareError.JobNotFound: + JsonRpcContext.SetException(new JobNotFoundError(share.JobId)); + break; + case ShareError.LowDifficultyShare: + JsonRpcContext.SetException(new LowDifficultyShare(share.Difficulty)); + break; + case ShareError.NTimeOutOfRange: + JsonRpcContext.SetException(new OtherError("nTime out of range")); + break; + } + + Log.ForContext().Debug("Share rejected at {0:0.00}/{1} by miner {2:l}.", share.Difficulty, miner.Difficulty, miner.Username); + } + + private bool SubmitBlock(IShare share) { try { _daemonClient.SubmitBlock(share.BlockHex.ToHexString()); var isAccepted = CheckIfBlockAccepted(share); - Log.ForContext() - .Information( - isAccepted + Log.ForContext().Information( + isAccepted ? "Found block [{0}] with hash: {1:l}." : "Submitted block [{0}] but got denied: {1:l}.", share.Height, share.BlockHash.ToHexString()); @@ -159,7 +173,7 @@ private bool SubmitBlock(Share share) } } - private bool CheckIfBlockAccepted(Share share) + private bool CheckIfBlockAccepted(IShare share) { try { diff --git a/src/CoiniumServ/Net/Server/IServer.cs b/src/CoiniumServ/Net/Server/IServer.cs index 891f63402..a05042f3d 100644 --- a/src/CoiniumServ/Net/Server/IServer.cs +++ b/src/CoiniumServ/Net/Server/IServer.cs @@ -20,6 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + namespace CoiniumServ.Net.Server { /// diff --git a/src/CoiniumServ/Net/Server/Sockets/Connection.cs b/src/CoiniumServ/Net/Server/Sockets/Connection.cs index 3833ff725..1a6600c79 100644 --- a/src/CoiniumServ/Net/Server/Sockets/Connection.cs +++ b/src/CoiniumServ/Net/Server/Sockets/Connection.cs @@ -67,7 +67,7 @@ public IPEndPoint LocalEndPoint /// /// The server instance that connection is bound to. /// - private SocketServer _server; + private readonly SocketServer _server; /// /// Default buffer size. @@ -177,11 +177,12 @@ public int Send(byte[] buffer, SocketFlags flags) /// Returns count of sent bytes. public int Send(IEnumerable data, SocketFlags flags) { - if (data == null) throw new ArgumentNullException("data"); + if (data == null) + throw new ArgumentNullException("data"); + if (_server == null) - { throw new Exception("[Connection] _server is null in Send"); - } + return _server.Send(this, data, flags); } @@ -225,10 +226,7 @@ public int Send(byte[] buffer, int start, int count, SocketFlags flags) public void Disconnect() { - if(Socket.Connected) - Socket.Disconnect(true); - - Client = null; + _server.RemoveConnection(this); } #endregion diff --git a/src/CoiniumServ/Net/Server/Sockets/ISocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/ISocketServer.cs new file mode 100644 index 000000000..759a71c62 --- /dev/null +++ b/src/CoiniumServ/Net/Server/Sockets/ISocketServer.cs @@ -0,0 +1,38 @@ +#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; + +namespace CoiniumServ.Net.Server.Sockets +{ + public interface ISocketServer:IServer + { + void RemoveConnection(IConnection connection); + + void Shutdown(); + + void DisconnectAll(); + + IEnumerable GetConnections(); + } +} diff --git a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs index ac6209c1e..903b2af0e 100644 --- a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs @@ -31,7 +31,7 @@ namespace CoiniumServ.Net.Server.Sockets { - public class SocketServer : IServer, IDisposable + public class SocketServer : ISocketServer, IDisposable { /// /// The IP address of the interface the server binded. @@ -196,9 +196,7 @@ private void ReceiveCallback(IAsyncResult result) Log.ForContext().Debug("Connection closed:" + connection.Client); } else - { RemoveConnection(connection); // Connection was lost. - } } catch (SocketException e) { @@ -224,6 +222,9 @@ public virtual int Send(Connection connection, byte[] buffer, int start, int cou if (buffer == null) throw new ArgumentNullException("buffer"); + if (!connection.IsConnected) + return 0; + var totalBytesSent = 0; var bytesRemaining = buffer.Length; @@ -270,29 +271,18 @@ public virtual int Send(Connection connection, IEnumerable data, SocketFla #region disconnect & shutdown handlers - public virtual void DisconnectAll() - { - lock (ConnectionLock) - { - foreach (var connection in Connections.Cast()) // Check if the connection is connected. - { - // Disconnect and raise the ClientDisconnected event. - - connection.Disconnect(); - OnClientDisconnect(new ConnectionEventArgs(connection)); - } - - Connections.Clear(); - } - } - - private void RemoveConnection(Connection connection) + public void RemoveConnection(IConnection connection) { if (connection == null) return; - // disconnect the client - connection.Disconnect(); + lock (connection) + { + if (connection.IsConnected) // disconnect the client + connection.Socket.Disconnect(true); + } + + connection.Client = null; // Remove the connection from the dictionary and raise the OnDisconnection event. lock (ConnectionLock) @@ -314,7 +304,8 @@ public virtual void Shutdown() throw new ObjectDisposedException(GetType().Name, "Server has been already disposed."); // Check if the server is actually listening. - if (!IsListening) return; + if (!IsListening) + return; // Close the listener socket. if (Listener != null) @@ -324,15 +315,26 @@ public virtual void Shutdown() } // Disconnect the clients. - foreach (var connection in Connections.ToList()) // use ToList() so we don't get collection modified exception there - { - connection.Disconnect(); - } + DisconnectAll(); Listener = null; IsListening = false; } + public virtual void DisconnectAll() + { + lock (ConnectionLock) + { + foreach (var connection in Connections.ToList()) // using ToList() to get a copy in order to prevent any modified collection exceptions. + { + RemoveConnection(connection); + } + + Connections.Clear(); + } + } + + #endregion #region service methods diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 3bf47fd8d..25d2fdbee 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -23,6 +23,7 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Miners; @@ -67,6 +68,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 7b4345e4e..6de1e21fb 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; @@ -47,6 +48,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 45114cfdf..282348ced 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -64,6 +64,9 @@ public class StratumMiner : IClient, IStratumMiner /// public bool Authenticated { get; set; } + public int ValidShares { get; set; } + public int InvalidShares { get; set; } + public IPool Pool { get; private set; } public float Difficulty { get; set; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index e9782cc0a..8ecd92854 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -69,9 +69,9 @@ public void Initialize(IServerConfig config) BindIP = config.BindInterface; Port = config.Port; - ClientConnected += StratumServer_ClientConnected; - ClientDisconnected += StratumServer_ClientDisconnected; - DataReceived += StratumServer_DataReceived; + ClientConnected += OnClientConnection; + ClientDisconnected += OnClientDisconnection; + DataReceived += OnClientRecieveData; } /// @@ -98,7 +98,7 @@ public override bool Stop() /// /// /// - private void StratumServer_ClientConnected(object sender, ConnectionEventArgs e) + private void OnClientConnection(object sender, ConnectionEventArgs e) { Log.ForContext().Information("Stratum client connected: {0}", e.Connection.ToString()); @@ -112,7 +112,7 @@ private void StratumServer_ClientConnected(object sender, ConnectionEventArgs e) /// /// /// - private void StratumServer_ClientDisconnected(object sender, ConnectionEventArgs e) + private void OnClientDisconnection(object sender, ConnectionEventArgs e) { Log.ForContext().Information("Stratum client disconnected: {0}", e.Connection.ToString()); @@ -124,7 +124,7 @@ private void StratumServer_ClientDisconnected(object sender, ConnectionEventArgs /// /// /// - private void StratumServer_DataReceived(object sender, ConnectionDataEventArgs e) + private void OnClientRecieveData(object sender, ConnectionDataEventArgs e) { var connection = (Connection)e.Connection; ((StratumMiner)connection.Client).Parse(e); diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 28652f2a1..b881ba77b 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -28,7 +28,6 @@ using AustinHarris.JsonRpc; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; -using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Vanilla.Service; using CoiniumServ.Utils.Extensions; using Serilog; @@ -52,6 +51,9 @@ public class VanillaMiner : IVanillaMiner /// public bool Authenticated { get; set; } + public int ValidShares { get; set; } + public int InvalidShares { get; set; } + public IPool Pool { get; private set; } private readonly IMinerManager _minerManager; diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 8ea8f7f8c..a8e781bb1 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -42,7 +42,6 @@ public WebServer(IApplicationContext applicationContext, IGlobalConfigFactory gl BindIP = Config.BindInterface; Port = Config.Port; - if (Config.Enabled) Start(); diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index cbdd42432..c36c6d26d 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -25,6 +25,7 @@ using CoiniumServ.Crypto.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Miners; @@ -58,6 +59,7 @@ public class PoolTests private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; + private readonly IBanningManagerFactory _banningManagerFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -71,6 +73,7 @@ public class PoolTests private readonly IPaymentProcessor _paymentProcessor; private readonly IStatistics _statistics; private readonly IVardiffManager _vardiffManager; + private readonly IBanningManager _banningManager; /// /// Initialize mock objects. @@ -88,6 +91,7 @@ public PoolTests() _paymentProcessorFactory = Substitute.For(); _statisticsObjectFactory = Substitute.For(); _vardiffManagerFactory = Substitute.For(); + _banningManagerFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -100,6 +104,7 @@ public PoolTests() _paymentProcessor = Substitute.For(); _statistics = Substitute.For(); _vardiffManager = Substitute.For(); + _banningManager = Substitute.For(); } /// @@ -120,8 +125,8 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _storageFactory, _paymentProcessorFactory, _statisticsObjectFactory, - _vardiffManagerFactory - ); + _vardiffManagerFactory, + _banningManagerFactory); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -145,8 +150,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _storageFactory, _paymentProcessorFactory, _statisticsObjectFactory, - _vardiffManagerFactory - ); + _vardiffManagerFactory, + _banningManagerFactory); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -181,6 +186,10 @@ public void InitializationTest_NonNullParams_ShouldSuccess() var vardiffConfig = Substitute.For(); _vardiffManagerFactory.Get(vardiffConfig, _shareManager); + // banning manager + var banningConfig = Substitute.For(); + _banningManagerFactory.Get(banningConfig, _shareManager); + // initalize job manager. _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig,rewardsConfig).Returns(_jobManager); _jobManager.Initialize(pool.InstanceId); From f698cc942e267ede38ddcebdaa9bb434c21a99a9 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 18 Jul 2014 13:41:09 +0300 Subject: [PATCH 084/230] BanManager implementation complete. --- src/CoiniumServ/CoiniumServ.csproj | 17 +- src/CoiniumServ/Mining/Banning/BanManager.cs | 160 ++++++++++++++++++ ...ManagerFactory.cs => BanManagerFactory.cs} | 10 +- .../Mining/Banning/BanningManager.cs | 83 --------- .../{IBanningManager.cs => IBanManager.cs} | 7 +- ...anagerFactory.cs => IBanManagerFactory.cs} | 4 +- .../Config/{BanningConfig.cs => BanConfig.cs} | 4 +- .../{IBanningConfig.cs => IBanConfig.cs} | 2 +- .../Mining/Pools/Config/IPoolConfig.cs | 2 +- .../Mining/Pools/Config/PoolConfig.cs | 4 +- src/CoiniumServ/Mining/Pools/Pool.cs | 10 +- .../Sockets/BannedConnectionEventArgs.cs | 38 +++++ .../Net/Server/Sockets/SocketServer.cs | 70 +++++--- .../Repository/Registries/FactoryRegistry.cs | 2 +- .../Repository/Registries/ManagerRegistry.cs | 2 +- src/CoiniumServ/Server/IServerFactory.cs | 3 +- .../Server/Mining/Stratum/StratumServer.cs | 34 +++- src/CoiniumServ/Server/ServerFactory.cs | 8 +- src/CoiniumServ/packages.config | 2 +- src/Tests/Mining/Pools/PoolTests.cs | 18 +- 20 files changed, 324 insertions(+), 156 deletions(-) create mode 100644 src/CoiniumServ/Mining/Banning/BanManager.cs rename src/CoiniumServ/Mining/Banning/{BanningManagerFactory.cs => BanManagerFactory.cs} (82%) delete mode 100644 src/CoiniumServ/Mining/Banning/BanningManager.cs rename src/CoiniumServ/Mining/Banning/{IBanningManager.cs => IBanManager.cs} (89%) rename src/CoiniumServ/Mining/Banning/{IBanningManagerFactory.cs => IBanManagerFactory.cs} (89%) rename src/CoiniumServ/Mining/Pools/Config/{BanningConfig.cs => BanConfig.cs} (94%) rename src/CoiniumServ/Mining/Pools/Config/{IBanningConfig.cs => IBanConfig.cs} (97%) create mode 100644 src/CoiniumServ/Net/Server/Sockets/BannedConnectionEventArgs.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 334e20d56..8b4f5f608 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -89,11 +89,11 @@ False - ..\..\build\packages\Serilog.1.3.34\lib\net45\Serilog.dll + ..\..\build\packages\Serilog.1.3.35\lib\net45\Serilog.dll False - ..\..\build\packages\Serilog.1.3.34\lib\net45\Serilog.FullNetFx.dll + ..\..\build\packages\Serilog.1.3.35\lib\net45\Serilog.FullNetFx.dll False @@ -110,12 +110,12 @@ - - - - - - + + + + + + @@ -163,6 +163,7 @@ + diff --git a/src/CoiniumServ/Mining/Banning/BanManager.cs b/src/CoiniumServ/Mining/Banning/BanManager.cs new file mode 100644 index 000000000..761d1b10c --- /dev/null +++ b/src/CoiniumServ/Mining/Banning/BanManager.cs @@ -0,0 +1,160 @@ +#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.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Utils.Helpers.Time; +using Serilog; + +namespace CoiniumServ.Mining.Banning +{ + public class BanManager:IBanManager + { + public IBanConfig Config { get; private set; } + + private readonly Dictionary _bannedIps; + + private readonly Timer _timer; + + public BanManager(IBanConfig banConfig, IShareManager shareManager) + { + Config = banConfig; + + if (!Config.Enabled) + return; + + _bannedIps = new Dictionary(); + shareManager.ShareSubmitted += OnShare; + + _timer = new Timer(CheckBans, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + CheckBans(null); + } + + private void OnShare(object sender, EventArgs e) + { + var shareArgs = (ShareEventArgs)e; + var miner = shareArgs.Miner; + + if (miner == null) + return; + + var totalShares = miner.ValidShares + miner.InvalidShares; + + if (totalShares < Config.CheckThreshold) // check if we exceeded the threshold for checks. + return; + + var invalidPercentage = miner.InvalidShares/totalShares*100; + + if (invalidPercentage < Config.InvalidPercent) + // if the miner didn't reach the invalid share percentage, reset his stats. + { + miner.ValidShares = 0; + miner.InvalidShares = 0; + } + else // he needs a ban + { + Log.ForContext().Information("Banned miner {0:l} because of high percentage of invalid shares: {1}%.", miner.Username, invalidPercentage); + Ban(miner); + } + } + + private void Ban(IMiner miner) + { + // TODO: add vanilla miners to banlist too. + if (miner is IVanillaMiner) // as vanilla miners doesn't use persistent connections, we don't need to disconect him + return; // but just blacklist his ip. + + var client = (IClient) miner; + var ip = client.Connection.RemoteEndPoint.Address; + + if(!_bannedIps.ContainsKey(ip)) + _bannedIps.Add(ip, TimeHelpers.NowInUnixTime()); + + client.Connection.Disconnect(); + } + + public bool IsBanned(IPAddress ip) + { + if (!_bannedIps.ContainsKey(ip)) // check if ip exists in banlist. + return false; + + if (!BanExpired(ip)) // if ip has still an ongoing ban. + return true; + + // if the code flow reaches here, it means the ban has been expired, so remove it first. + RemoveBan(ip); + return false; + } + + public void CheckBans(object state) + { + var expiredBans = 0; + var banlist = _bannedIps.ToDictionary(x => x.Key); // get a copy of the current banlist + + foreach (var pair in banlist) + { + if (!BanExpired(pair.Key)) // check if the ip should be still banned? + continue; + + expiredBans++; + RemoveBan(pair.Key); + } + + var remainingBans = _bannedIps.Count; + + Log.ForContext().Information( + expiredBans > 0 + ? "Cleared {0} expired bans [remaining bans: {1}]." + : "No expired bans found to be cleared [remaining bans: {1}].", expiredBans, remainingBans); + + // reset the recache timer. + _timer.Change(Config.PurgeInterval * 1000, Timeout.Infinite); + } + + private bool BanExpired(IPAddress ip) + { + var banTime = _bannedIps[ip]; + + var elapsedTime = TimeHelpers.NowInUnixTime() - banTime; // elapsed time since his ban. + var timeLeft = Config.Duration - elapsedTime; // time left for his ban + + if (timeLeft > 0) // if he has still remaining time + return false; + + return true; + } + + private void RemoveBan(IPAddress ip) + { + _bannedIps.Remove(ip); + } + } +} diff --git a/src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs b/src/CoiniumServ/Mining/Banning/BanManagerFactory.cs similarity index 82% rename from src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs rename to src/CoiniumServ/Mining/Banning/BanManagerFactory.cs index 752c59eca..1adf098e0 100644 --- a/src/CoiniumServ/Mining/Banning/BanningManagerFactory.cs +++ b/src/CoiniumServ/Mining/Banning/BanManagerFactory.cs @@ -28,7 +28,7 @@ namespace CoiniumServ.Mining.Banning { - public class BanningManagerFactory : IBanningManagerFactory + public class BanManagerFactory : IBanManagerFactory { /// /// The _kernel @@ -39,20 +39,20 @@ public class BanningManagerFactory : IBanningManagerFactory /// Initializes a new instance of the class. /// /// The application context. - public BanningManagerFactory(IApplicationContext applicationContext) + public BanManagerFactory(IApplicationContext applicationContext) { _applicationContext = applicationContext; } - public IBanningManager Get(IBanningConfig banningConfig, IShareManager shareManager) + public IBanManager Get(IBanConfig banConfig, IShareManager shareManager) { var @params = new NamedParameterOverloads { - {"banningConfig", banningConfig}, + {"banConfig", banConfig}, {"shareManager", shareManager}, }; - return _applicationContext.Container.Resolve(@params); + return _applicationContext.Container.Resolve(@params); } } } diff --git a/src/CoiniumServ/Mining/Banning/BanningManager.cs b/src/CoiniumServ/Mining/Banning/BanningManager.cs deleted file mode 100644 index 9fe1588a2..000000000 --- a/src/CoiniumServ/Mining/Banning/BanningManager.cs +++ /dev/null @@ -1,83 +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; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Net.Server.Sockets; -using CoiniumServ.Server.Mining.Vanilla; - -namespace CoiniumServ.Mining.Banning -{ - public class BanningManager:IBanningManager - { - public IBanningConfig Config { get; private set; } - - public BanningManager(IBanningConfig banningConfig, IShareManager shareManager) - { - Config = banningConfig; - - if (!Config.Enabled) - return; - - shareManager.ShareSubmitted += OnShare; - } - - private void OnShare(object sender, EventArgs e) - { - var shareArgs = (ShareEventArgs)e; - var miner = shareArgs.Miner; - - if (miner == null) - return; - - var totalShares = miner.ValidShares + miner.InvalidShares; - - if (totalShares < Config.CheckThreshold) // check if we exceeded the threshold for checks. - return; - - var invalidPercentage = miner.InvalidShares/totalShares*100; - - if (invalidPercentage < Config.InvalidPercent) - // if the miner didn't reach the invalid share percentage, reset his stats. - { - miner.ValidShares = 0; - miner.InvalidShares = 0; - } - else // he needs a ban - Ban(miner); - } - - private void Ban(IMiner miner) - { - // todo: add ip to banlist. - - if (miner is IVanillaMiner) // as vanilla miners doesn't use persistent connections, we don't need to disconect him - return; // but just blacklist hip ip. - - var client = (IClient) miner; - client.Connection.Disconnect(); - } - } -} diff --git a/src/CoiniumServ/Mining/Banning/IBanningManager.cs b/src/CoiniumServ/Mining/Banning/IBanManager.cs similarity index 89% rename from src/CoiniumServ/Mining/Banning/IBanningManager.cs rename to src/CoiniumServ/Mining/Banning/IBanManager.cs index 8b4150f54..4d3ed304a 100644 --- a/src/CoiniumServ/Mining/Banning/IBanningManager.cs +++ b/src/CoiniumServ/Mining/Banning/IBanManager.cs @@ -21,12 +21,15 @@ // #endregion +using System.Net; using CoiniumServ.Mining.Pools.Config; namespace CoiniumServ.Mining.Banning { - public interface IBanningManager + public interface IBanManager { - IBanningConfig Config { get; } + IBanConfig Config { get; } + + bool IsBanned(IPAddress ip); } } diff --git a/src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs b/src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs similarity index 89% rename from src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs rename to src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs index d05df876a..c166a1c35 100644 --- a/src/CoiniumServ/Mining/Banning/IBanningManagerFactory.cs +++ b/src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs @@ -26,8 +26,8 @@ namespace CoiniumServ.Mining.Banning { - public interface IBanningManagerFactory + public interface IBanManagerFactory { - IBanningManager Get(IBanningConfig banningConfig, IShareManager shareManager); + IBanManager Get(IBanConfig banConfig, IShareManager shareManager); } } diff --git a/src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs similarity index 94% rename from src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs rename to src/CoiniumServ/Mining/Pools/Config/BanConfig.cs index ac555f207..eaf4c43b9 100644 --- a/src/CoiniumServ/Mining/Pools/Config/BanningConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs @@ -23,7 +23,7 @@ namespace CoiniumServ.Mining.Pools.Config { - public class BanningConfig : IBanningConfig + public class BanConfig : IBanConfig { public bool Enabled { get; private set; } public int Duration { get; private set; } @@ -31,7 +31,7 @@ public class BanningConfig : IBanningConfig public int CheckThreshold { get; private set; } public int PurgeInterval { get; private set; } - public BanningConfig(dynamic config) + public BanConfig(dynamic config) { Enabled = config.enabled; Duration = config.duration; diff --git a/src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs rename to src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs index 0c5a0ac0c..b232991be 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IBanningConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs @@ -23,7 +23,7 @@ namespace CoiniumServ.Mining.Pools.Config { - public interface IBanningConfig + public interface IBanConfig { bool Enabled { get; } diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 55ad3e60d..2f5957af2 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -51,6 +51,6 @@ public interface IPoolConfig:IConfig IPaymentConfig Payments { get; } - IBanningConfig Banning { get; } + IBanConfig Banning { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index e008e5b7a..2c5111952 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -55,7 +55,7 @@ public class PoolConfig : IPoolConfig public IPaymentConfig Payments { get; private set; } - public IBanningConfig Banning { get; private set; } + public IBanConfig Banning { get; private set; } /// /// Initializes a new instance of the class. @@ -111,7 +111,7 @@ public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) return; } - Banning = new BanningConfig(config.banning); + Banning = new BanConfig(config.banning); Valid = true; } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index e05dfbff8..54310339f 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -67,7 +67,7 @@ public class Pool : IPool private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; - private readonly IBanningManagerFactory _banningManagerFactory; + private readonly IBanManagerFactory _banningManagerFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -77,7 +77,7 @@ public class Pool : IPool private IHashAlgorithm _hashAlgorithm; private IPaymentProcessor _paymentProcessor; private IVardiffManager _vardiffManager; - private IBanningManager _banningManager; + private IBanManager _banningManager; private Dictionary _servers; @@ -115,7 +115,7 @@ public Pool( IPaymentProcessorFactory paymentProcessorFactory, IStatisticsObjectFactory statisticsObjectFactory, IVardiffManagerFactory vardiffManagerFactory, - IBanningManagerFactory banningManagerFactory) + IBanManagerFactory banningManagerFactory) { Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); @@ -209,7 +209,7 @@ private void InitServers() if (Config.Stratum != null && Config.Stratum.Enabled) { - var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager); + var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager, _banningManager); var stratumService = _serviceFactory.Get("Stratum", Config.Coin, _shareManager, _daemonClient); stratumServer.Initialize(Config.Stratum); @@ -218,7 +218,7 @@ private void InitServers() if (Config.Vanilla != null && Config.Vanilla.Enabled) { - var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager); + var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager, _banningManager); var vanillaService = _serviceFactory.Get("Vanilla", Config.Coin, _shareManager, _daemonClient); vanillaServer.Initialize(Config.Vanilla); diff --git a/src/CoiniumServ/Net/Server/Sockets/BannedConnectionEventArgs.cs b/src/CoiniumServ/Net/Server/Sockets/BannedConnectionEventArgs.cs new file mode 100644 index 000000000..7698cc653 --- /dev/null +++ b/src/CoiniumServ/Net/Server/Sockets/BannedConnectionEventArgs.cs @@ -0,0 +1,38 @@ +#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.Net; + +namespace CoiniumServ.Net.Server.Sockets +{ + public class BannedConnectionEventArgs:EventArgs + { + public IPEndPoint Endpoint { get; private set; } + + public BannedConnectionEventArgs(EndPoint endpoint) + { + Endpoint = (IPEndPoint)endpoint; + } + } +} diff --git a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs index 903b2af0e..4d425fc8e 100644 --- a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs @@ -65,11 +65,13 @@ public class SocketServer : ISocketServer, IDisposable // connection event handlers. public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e); + public delegate void BannedConnectionEventHandler(object sender, BannedConnectionEventArgs e); public delegate void ConnectionDataEventHandler(object sender, ConnectionDataEventArgs e); // connection events. public event ConnectionEventHandler ClientConnected; public event ConnectionEventHandler ClientDisconnected; + public event BannedConnectionEventHandler BannedConnection; public event ConnectionDataEventHandler DataReceived; public event ConnectionDataEventHandler DataSent; @@ -78,19 +80,6 @@ public class SocketServer : ISocketServer, IDisposable /// private bool _disposed; - #region server control - public virtual bool Start() - { - throw new NotImplementedException(); - } - - public virtual bool Stop() - { - throw new NotImplementedException(); - } - - #endregion - #region listener & accept callbacks. /// @@ -153,14 +142,25 @@ private void AcceptCallback(IAsyncResult result) try { var socket = Listener.EndAccept(result); // Finish accepting the incoming connection. - var connection = new Connection(this, socket); // Track the connection. + var banned = IsBanned(socket); + + if (banned) + { + var endpoint = socket.RemoteEndPoint; + socket.Disconnect(true); + OnBannedConnection(new BannedConnectionEventArgs(endpoint)); + } + else + { + var connection = new Connection(this, socket); // Track the connection. - lock (ConnectionLock) - Connections.Add(connection); // Add the new connection to the active connections list. + lock (ConnectionLock) + Connections.Add(connection); // Add the new connection to the active connections list. - OnClientConnection(new ConnectionEventArgs(connection)); // Raise the ClientConnected event. + OnClientConnection(new ConnectionEventArgs(connection)); // Raise the ClientConnected event. + connection.BeginReceive(ReceiveCallback, connection); // Begin receiving on the new connection connection. + } - connection.BeginReceive(ReceiveCallback, connection); // Begin receiving on the new connection connection. Listener.BeginAccept(AcceptCallback, null); // Continue receiving other incoming connection asynchronously. } catch (NullReferenceException) { } // we recive this after issuing server-shutdown, just ignore it. @@ -170,6 +170,11 @@ private void AcceptCallback(IAsyncResult result) //} } + public virtual bool IsBanned(Socket socket) + { + return false; + } + #endregion #region recieve callback @@ -348,9 +353,22 @@ public IEnumerable GetConnections() #endregion + #region server control + public virtual bool Start() + { + throw new NotImplementedException(); + } + + public virtual bool Stop() + { + throw new NotImplementedException(); + } + + #endregion + #region events - protected virtual void OnClientConnection(ConnectionEventArgs e) + private void OnClientConnection(ConnectionEventArgs e) { var handler = ClientConnected; @@ -358,7 +376,7 @@ protected virtual void OnClientConnection(ConnectionEventArgs e) handler(this, e); } - protected virtual void OnClientDisconnect(ConnectionEventArgs e) + private void OnClientDisconnect(ConnectionEventArgs e) { var handler = ClientDisconnected; @@ -366,7 +384,15 @@ protected virtual void OnClientDisconnect(ConnectionEventArgs e) handler(this, e); } - protected virtual void OnDataReceived(ConnectionDataEventArgs e) + private void OnBannedConnection(BannedConnectionEventArgs e) + { + var handler = BannedConnection; + + if (handler != null) + handler(this, e); + } + + private void OnDataReceived(ConnectionDataEventArgs e) { var handler = DataReceived; @@ -374,7 +400,7 @@ protected virtual void OnDataReceived(ConnectionDataEventArgs e) handler(this, e); } - protected virtual void OnDataSent(ConnectionDataEventArgs e) + private void OnDataSent(ConnectionDataEventArgs e) { var handler = DataSent; diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 25d2fdbee..759823a67 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -68,7 +68,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 6de1e21fb..d3fd4da32 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -48,7 +48,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); } } } diff --git a/src/CoiniumServ/Server/IServerFactory.cs b/src/CoiniumServ/Server/IServerFactory.cs index 87c857216..a275b6a7e 100644 --- a/src/CoiniumServ/Server/IServerFactory.cs +++ b/src/CoiniumServ/Server/IServerFactory.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; @@ -31,7 +32,7 @@ namespace CoiniumServ.Server { public interface IServerFactory { - IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager); + IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager); IWebServer Get(string serverName, IPoolManager poolManager); } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index 8ecd92854..ed5460275 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -21,6 +21,10 @@ // #endregion +using System; +using System.Net; +using System.Net.Sockets; +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; @@ -37,7 +41,6 @@ namespace CoiniumServ.Server.Mining.Stratum /// public class StratumServer : SocketServer, IMiningServer { - public IServerConfig Config { get; private set; } private readonly IPool _pool; @@ -46,17 +49,20 @@ public class StratumServer : SocketServer, IMiningServer private readonly IJobManager _jobManager; + private readonly IBanManager _banManager; + /// /// Initializes a new instance of the class. /// /// /// The miner manager. /// - public StratumServer(IPool pool, IMinerManager minerManager, IJobManager jobManager) + public StratumServer(IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager) { _pool = pool; _minerManager = minerManager; _jobManager = jobManager; + _banManager = banManager; } /// @@ -70,8 +76,9 @@ public void Initialize(IServerConfig config) Port = config.Port; ClientConnected += OnClientConnection; - ClientDisconnected += OnClientDisconnection; - DataReceived += OnClientRecieveData; + ClientDisconnected += OnClientDisconnect; + BannedConnection += OnBannedConnection; + DataReceived += OnDataReceived; } /// @@ -90,7 +97,13 @@ public override bool Start() /// public override bool Stop() { - return true; + throw new NotImplementedException(); + } + + public override bool IsBanned(Socket socket) + { + var endpoint = (IPEndPoint) socket.RemoteEndPoint; + return _banManager.IsBanned(endpoint.Address); } /// @@ -112,22 +125,27 @@ private void OnClientConnection(object sender, ConnectionEventArgs e) /// /// /// - private void OnClientDisconnection(object sender, ConnectionEventArgs e) + private void OnClientDisconnect(object sender, ConnectionEventArgs e) { Log.ForContext().Information("Stratum client disconnected: {0}", e.Connection.ToString()); _minerManager.Remove(e.Connection); } + private void OnBannedConnection(object sender, BannedConnectionEventArgs e) + { + Log.ForContext().Information("Rejected connection from banned ip: {0:l}", e.Endpoint.Address.ToString()); + } + /// /// Client data recieve handler. /// /// /// - private void OnClientRecieveData(object sender, ConnectionDataEventArgs e) + private void OnDataReceived(object sender, ConnectionDataEventArgs e) { var connection = (Connection)e.Connection; ((StratumMiner)connection.Client).Parse(e); - } + } } } diff --git a/src/CoiniumServ/Server/ServerFactory.cs b/src/CoiniumServ/Server/ServerFactory.cs index 0433a9321..16c8f45ba 100644 --- a/src/CoiniumServ/Server/ServerFactory.cs +++ b/src/CoiniumServ/Server/ServerFactory.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; @@ -46,14 +47,17 @@ public ServerFactory(IApplicationContext applicationContext) /// Name of the service. /// /// The miner manager. + /// + /// /// - public IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager) + public IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager) { var @params = new NamedParameterOverloads { {"pool", pool}, {"minerManager", minerManager}, - {"jobManager", jobManager} + {"jobManager", jobManager}, + {"banManager", banManager} }; return _applicationContext.Container.Resolve(serverName, @params); diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 0f7bdbf95..20f96ad9a 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index c36c6d26d..0d9bfdc4c 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -59,7 +59,7 @@ public class PoolTests private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; - private readonly IBanningManagerFactory _banningManagerFactory; + private readonly IBanManagerFactory _banManagerFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -73,7 +73,7 @@ public class PoolTests private readonly IPaymentProcessor _paymentProcessor; private readonly IStatistics _statistics; private readonly IVardiffManager _vardiffManager; - private readonly IBanningManager _banningManager; + private readonly IBanManager _banManager; /// /// Initialize mock objects. @@ -91,7 +91,7 @@ public PoolTests() _paymentProcessorFactory = Substitute.For(); _statisticsObjectFactory = Substitute.For(); _vardiffManagerFactory = Substitute.For(); - _banningManagerFactory = Substitute.For(); + _banManagerFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -104,7 +104,7 @@ public PoolTests() _paymentProcessor = Substitute.For(); _statistics = Substitute.For(); _vardiffManager = Substitute.For(); - _banningManager = Substitute.For(); + _banManager = Substitute.For(); } /// @@ -126,7 +126,7 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() _paymentProcessorFactory, _statisticsObjectFactory, _vardiffManagerFactory, - _banningManagerFactory); + _banManagerFactory); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -151,7 +151,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _paymentProcessorFactory, _statisticsObjectFactory, _vardiffManagerFactory, - _banningManagerFactory); + _banManagerFactory); pool.Should().Not.Be.Null(); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); @@ -187,8 +187,8 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _vardiffManagerFactory.Get(vardiffConfig, _shareManager); // banning manager - var banningConfig = Substitute.For(); - _banningManagerFactory.Get(banningConfig, _shareManager); + var banConfig = Substitute.For(); + _banManagerFactory.Get(banConfig, _shareManager); // initalize job manager. _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig,rewardsConfig).Returns(_jobManager); @@ -200,7 +200,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _daemonClient.GetMiningInfo().Returns(new MiningInfo()); // init server - _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager).Returns(_miningServer); + _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager,_banManager).Returns(_miningServer); // init service _serviceFactory.Get(Services.Stratum, poolConfig.Coin, _shareManager, _daemonClient).Returns(_rpcService); From fbbba7ef73258d117e7eebc1b61106d5ccc47002 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 18 Jul 2014 13:54:46 +0300 Subject: [PATCH 085/230] Added connection timeout to redis. Improved redis connection error & info messages. --- src/CoiniumServ/Persistance/Redis/Redis.cs | 40 +++++++++++++--------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index a03fc5114..d150101b9 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -419,7 +419,8 @@ private void Initialize() { var options = new ConfigurationOptions() { - AllowAdmin = true + AllowAdmin = true, + ConnectTimeout = 1000, }; var endpoint = new DnsEndPoint(_redisConfig.Host, _redisConfig.Port, AddressFamily.InterNetwork); @@ -440,27 +441,34 @@ private void Initialize() _server = _connectionMultiplexer.GetServer(endpoint); // check the version - var info = _server.Info(); - Version version = null; - foreach (var pair in info[0]) - { - if (pair.Key == "redis_version") - { - version = new Version(pair.Value); - if (version < _requiredMinimumVersion) - throw new Exception(string.Format("You are using redis version {0}, minimum required version is 2.6", version)); + var version = GetVersion(); + if (version < _requiredMinimumVersion) + throw new Exception(string.Format("You are using redis version {0}, minimum required version is 2.6", version)); - break; - } - } - - Log.ForContext().Information("Storage initialized: {0:l}, v{1:l}.", endpoint, version); + Log.ForContext().Information("Storage initialized: {0:l}:{1}, v{2:l}.", endpoint.Host, endpoint.Port, version); } catch (Exception e) { IsEnabled = false; - Log.ForContext().Error(e, string.Format("Storage initialization failed: {0}", endpoint)); + Log.ForContext().Error(string.Format("Storage initialization failed: {0:l}:{1}.", endpoint.Host, endpoint.Port)); } } + + private Version GetVersion() + { + Version version = null; + var info = _server.Info(); + + foreach (var pair in info[0]) + { + if (pair.Key != "redis_version") + continue; + + version = new Version(pair.Value); + break; + } + + return version; + } } } From 7ed4a54bc57643b365fd8bd5a51e84627b039801 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 18 Jul 2014 15:31:21 +0300 Subject: [PATCH 086/230] Added SHA256 support. Added blake-256 support. Moved diff1 to Algorithms.cs:diff1 as static. --- src/CoiniumServ/CoiniumServ.csproj | 2 + .../Crypto/Algorithms/Algorithms.cs | 15 ++++++ src/CoiniumServ/Crypto/Algorithms/Blake.cs | 46 +++++++++++++++++ .../Crypto/Algorithms/HashAlgorithmFactory.cs | 2 +- .../Crypto/Algorithms/IHashAlgorithm.cs | 3 -- src/CoiniumServ/Crypto/Algorithms/Scrypt.cs | 25 +++------ src/CoiniumServ/Crypto/Algorithms/Sha256.cs | 51 +++++++++++++++++++ src/CoiniumServ/Crypto/Utils.cs | 1 + .../Mining/Jobs/Manager/JobManager.cs | 2 +- src/CoiniumServ/Mining/Shares/Share.cs | 3 +- .../Repository/Registries/ClassRegistry.cs | 1 + .../Mining/Stratum/Notifications/Job.cs | 2 +- 12 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 src/CoiniumServ/Crypto/Algorithms/Blake.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/Sha256.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 8b4f5f608..ccda4194d 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -110,6 +110,8 @@ + + diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs index ca197c708..c92cf0cf4 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs @@ -20,10 +20,25 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System.Globalization; +using CoiniumServ.Utils.Numerics; + namespace CoiniumServ.Crypto.Algorithms { public static class Algorithms { public const string Scrypt = "scrypt"; + public const string Sha256 = "sha256"; + + /// + /// Global diff1 + /// + public static BigInteger Diff1 { get; private set; } + + static Algorithms() + { + Diff1 = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + } } } diff --git a/src/CoiniumServ/Crypto/Algorithms/Blake.cs b/src/CoiniumServ/Crypto/Algorithms/Blake.cs new file mode 100644 index 000000000..def05e825 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Blake.cs @@ -0,0 +1,46 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Blake : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Blake() + { + _hasher = HashFactory.Crypto.SHA3.CreateBlake256(); + Multiplier = (UInt32) Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs index d943e6de1..bdbc3aa04 100644 --- a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs @@ -48,7 +48,7 @@ public HashAlgorithmFactory(IApplicationContext applicationContext) /// public IHashAlgorithm Get(string algorithmName) { - // Default to Scrypt + // Default to scrypt if (string.IsNullOrWhiteSpace(algorithmName)) algorithmName = Algorithms.Scrypt; diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs index 0a3885c9c..70ab921f1 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs @@ -22,7 +22,6 @@ #endregion using System; -using CoiniumServ.Utils.Numerics; namespace CoiniumServ.Crypto.Algorithms { @@ -31,7 +30,5 @@ public interface IHashAlgorithm UInt32 Multiplier { get; } byte[] Hash(byte[] input); - - BigInteger Difficulty { get; } } } \ No newline at end of file diff --git a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs index 255bf412d..bd2001f2e 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs @@ -38,43 +38,34 @@ public class Scrypt : IHashAlgorithm /// public UInt32 Multiplier { get; private set; } - /// - /// Gets the difficulty. - /// - /// - /// The difficulty. - /// - public BigInteger Difficulty { get; private set; } - /// /// N parameter - CPU/memory cost parameter. /// - public int N { get; private set; } + private readonly int _n; /// /// R parameter - block size. /// - public int R { get; private set; } + private readonly int _r; /// /// P - parallelization parameter - a large value of p can increase computational /// cost of scrypt without increasing the memory usage. /// - public int P { get; private set; } + private readonly int _p; public Scrypt() { - N = 1024; - R = 1; - P = 1; - Multiplier = (UInt32) Math.Pow(2, 16); + _n = 1024; + _r = 1; + _p = 1; - Difficulty = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + Multiplier = (UInt32) Math.Pow(2, 16); } public byte[] Hash(byte[] input) { - var result = SCrypt.ComputeDerivedKey(input, input, N, R, P, null, 32); + var result = SCrypt.ComputeDerivedKey(input, input, _n, _r, _p, null, 32); return result; } } diff --git a/src/CoiniumServ/Crypto/Algorithms/Sha256.cs b/src/CoiniumServ/Crypto/Algorithms/Sha256.cs new file mode 100644 index 000000000..bca27b316 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Sha256.cs @@ -0,0 +1,51 @@ +#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.Security.Cryptography; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Sha256:IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly SHA256Managed _algorithm; + + public Sha256() + { + _algorithm = new SHA256Managed(); + Multiplier = 1; + } + + public byte[] Hash(byte[] input) + { + return DoubleDigest(input); // coins like bitcoin (sha256d coins) uses double-digest. + } + + public byte[] DoubleDigest(byte[] input) + { + var first = _algorithm.ComputeHash(input); + return _algorithm.ComputeHash(first); + } + } +} diff --git a/src/CoiniumServ/Crypto/Utils.cs b/src/CoiniumServ/Crypto/Utils.cs index 12da9b77b..a446ced1e 100644 --- a/src/CoiniumServ/Crypto/Utils.cs +++ b/src/CoiniumServ/Crypto/Utils.cs @@ -33,6 +33,7 @@ public static class Utils /// public static byte[] DoubleDigest(this byte[] input) { + // TODO: instead use SHA256.cs. return DoubleDigest(input, 0, input.Length); } diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index b5f00cb8e..16cd25fc8 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -62,7 +62,7 @@ public class JobManager : IJobManager private Timer _timer; - private const int TimerExpiration = 10; + private const int TimerExpiration = 60; public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig) { diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index 9ad5bac69..901684f0d 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -24,6 +24,7 @@ using System; using CoiniumServ.Coin.Coinbase; using CoiniumServ.Crypto; +using CoiniumServ.Crypto.Algorithms; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Miners; using CoiniumServ.Server.Mining.Stratum; @@ -119,7 +120,7 @@ public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, st HeaderValue = new BigInteger(HeaderHash); // calculate the share difficulty - Difficulty = ((double)new BigRational(Job.HashAlgorithm.Difficulty, HeaderValue)) * Job.HashAlgorithm.Multiplier; + Difficulty = ((double)new BigRational(Algorithms.Diff1, HeaderValue)) * Job.HashAlgorithm.Multiplier; // calculate the block difficulty BlockDiffAdjusted = Job.Difficulty * Job.HashAlgorithm.Multiplier; diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index a64311f45..527c576fc 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -46,6 +46,7 @@ public ClassRegistry(IApplicationContext applicationContext) public void RegisterInstances() { _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Scrypt).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Sha256).AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs index 77a1131ef..549c510e4 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs @@ -155,7 +155,7 @@ public Job(UInt64 id, IHashAlgorithm algorithm, IBlockTemplate blockTemplate, IG : BigInteger.Parse(blockTemplate.Target, NumberStyles.HexNumber); // set the block diff - Difficulty = ((double)new BigRational(HashAlgorithm.Difficulty, Target)); + Difficulty = ((double)new BigRational(Algorithms.Diff1, Target)); // set the ntime nTime = BitConverter.GetBytes(blockTemplate.CurTime.BigEndian()).ToHexString(); From 17379939f04323818b9e89abf355694a66d6761b Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 18 Jul 2014 16:17:32 +0300 Subject: [PATCH 087/230] Added new hash algorithms: blake, fugue, groestl, keccak, shavite3, skein. IHashAlgorithm:Hash() now takes a config parameter so it can read from coin's specific configured options. Fixed Crypto/Utils.cs methods, they'll no longer create Sha256Manager instance every time they get called. --- src/CoiniumServ/Coin/Coinbase/Utils.cs | 7 ++- src/CoiniumServ/Coin/Config/CoinConfig.cs | 2 + src/CoiniumServ/Coin/Config/ICoinConfig.cs | 2 + src/CoiniumServ/CoiniumServ.csproj | 5 ++ .../Crypto/Algorithms/Algorithms.cs | 6 +++ src/CoiniumServ/Crypto/Algorithms/Blake.cs | 3 +- src/CoiniumServ/Crypto/Algorithms/Fugue.cs | 47 +++++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/Groestl.cs | 47 +++++++++++++++++++ .../Crypto/Algorithms/HashAlgorithmFactory.cs | 10 ++-- .../Crypto/Algorithms/IHashAlgorithm.cs | 2 +- src/CoiniumServ/Crypto/Algorithms/Keccak.cs | 47 +++++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/Scrypt.cs | 5 +- src/CoiniumServ/Crypto/Algorithms/Sha256.cs | 3 +- src/CoiniumServ/Crypto/Algorithms/Shavite3.cs | 46 ++++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/Skein.cs | 46 ++++++++++++++++++ src/CoiniumServ/Crypto/Utils.cs | 28 ++++++----- src/CoiniumServ/Mining/Shares/Share.cs | 3 +- .../Repository/Registries/ClassRegistry.cs | 8 ++++ 18 files changed, 287 insertions(+), 30 deletions(-) create mode 100644 src/CoiniumServ/Crypto/Algorithms/Fugue.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/Groestl.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/Keccak.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/Shavite3.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/Skein.cs diff --git a/src/CoiniumServ/Coin/Coinbase/Utils.cs b/src/CoiniumServ/Coin/Coinbase/Utils.cs index 608f1b1f5..10e9d4049 100644 --- a/src/CoiniumServ/Coin/Coinbase/Utils.cs +++ b/src/CoiniumServ/Coin/Coinbase/Utils.cs @@ -78,10 +78,13 @@ public static byte[] CoinAddressToScript(string address) /// Hashes the coinbase. /// /// + /// /// - public static Hash HashCoinbase(byte[] coinbase) + public static Hash HashCoinbase(byte[] coinbase, bool doubleDigest = true) { - return coinbase.DoubleDigest(); + return doubleDigest ? coinbase.DoubleDigest() : coinbase.Digest(); + + // TODO: fix this according - https://github.com/zone117x/node-stratum-pool/blob/eb4b62e9c4de8a8cde83c2b3756ca1a45f02b957/lib/jobManager.js#L69 } /// diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index 32d8f1b82..675e753cd 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -28,6 +28,7 @@ public class CoinConfig : ICoinConfig public string Name { get; private set; } public string Symbol { get; private set; } public string Algorithm { get; private set; } + public dynamic Options { get; private set; } public CoinConfig(dynamic config) { @@ -40,6 +41,7 @@ public CoinConfig(dynamic config) Name = config.name; Symbol = config.symbol; Algorithm = config.algorithm; + Options = config; Valid = true; } diff --git a/src/CoiniumServ/Coin/Config/ICoinConfig.cs b/src/CoiniumServ/Coin/Config/ICoinConfig.cs index 20bd25704..d2389f9fb 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfig.cs @@ -32,5 +32,7 @@ public interface ICoinConfig:IConfig string Symbol { get; } string Algorithm { get; } + + dynamic Options { get; } } } diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index ccda4194d..e72bc8a5c 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -111,7 +111,12 @@ + + + + + diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs index c92cf0cf4..f9cc423d8 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs @@ -28,8 +28,14 @@ namespace CoiniumServ.Crypto.Algorithms { public static class Algorithms { + public const string Blake = "blake"; + public const string Fugue = "fugue"; + public const string Groestl = "groestl"; + public const string Keccak = "keccak"; public const string Scrypt = "scrypt"; public const string Sha256 = "sha256"; + public const string Shavite3 = "shavite3"; + public const string Skein = "skein"; /// /// Global diff1 diff --git a/src/CoiniumServ/Crypto/Algorithms/Blake.cs b/src/CoiniumServ/Crypto/Algorithms/Blake.cs index def05e825..06859c56f 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Blake.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Blake.cs @@ -35,10 +35,11 @@ public class Blake : IHashAlgorithm public Blake() { _hasher = HashFactory.Crypto.SHA3.CreateBlake256(); + Multiplier = (UInt32) Math.Pow(2, 8); } - public byte[] Hash(byte[] input) + public byte[] Hash(byte[] input, dynamic config) { return _hasher.ComputeBytes(input).GetBytes(); } diff --git a/src/CoiniumServ/Crypto/Algorithms/Fugue.cs b/src/CoiniumServ/Crypto/Algorithms/Fugue.cs new file mode 100644 index 000000000..e1850e922 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Fugue.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Fugue : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Fugue() + { + _hasher = HashFactory.Crypto.SHA3.CreateFugue256(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/Groestl.cs b/src/CoiniumServ/Crypto/Algorithms/Groestl.cs new file mode 100644 index 000000000..d1e5f8433 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Groestl.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Groestl : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Groestl() + { + _hasher = HashFactory.Crypto.SHA3.CreateGroestl512(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs index bdbc3aa04..335db36f7 100644 --- a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs +++ b/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs @@ -44,15 +44,11 @@ public HashAlgorithmFactory(IApplicationContext applicationContext) /// /// Gets the specified algorithm name. /// - /// Name of the algorithm. + /// Name of the algorithm. /// - public IHashAlgorithm Get(string algorithmName) + public IHashAlgorithm Get(string algorithm) { - // Default to scrypt - if (string.IsNullOrWhiteSpace(algorithmName)) - algorithmName = Algorithms.Scrypt; - - return _applicationContext.Container.Resolve(algorithmName); + return _applicationContext.Container.Resolve(algorithm); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs index 70ab921f1..fe2d97d20 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs +++ b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs @@ -29,6 +29,6 @@ public interface IHashAlgorithm { UInt32 Multiplier { get; } - byte[] Hash(byte[] input); + byte[] Hash(byte[] input, dynamic config); } } \ No newline at end of file diff --git a/src/CoiniumServ/Crypto/Algorithms/Keccak.cs b/src/CoiniumServ/Crypto/Algorithms/Keccak.cs new file mode 100644 index 000000000..3f040dbd9 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Keccak.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Keccak : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Keccak() + { + _hasher = HashFactory.Crypto.SHA3.CreateKeccak256(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs index bd2001f2e..37610fccb 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs @@ -63,10 +63,9 @@ public Scrypt() Multiplier = (UInt32) Math.Pow(2, 16); } - public byte[] Hash(byte[] input) + public byte[] Hash(byte[] input, dynamic config) { - var result = SCrypt.ComputeDerivedKey(input, input, _n, _r, _p, null, 32); - return result; + return SCrypt.ComputeDerivedKey(input, input, _n, _r, _p, null, 32); } } } diff --git a/src/CoiniumServ/Crypto/Algorithms/Sha256.cs b/src/CoiniumServ/Crypto/Algorithms/Sha256.cs index bca27b316..27a703bce 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Sha256.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Sha256.cs @@ -34,10 +34,11 @@ public class Sha256:IHashAlgorithm public Sha256() { _algorithm = new SHA256Managed(); + Multiplier = 1; } - public byte[] Hash(byte[] input) + public byte[] Hash(byte[] input, dynamic config) { return DoubleDigest(input); // coins like bitcoin (sha256d coins) uses double-digest. } diff --git a/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs b/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs new file mode 100644 index 000000000..6ed50ce74 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs @@ -0,0 +1,46 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Shavite3 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Shavite3() + { + _hasher = HashFactory.Crypto.SHA3.CreateSHAvite3_512(); + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/Skein.cs b/src/CoiniumServ/Crypto/Algorithms/Skein.cs new file mode 100644 index 000000000..1e99e6b96 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/Skein.cs @@ -0,0 +1,46 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class Skein : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Skein() + { + _hasher = HashFactory.Crypto.SHA3.CreateSkein512(); + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Utils.cs b/src/CoiniumServ/Crypto/Utils.cs index a446ced1e..f4023ac78 100644 --- a/src/CoiniumServ/Crypto/Utils.cs +++ b/src/CoiniumServ/Crypto/Utils.cs @@ -28,24 +28,26 @@ namespace CoiniumServ.Crypto { public static class Utils { - /// - /// See . - /// - public static byte[] DoubleDigest(this byte[] input) + private static readonly SHA256Managed Sha256Managed; + + static Utils() { - // TODO: instead use SHA256.cs. - return DoubleDigest(input, 0, input.Length); + Sha256Managed = new SHA256Managed(); + } + + public static byte[] Digest(this byte[] input) + { + return Sha256Managed.ComputeHash(input, 0, input.Length); } /// /// Calculates the SHA-256 hash of the given byte range, and then hashes the resulting hash again. This is /// standard procedure in BitCoin. The resulting hash is in big endian form. /// - public static byte[] DoubleDigest(this byte[] input, int offset, int length) + public static byte[] DoubleDigest(this byte[] input) { - var algorithm = new SHA256Managed(); - var first = algorithm.ComputeHash(input, offset, length); - return algorithm.ComputeHash(first); + var first = Sha256Managed.ComputeHash(input, 0, input.Length); + return Sha256Managed.ComputeHash(first); } /// @@ -53,12 +55,12 @@ public static byte[] DoubleDigest(this byte[] input, int offset, int length) /// public static byte[] DoubleDigestTwoBuffers(byte[] input1, int offset1, int length1, byte[] input2, int offset2, int length2) { - var algorithm = new SHA256Managed(); var buffer = new byte[length1 + length2]; Array.Copy(input1, offset1, buffer, 0, length1); Array.Copy(input2, offset2, buffer, length1, length2); - var first = algorithm.ComputeHash(buffer, 0, buffer.Length); - return algorithm.ComputeHash(first); + + var first = Sha256Managed.ComputeHash(buffer, 0, buffer.Length); + return Sha256Managed.ComputeHash(first); } } } diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index 901684f0d..cc24e82ad 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -115,8 +115,7 @@ public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, st // create the block headers HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, NTime, Nonce); - // TODO: add sha256 and others support! - HeaderHash = Job.HashAlgorithm.Hash(HeaderBuffer); + HeaderHash = Job.HashAlgorithm.Hash(HeaderBuffer, miner.Pool.Config.Coin.Options); HeaderValue = new BigInteger(HeaderHash); // calculate the share difficulty diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 527c576fc..516a9d0d7 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -45,8 +45,16 @@ public ClassRegistry(IApplicationContext applicationContext) public void RegisterInstances() { + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Blake).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Fugue).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Groestl).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Keccak).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Scrypt).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Sha256).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Shavite3).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Skein).AsSingleton(); + + _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); From 542d17b8171e4ef281a7f3fcd2ad4356f65dbf0f Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 18 Jul 2014 17:11:39 +0300 Subject: [PATCH 088/230] Added x11, x13, x15 and x17 support! --- src/CoiniumServ/CoiniumServ.csproj | 4 + .../Crypto/Algorithms/Algorithms.cs | 6 ++ src/CoiniumServ/Crypto/Algorithms/X11.cs | 67 +++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/X13.cs | 69 ++++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/X15.cs | 71 ++++++++++++++++++ src/CoiniumServ/Crypto/Algorithms/X17.cs | 73 +++++++++++++++++++ .../Repository/Registries/ClassRegistry.cs | 6 +- 7 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 src/CoiniumServ/Crypto/Algorithms/X11.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/X13.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/X15.cs create mode 100644 src/CoiniumServ/Crypto/Algorithms/X17.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index e72bc8a5c..4c5c0329e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -117,6 +117,10 @@ + + + + diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs index f9cc423d8..f202a8f16 100644 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs @@ -36,6 +36,12 @@ public static class Algorithms public const string Sha256 = "sha256"; public const string Shavite3 = "shavite3"; public const string Skein = "skein"; + public const string X11 = "X11"; + public const string X13 = "X13"; + public const string X15 = "X15"; + public const string X17 = "X17"; + + // todo: add hefty1, qubit support /// /// Global diff1 diff --git a/src/CoiniumServ/Crypto/Algorithms/X11.cs b/src/CoiniumServ/Crypto/Algorithms/X11.cs new file mode 100644 index 000000000..59d19baea --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/X11.cs @@ -0,0 +1,67 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class X11 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X11() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/X13.cs b/src/CoiniumServ/Crypto/Algorithms/X13.cs new file mode 100644 index 000000000..e4069abfc --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/X13.cs @@ -0,0 +1,69 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class X13 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X13() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/X15.cs b/src/CoiniumServ/Crypto/Algorithms/X15.cs new file mode 100644 index 000000000..96031c5b6 --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/X15.cs @@ -0,0 +1,71 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class X15 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X15() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + HashFactory.Crypto.SHA3.CreateShabal512(), + HashFactory.Crypto.CreateWhirlpool(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/X17.cs b/src/CoiniumServ/Crypto/Algorithms/X17.cs new file mode 100644 index 000000000..137a75c6f --- /dev/null +++ b/src/CoiniumServ/Crypto/Algorithms/X17.cs @@ -0,0 +1,73 @@ +#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 HashLib; + +namespace CoiniumServ.Crypto.Algorithms +{ + public class X17 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X17() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + HashFactory.Crypto.SHA3.CreateShabal512(), + HashFactory.Crypto.CreateWhirlpool(), + HashFactory.Crypto.CreateSHA512(), + HashFactory.Crypto.CreateHaval_5_256(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 516a9d0d7..ce8436f16 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -45,6 +45,7 @@ public ClassRegistry(IApplicationContext applicationContext) public void RegisterInstances() { + // hash algorithms _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Blake).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Fugue).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Groestl).AsSingleton(); @@ -53,7 +54,10 @@ public void RegisterInstances() _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Sha256).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Shavite3).AsSingleton(); _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Skein).AsSingleton(); - + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X11).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X13).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X15).AsSingleton(); + _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X17).AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); From 8285b27b4b783b7de42b7425ce3ba90252fe8207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 17:47:26 +0300 Subject: [PATCH 089/230] Update README.md --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9f1f7d666..7db25ec44 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,50 @@ Can run on these platforms; ###### Multiplexed Structure * Multiple pools & ports. -* Multi-pool (switched) mining support. -* Multiple coin daemon connections. +* Multiple coin daemon connection support. * Multiple database layers. ###### Functionality -* Stratum server (over sockets) support. [in-development] -* Vanilla server (getwork & getblocktemplate over http server) support. [in-development] +* Stratum server (over TCP sockets). +* Vanilla server (getwork over http server). [experimental] +* Daemon RPC interface. +* Block template / job managment. +* Generation transaction builder. +* Share processor. +* Payment processor. +* Proof of Work (PoW) and Proof of Stake (PoS) [in-development] support. +* Transaction messages support [in-development]. +* Vardiff support. +* Ban manager support that can handles miners flooding with invalid shares. +* + +###### Hashing Algorithms + +###### Working +* ✓ __Scrypt__ + +###### Needs Testing + +* ✓ __SHA256__ +* ✓ __Blake__ +* ✓ __Fugue__ +* ✓ __Groestl__ +* ✓ __Keccak__ +* ✓ __SHAvite3__ +* ✓ __Skein__ +* ✓ __X11__ +* ✓ __X13__ +* ✓ __X15__ +* ✓ __X17__ + +###### Under Development + +* ✓ __Scrypt-Jane__ +* ✓ __Scrypt-N__ +* ✓ __Quark__ +* ✓ __NIST5__ +* ✓ __Qubit__ +* ✓ __Hefty1__ ###### Development Model * Strictly [follows](https://github.com/CoiniumServ/CoiniumServ/tree/develop/src/Tests) the [Test Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) model. We have implemented extensive tests for all important functionality and never merge in code that breaks tests and stuff. Yet again, when a new functionality is introduced we also expect proper tests to be implemented within the PR. In simple words, most probably you won't notice any functionality-breaking changes within the repository. From 4c7a34a78523a15f5fbaef34c97a38b00a82b47e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 17:49:07 +0300 Subject: [PATCH 090/230] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7db25ec44..2c1cedd85 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,13 @@ Can run on these platforms; * Transaction messages support [in-development]. * Vardiff support. * Ban manager support that can handles miners flooding with invalid shares. -* ###### Hashing Algorithms -###### Working +_Working_ * ✓ __Scrypt__ -###### Needs Testing +_Needs Testing_ * ✓ __SHA256__ * ✓ __Blake__ @@ -55,7 +54,7 @@ Can run on these platforms; * ✓ __X15__ * ✓ __X17__ -###### Under Development +_Under Development_ * ✓ __Scrypt-Jane__ * ✓ __Scrypt-N__ From 4e434cf2240c013bc01cd564ba861a158dc28a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 18 Jul 2014 17:50:28 +0300 Subject: [PATCH 091/230] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c1cedd85..8044d0a44 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ CoiniumServ was created to be used for [Coinium.org](http://www.coinium.org) mining pool network at first hand. You can check [some of pools](https://github.com/CoiniumServ/CoiniumServ/wiki/Pools) of the pools running CoiniumServ. * Official pools: [coinium.org](http://www.coinium.org) -* Official site: [coiniumserv.com](http://www.coiniumserv.com) ![CoiniumServ running over mono & ubuntu](http://i.imgur.com/izIB5nq.png) @@ -94,6 +93,7 @@ You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) - **#coinium-serv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) +* Official site: [coiniumserv.com](http://www.coiniumserv.com) * [Twitter](http://twitter.com/coinium) * [Support forums](http://forum.coinium.org/forum/19-support/) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) From c7bee15096bc3619d1a5aafd7c4c3cd2ba44a195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 04:57:03 +0300 Subject: [PATCH 092/230] Added packet log support /logs/packet.log. --- src/CoiniumServ/Daemon/DaemonBase.cs | 7 +- src/CoiniumServ/Mining/Banning/BanManager.cs | 8 +- .../Server/Mining/Stratum/StratumMiner.cs | 11 ++- .../Server/Mining/Vanilla/VanillaMiner.cs | 6 +- src/CoiniumServ/Utils/Logging.cs | 78 +++++++++++++------ src/CoiniumServ/config/config-sample.json | 45 ++++++----- 6 files changed, 99 insertions(+), 56 deletions(-) diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 035a9e8b1..460b9c6d2 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -27,6 +27,7 @@ using System.Text; using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Exceptions; +using CoiniumServ.Utils; using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Serilog; @@ -87,6 +88,8 @@ private DaemonResponse MakeRpcRequest(DaemonRequest walletRequest) public string MakeRawRequest(string method, params object[] parameters) { var response = MakeRawRpcRequest(new DaemonRequest(RequestCounter++, method, parameters)); + Logging.PacketLogger.ForContext().Verbose("rx: {0}", response.PrettifyJson()); + return response; } @@ -116,7 +119,7 @@ private HttpWebRequest MakeHttpRequest(DaemonRequest walletRequest) webRequest.Method = "POST"; webRequest.Timeout = 1000; - Log.ForContext().Verbose("Send: {0}", Encoding.UTF8.GetString(walletRequest.GetBytes()).PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("tx: {0}", Encoding.UTF8.GetString(walletRequest.GetBytes()).PrettifyJson()); byte[] byteArray = walletRequest.GetBytes(); webRequest.ContentLength = byteArray.Length; @@ -147,7 +150,7 @@ private DaemonResponse GetRpcResponse(HttpWebRequest httpWebRequest) { string json = GetJsonResponse(httpWebRequest); - Log.ForContext().Verbose("Recv: {0}", json.PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("rx: {0}", json.PrettifyJson()); try { diff --git a/src/CoiniumServ/Mining/Banning/BanManager.cs b/src/CoiniumServ/Mining/Banning/BanManager.cs index 761d1b10c..383e527ff 100644 --- a/src/CoiniumServ/Mining/Banning/BanManager.cs +++ b/src/CoiniumServ/Mining/Banning/BanManager.cs @@ -130,10 +130,10 @@ public void CheckBans(object state) var remainingBans = _bannedIps.Count; - Log.ForContext().Information( - expiredBans > 0 - ? "Cleared {0} expired bans [remaining bans: {1}]." - : "No expired bans found to be cleared [remaining bans: {1}].", expiredBans, remainingBans); + if(expiredBans > 0) + Log.ForContext().Information("Cleared {0} expired bans [remaining bans: {1}].", expiredBans, remainingBans); + else + Log.ForContext().Information("No expired bans found to be cleared [remaining bans: {0}].", remainingBans); // reset the recache timer. _timer.Change(Config.PurgeInterval * 1000, Timeout.Infinite); diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 282348ced..503be0ac6 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -22,6 +22,7 @@ #endregion using System; +using System.Configuration; using System.Text; using AustinHarris.JsonRpc; using CoiniumServ.Mining.Miners; @@ -30,10 +31,12 @@ using CoiniumServ.Server.Mining.Stratum.Errors; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Stratum.Service; +using CoiniumServ.Utils; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Serilog; +using Serilog.Context; namespace CoiniumServ.Server.Mining.Stratum { @@ -135,7 +138,7 @@ public bool Authenticate(string user, string password) /// public void Parse(ConnectionDataEventArgs e) { - Log.ForContext().Verbose("Recv:\n{0}", e.Data.ToEncodedString().PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("rx: {0}", e.Data.ToEncodedString().PrettifyJson()); var rpcResultHandler = new AsyncCallback( callback => @@ -149,7 +152,7 @@ public void Parse(ConnectionDataEventArgs e) var miner = (StratumMiner)context.Miner; miner.Connection.Send(response); - Log.ForContext().Verbose("Reply:\n{0}", result.PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("tx: {0}", result.PrettifyJson()); }); var line = e.Data.ToEncodedString(); @@ -180,7 +183,7 @@ public void SendDifficulty() Connection.Send(data); Log.ForContext().Debug("Difficulty updated to {0} for miner: {1:l}", Difficulty, Username); - Log.ForContext().Verbose("Send:\n{0}", data.ToEncodedString().PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); } /// @@ -200,7 +203,7 @@ public void SendJob(IJob job) var data = Encoding.UTF8.GetBytes(json); Connection.Send(data); - Log.ForContext().Verbose("Send:\n{0}", data.ToEncodedString().PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); } } } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index b881ba77b..1b49cbd4b 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -29,8 +29,8 @@ using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; using CoiniumServ.Server.Mining.Vanilla.Service; +using CoiniumServ.Utils; using CoiniumServ.Utils.Extensions; -using Serilog; namespace CoiniumServ.Server.Mining.Vanilla { @@ -99,13 +99,13 @@ public void Parse(HttpListenerContext httpContext) context.Request.Response.ContentLength64 = response.Length; context.Request.Response.OutputStream.Write(response, 0, response.Length); - Log.ForContext().Verbose("Reply:\n{0}", result.PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("tx: {0}", result.PrettifyJson()); }); using (var reader = new StreamReader(httpRequest.InputStream, Encoding.UTF8)) { var line = reader.ReadToEnd(); - Log.ForContext().Verbose("Recv:\n{0}", line.PrettifyJson()); + Logging.PacketLogger.ForContext().Verbose("rx: {0}", line.PrettifyJson()); var rpcRequest = new HttpServiceRequest(line, httpContext); var rpcContext = new HttpServiceContext(this, rpcRequest); diff --git a/src/CoiniumServ/Utils/Logging.cs b/src/CoiniumServ/Utils/Logging.cs index c5dc6f252..397aa58f2 100644 --- a/src/CoiniumServ/Utils/Logging.cs +++ b/src/CoiniumServ/Utils/Logging.cs @@ -38,58 +38,71 @@ public static class Logging { // TODO: change to singleton. - public const string ConsoleLogFormat = "{Timestamp:HH:mm:ss} [{Level}] [{Component:l}] [{Pool:l}] {Message}{NewLine}{Exception}"; - public const string FileLogFormat = "{Timestamp} [{Level}] [{Component:l}] [{Pool:l}] {Message}{NewLine}{Exception}"; + public static ILogger PacketLogger { get; private set; } - public static string RootFolder { get; private set; } + private const string ConsoleLogFormat = "{Timestamp:HH:mm:ss} [{Level}] [{Source:l}] [{Pool:l}] {Message}{NewLine}{Exception}"; + private const string FileLogFormat = "{Timestamp} [{Level}] [{Source:l}] [{Pool:l}] {Message}{NewLine}{Exception}"; - public static void Init(dynamic globalConfig) + private static string _rootFolder; + + public static void Init(dynamic config) { + //Serilog.Debugging.SelfLog.Out = Console.Out; // comment out this line to see serilog's debug messages. + try { // read the root folder for logs. - RootFolder = !string.IsNullOrEmpty(globalConfig.logs.root) ? globalConfig.logs.root : "logs"; + _rootFolder = !string.IsNullOrEmpty(config.logs.root) ? config.logs.root : "logs"; - if (!Directory.Exists(RootFolder)) // make sure log root exists. - Directory.CreateDirectory(RootFolder); + if (!Directory.Exists(_rootFolder)) // make sure log root exists. + Directory.CreateDirectory(_rootFolder); // create the global logger. - var config = new LoggerConfiguration(); - + var globalConfig = new LoggerConfiguration(); + var packetLoggerConfig = new LoggerConfiguration(); + // add enrichers - config.Enrich.With(new ComponentEnricher()); - config.Enrich.With(new PoolEnricher()); + globalConfig.Enrich.With(new SourceEnricher()); + globalConfig.Enrich.With(new PoolEnricher()); + + packetLoggerConfig.Enrich.With(new SourceEnricher()); + packetLoggerConfig.Enrich.With(new PoolEnricher()); // read log targets. - var targets = globalConfig.logs.targets; + var targets = config.logs.targets; foreach (dynamic target in targets) { var enabled = target.enabled; + if (!enabled) continue; switch ((string) target.type) { case "console": - AddConsoleLog(config, target); + AddConsoleLog(globalConfig, target); break; case "file": - AddLogFile(config, target); + AddLogFile(globalConfig, target); + break; + case "packet": + AddPacketLog(packetLoggerConfig, target); break; } } // lower the default minimum level to verbose as sinks can only rise them but not lower. - config.MinimumLevel.Verbose(); + globalConfig.MinimumLevel.Verbose(); + packetLoggerConfig.MinimumLevel.Verbose(); - // bind the config to global log. - Log.Logger = config.CreateLogger(); + Log.Logger = globalConfig.CreateLogger(); // bind the config to global log. + PacketLogger = packetLoggerConfig.CreateLogger(); } catch (RuntimeBinderException e) { - System.Console.ForegroundColor = ConsoleColor.Red; - System.Console.WriteLine("Couldn't read log targets in config.json! [{0}]", e); - System.Console.ResetColor(); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Couldn't read log targets in config.json! [{0}]", e); + Console.ResetColor(); Environment.Exit(-1); } } @@ -104,9 +117,26 @@ private static void AddConsoleLog(LoggerConfiguration config, dynamic target) private static void AddLogFile(LoggerConfiguration config, dynamic target) { LogEventLevel level = GetLogLevel(target.level); + bool rolling = target.rolling; var fileName = target.filename; - string filePath = String.Format("{0}/{1}", RootFolder, fileName); + + string filePath = String.Format("{0}/{1}", _rootFolder, fileName); + + if (rolling) + config.WriteTo.RollingFile(filePath, level, FileLogFormat); + else + config.WriteTo.File(filePath, level, FileLogFormat); + } + + private static void AddPacketLog(LoggerConfiguration config, dynamic target) + { + LogEventLevel level = GetLogLevel(target.level); + + bool rolling = target.rolling; + var fileName = target.filename; + + string filePath = String.Format("{0}/{1}", _rootFolder, fileName); if (rolling) config.WriteTo.RollingFile(filePath, level, FileLogFormat); @@ -136,13 +166,13 @@ private static LogEventLevel GetLogLevel(dynamic level) } } - public class ComponentEnricher : ILogEventEnricher + public class SourceEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { logEvent.AddPropertyIfAbsent(logEvent.Properties.Keys.Contains("SourceContext") - ? propertyFactory.CreateProperty("Component", logEvent.Properties["SourceContext"].ToString().Replace("\"","").Split('.').Last()) - : propertyFactory.CreateProperty("Component", "global")); + ? propertyFactory.CreateProperty("Source", logEvent.Properties["SourceContext"].ToString().Replace("\"","").Split('.').Last()) + : propertyFactory.CreateProperty("Source", "global")); } } diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-sample.json index a01eabb4e..eb8bbf06c 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-sample.json @@ -1,4 +1,22 @@ { + # website configuration + "web": { + "enabled": true, + "bind": "127.0.0.1", + "port": 91 + }, + + # storage configuration. + "storage": { + "redis": { + "enabled": true, + "host": "10.0.0.13", + "port": 6379, + "password": "", + "databaseId": 0 + } + }, + # log configuration "logs": { "root": "logs", @@ -21,25 +39,14 @@ "filename": "debug.log", "rolling": true, "level": "verbose" - } + }, + { + "enabled": true, + "type": "packet", + "filename": "packet.log", + "rolling": true, + "level": "verbose" + } ] - }, - - # website configuration - "web": { - "enabled": true, - "bind": "127.0.0.1", - "port": 80 - }, - - # storage configuration. - "storage": { - "redis": { - "enabled": true, - "host": "127.0.0.1", - "port": 6379, - "password": "", - "databaseId": 0 - } } } \ No newline at end of file From 2a5c8ef88fc89831a90c8344c6b047bef9d86dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 05:01:46 +0300 Subject: [PATCH 093/230] Update README.md --- README.md | 74 +++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 8044d0a44..78d599d9a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,42 @@ CoiniumServ was created to be used for [Coinium.org](http://www.coinium.org) min ![CoiniumServ running over mono & ubuntu](http://i.imgur.com/izIB5nq.png) +### Support + +Start by reading our [FAQ](https://github.com/CoiniumServ/CoiniumServ/wiki/FAQ) and [wiki](https://github.com/CoiniumServ/CoiniumServ/wiki/). If you need further help, join us over our user-support channel [#coinium-serv@freenode](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde). + +You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) page to report bugs. + +* IRC (**irc.freenode.net**): + - **#coinium-serv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) + - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) + - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) +* Official site: [coiniumserv.com](http://www.coiniumserv.com) +* [Twitter](http://twitter.com/coinium) +* [Support forums](http://forum.coinium.org/forum/19-support/) +* [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) +* [Bitcoin wiki](https://en.bitcoin.it/wiki/CoiniumServ) + +### Donation + +You can contribute the development of the project by donating; + +* BTC: `18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D` +* LTC: `LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa` +* DOGE: `D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc` + +###### Bounties + +BountySource integration available over [here](https://www.bountysource.com/trackers/401667-coiniumserv). You can set bounties and solve them. + +[![Bountysource](https://api.bountysource.com/badge/team?team_id=760&style=bounties_received)](https://www.bountysource.com/teams/coinium/issues?utm_source=Coinium&utm_medium=shield&utm_campaign=TEAM_BADGE_1) + +###### Tips + +You can send tips and furher support the project or get tips for contributing by commiting. + +[![tip for next commit](http://tip4commit.com/projects/760.svg)](http://tip4commit.com/projects/760) + ### Features ###### Platform Agnostic @@ -79,26 +115,10 @@ wget -O - https://raw.githubusercontent.com/CoiniumServ/CoiniumServ/develop/cont ### Documentation -* [Documentation & Wiki](https://github.com/CoiniumServ/CoiniumServ/wiki/) +* [Wiki](https://github.com/CoiniumServ/CoiniumServ/wiki/) * [FAQ](https://github.com/CoiniumServ/CoiniumServ/wiki/FAQ) * [Master Plan](https://github.com/CoiniumServ/CoiniumServ/wiki/Master-Plan) ( & motivation) -### Support - -Start by reading our [FAQ](https://github.com/CoiniumServ/CoiniumServ/wiki/FAQ) and [wiki](https://github.com/CoiniumServ/CoiniumServ/wiki/). If you need further help, join us over our user-support channel [#coinium-serv@freenode](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde). - -You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) page to report bugs. - -* IRC (**irc.freenode.net**): - - **#coinium-serv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) - - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) - - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) -* Official site: [coiniumserv.com](http://www.coiniumserv.com) -* [Twitter](http://twitter.com/coinium) -* [Support forums](http://forum.coinium.org/forum/19-support/) -* [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) -* [Bitcoin wiki](https://en.bitcoin.it/wiki/CoiniumServ) - ### Contributing Start reading by these; @@ -106,26 +126,6 @@ Start reading by these; * [Developer's Guide](https://github.com/CoiniumServ/CoiniumServ/wiki/Developer's-Guide) * [Technical Documentation](https://github.com/CoiniumServ/CoiniumServ/wiki/Technical-Documentation) -### Donation - -You can contribute the development of the project by donating; - -* BTC: `18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D` -* LTC: `LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa` -* DOGE: `D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc` - -###### Bounties - -BountySource integration available over [here](https://www.bountysource.com/trackers/401667-coiniumserv). You can set bounties and solve them. - -[![Bountysource](https://api.bountysource.com/badge/team?team_id=760&style=bounties_received)](https://www.bountysource.com/teams/coinium/issues?utm_source=Coinium&utm_medium=shield&utm_campaign=TEAM_BADGE_1) - -###### Tips - -You can send tips and furher support the project or get tips for contributing by commiting. - -[![tip for next commit](http://tip4commit.com/projects/760.svg)](http://tip4commit.com/projects/760) - ### License Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org - From 526e60c2968deffb8603f51c7c9b1ba5a30710bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 05:03:01 +0300 Subject: [PATCH 094/230] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78d599d9a..e44adca26 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ Start by reading our [FAQ](https://github.com/CoiniumServ/CoiniumServ/wiki/FAQ) You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) page to report bugs. +* Official site: [coiniumserv.com](http://www.coiniumserv.com) +* [Support forums](http://forum.coinium.org/forum/19-support/) * IRC (**irc.freenode.net**): - **#coinium-serv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) -* Official site: [coiniumserv.com](http://www.coiniumserv.com) * [Twitter](http://twitter.com/coinium) -* [Support forums](http://forum.coinium.org/forum/19-support/) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) * [Bitcoin wiki](https://en.bitcoin.it/wiki/CoiniumServ) From 799d00b4a4542486bf1c9cd891968078650564b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 05:08:54 +0300 Subject: [PATCH 095/230] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e44adca26..a1459f958 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ You can contribute the development of the project by donating; * BTC: `18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D` * LTC: `LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa` -* DOGE: `D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc` +* DOGE: `DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr` ###### Bounties From 03863011b1b07729a65c26cb13b3cece92979925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 05:11:11 +0300 Subject: [PATCH 096/230] updated dogecoin donation address --- src/CoiniumServ/Utils/ConsoleWindow.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CoiniumServ/Utils/ConsoleWindow.cs b/src/CoiniumServ/Utils/ConsoleWindow.cs index 09119233f..e6d61e75d 100644 --- a/src/CoiniumServ/Utils/ConsoleWindow.cs +++ b/src/CoiniumServ/Utils/ConsoleWindow.cs @@ -59,9 +59,9 @@ public static void PrintLicense() Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("You can contribute the development of the project by donating;"); Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D."); - Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa."); - Console.WriteLine("DOGE: D7mzHQtkWD9B1Xwnmjfg9x2DofbaZBg6Lc."); + Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D"); + Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa"); + Console.WriteLine("DOGE: DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr"); Console.WriteLine(); Console.ResetColor(); } From 40b20993bd7725d0ddc93ef80091392689d6519a Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 19 Jul 2014 14:09:54 +0300 Subject: [PATCH 097/230] Log messages now include the component field (ie, global or pool-name). Updated to nancy 0.23.2. --- src/CoiniumServ/App.config | 1 + src/CoiniumServ/CoiniumServ.csproj | 20 ++++++--- src/CoiniumServ/Mining/Banning/BanManager.cs | 13 ++++-- .../Mining/Banning/BanManagerFactory.cs | 6 ++- .../Mining/Banning/IBanManagerFactory.cs | 3 +- .../Mining/Jobs/Manager/IJobManagerFactory.cs | 8 +++- .../Mining/Jobs/Manager/JobManager.cs | 20 +++++---- .../Mining/Jobs/Manager/JobManagerFactory.cs | 6 ++- .../Mining/Miners/IMinerManagerFactory.cs | 4 +- src/CoiniumServ/Mining/Miners/MinerManager.cs | 18 ++++---- .../Mining/Miners/MinerManagerFactory.cs | 6 ++- src/CoiniumServ/Mining/Pools/Pool.cs | 45 ++++++++++--------- src/CoiniumServ/Mining/Pools/PoolManager.cs | 5 ++- .../Mining/Shares/IShareManagerFactory.cs | 3 +- src/CoiniumServ/Mining/Shares/ShareManager.cs | 25 ++++++----- .../Mining/Shares/ShareManagerFactory.cs | 6 ++- .../Mining/Vardiff/IVardiffManagerFactory.cs | 3 +- .../Mining/Vardiff/VardiffManager.cs | 11 ++++- .../Mining/Vardiff/VardiffManagerFactory.cs | 6 ++- .../Net/Server/Http/Web/HttpServer.cs | 19 ++++---- .../Payments/IPaymentProcessorFactory.cs | 3 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 20 +++++---- .../Payments/PaymentProcessorFactory.cs | 6 ++- src/CoiniumServ/Persistance/Redis/Redis.cs | 10 ++++- src/CoiniumServ/Program.cs | 12 +++-- src/CoiniumServ/Server/IServerFactory.cs | 4 +- .../Server/Mining/Stratum/StratumMiner.cs | 1 - .../Server/Mining/Stratum/StratumServer.cs | 14 ++++-- .../Server/Mining/Vanilla/VanillaServer.cs | 7 ++- src/CoiniumServ/Server/ServerFactory.cs | 6 ++- src/CoiniumServ/Utils/Logging.cs | 17 ++++--- src/CoiniumServ/config/config-sample.json | 6 +-- src/CoiniumServ/packages.config | 6 +-- src/Tests/Mining/Pools/PoolTests.cs | 41 +++++++++-------- 34 files changed, 237 insertions(+), 144 deletions(-) diff --git a/src/CoiniumServ/App.config b/src/CoiniumServ/App.config index d396d43fa..a1a9ea285 100644 --- a/src/CoiniumServ/App.config +++ b/src/CoiniumServ/App.config @@ -9,6 +9,7 @@ + diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 4c5c0329e..74ffbee1a 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -65,23 +65,24 @@ ..\..\build\packages\Metrics.NET.0.1.9\lib\net45\Metrics.dll - + False - ..\..\build\packages\Nancy.0.23.0\lib\net40\Nancy.dll + ..\..\build\packages\Nancy.0.23.2\lib\net40\Nancy.dll False ..\..\build\packages\Nancy.CustomErrors.1.0.4.0\lib\net40\Nancy.CustomErrors.dll - + False - ..\..\build\packages\Nancy.Hosting.Self.0.23.0\lib\net40\Nancy.Hosting.Self.dll + ..\..\build\packages\Nancy.Hosting.Self.0.23.2\lib\net40\Nancy.Hosting.Self.dll ..\..\build\packages\NancyFx.Metrics.0.1.9\lib\net45\Nancy.Metrics.dll - - ..\..\build\packages\Nancy.Viewengines.Razor.0.23.0\lib\net40\Nancy.ViewEngines.Razor.dll + + False + ..\..\build\packages\Nancy.Viewengines.Razor.0.23.2\lib\net40\Nancy.ViewEngines.Razor.dll False @@ -1030,6 +1031,13 @@ if $(ConfigurationName) == Debug ( xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" +) + + + +if $(ConfigurationName) == Debug ( +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" ) - - + + if $(ConfigurationName) == Debug ( -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.0\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" -) - - - -if $(ConfigurationName) == Debug ( xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" ) From ace80c8ba8387fe8c20f1c21f86a5b8b94fc2c6c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 19 Jul 2014 15:04:25 +0300 Subject: [PATCH 100/230] Moved Crypto/ namespace to Cryptology/. Removed hashalgorithmfactory and introduced ObjectFactory. Removed unused MerkleRoot. --- src/CoiniumServ/Coin/Address/Base58.cs | 2 +- src/CoiniumServ/Coin/Coinbase/Utils.cs | 2 +- src/CoiniumServ/CoiniumServ.csproj | 45 +++-- .../Cryptology/Algorithms/Algorithms.cs | 56 ++++++ .../Cryptology/Algorithms/Blake.cs | 47 +++++ .../Cryptology/Algorithms/Fugue.cs | 47 +++++ .../Cryptology/Algorithms/Groestl.cs | 47 +++++ .../Algorithms/IHashAlgorithm.cs} | 16 +- .../Cryptology/Algorithms/Keccak.cs | 47 +++++ .../Cryptology/Algorithms/Scrypt.cs | 69 +++++++ .../Cryptology/Algorithms/Sha256.cs | 52 +++++ .../Cryptology/Algorithms/Shavite3.cs | 46 +++++ .../Cryptology/Algorithms/Skein.cs | 46 +++++ src/CoiniumServ/Cryptology/Algorithms/X11.cs | 67 +++++++ src/CoiniumServ/Cryptology/Algorithms/X13.cs | 69 +++++++ src/CoiniumServ/Cryptology/Algorithms/X15.cs | 71 +++++++ src/CoiniumServ/Cryptology/Algorithms/X17.cs | 73 +++++++ .../{Crypto => Cryptology}/Hash.cs | 2 +- .../Cryptology/Merkle/IMerkleTree.cs | 47 +++++ .../Cryptology/Merkle/MerkleTree.cs | 143 +++++++++++++ .../{Crypto => Cryptology}/Utils.cs | 2 +- src/CoiniumServ/Factories/ConfigFactory.cs | 32 +++ src/CoiniumServ/Factories/IConfigFactory.cs | 32 +++ src/CoiniumServ/Factories/IObjectFactory.cs | 40 ++++ .../ObjectFactory.cs} | 24 ++- .../Mining/Jobs/Manager/IJobManagerFactory.cs | 2 +- .../Mining/Jobs/Manager/JobManager.cs | 2 +- .../Mining/Jobs/Manager/JobManagerFactory.cs | 2 +- src/CoiniumServ/Mining/Pools/Pool.cs | 21 +- .../Statistics/IStatisticsObjectFactory.cs | 2 +- .../Mining/Pools/Statistics/PerPool.cs | 2 +- .../Statistics/StatisticsObjectFactory.cs | 2 +- src/CoiniumServ/Mining/Shares/IShare.cs | 2 +- src/CoiniumServ/Mining/Shares/Share.cs | 4 +- src/CoiniumServ/Program.cs | 1 - .../Registries/AlgorithmRegistry.cs | 55 +++++ .../Repository/Registries/ClassRegistry.cs | 15 -- .../Repository/Registries/FactoryRegistry.cs | 5 +- .../Repository/Registries/Registry.cs | 1 + .../Mining/Stratum/Notifications/IJob.cs | 4 +- .../Mining/Stratum/Notifications/Job.cs | 4 +- .../Transactions/GenerationTransaction.cs | 2 +- src/CoiniumServ/Transactions/OutPoint.cs | 2 +- src/Tests/Coin/Coinbase/SerializersTests.cs | 2 +- src/Tests/Crypto/Merkle/MerkleRootTests.cs | 189 ------------------ .../Merkle/MerkleTreeTests.cs | 4 +- src/Tests/Mining/Pools/PoolTests.cs | 14 +- src/Tests/Mining/Shares/ShareTests.cs | 2 +- .../Server/Stratum/Notifications/JobTests.cs | 2 +- src/Tests/Tests.csproj | 3 +- 50 files changed, 1180 insertions(+), 288 deletions(-) create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Algorithms.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Blake.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Fugue.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Groestl.cs rename src/CoiniumServ/{Crypto/Algorithms/IHashAlgorithmFactory.cs => Cryptology/Algorithms/IHashAlgorithm.cs} (75%) create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Keccak.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Scrypt.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Sha256.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Shavite3.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/Skein.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/X11.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/X13.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/X15.cs create mode 100644 src/CoiniumServ/Cryptology/Algorithms/X17.cs rename src/CoiniumServ/{Crypto => Cryptology}/Hash.cs (99%) create mode 100644 src/CoiniumServ/Cryptology/Merkle/IMerkleTree.cs create mode 100644 src/CoiniumServ/Cryptology/Merkle/MerkleTree.cs rename src/CoiniumServ/{Crypto => Cryptology}/Utils.cs (98%) create mode 100644 src/CoiniumServ/Factories/ConfigFactory.cs create mode 100644 src/CoiniumServ/Factories/IConfigFactory.cs create mode 100644 src/CoiniumServ/Factories/IObjectFactory.cs rename src/CoiniumServ/{Crypto/Algorithms/HashAlgorithmFactory.cs => Factories/ObjectFactory.cs} (71%) create mode 100644 src/CoiniumServ/Repository/Registries/AlgorithmRegistry.cs delete mode 100644 src/Tests/Crypto/Merkle/MerkleRootTests.cs rename src/Tests/{Crypto => Cryptology}/Merkle/MerkleTreeTests.cs (99%) diff --git a/src/CoiniumServ/Coin/Address/Base58.cs b/src/CoiniumServ/Coin/Address/Base58.cs index e4f6a9cc0..b7abf5cbe 100644 --- a/src/CoiniumServ/Coin/Address/Base58.cs +++ b/src/CoiniumServ/Coin/Address/Base58.cs @@ -25,7 +25,7 @@ using System.Linq; using System.Text; using CoiniumServ.Coin.Address.Exceptions; -using CoiniumServ.Crypto; +using CoiniumServ.Cryptology; using Org.BouncyCastle.Math; namespace CoiniumServ.Coin.Address diff --git a/src/CoiniumServ/Coin/Coinbase/Utils.cs b/src/CoiniumServ/Coin/Coinbase/Utils.cs index 10e9d4049..1511d4b8e 100644 --- a/src/CoiniumServ/Coin/Coinbase/Utils.cs +++ b/src/CoiniumServ/Coin/Coinbase/Utils.cs @@ -25,7 +25,7 @@ using System.IO; using System.Linq; using CoiniumServ.Coin.Address; -using CoiniumServ.Crypto; +using CoiniumServ.Cryptology; using CoiniumServ.Utils.Extensions; using CoiniumServ.Utils.Numerics; using Gibbed.IO; diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 24bd61333..ee72817dd 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -111,17 +111,21 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -201,6 +205,7 @@ + @@ -215,9 +220,7 @@ - - - + @@ -264,11 +267,9 @@ - - - - - + + + @@ -291,19 +292,19 @@ - + - + - + diff --git a/src/CoiniumServ/Cryptology/Algorithms/Algorithms.cs b/src/CoiniumServ/Cryptology/Algorithms/Algorithms.cs new file mode 100644 index 000000000..405935952 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Algorithms.cs @@ -0,0 +1,56 @@ +#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.Globalization; +using CoiniumServ.Utils.Numerics; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public static class Algorithms + { + public const string Blake = "blake"; + public const string Fugue = "fugue"; + public const string Groestl = "groestl"; + public const string Keccak = "keccak"; + public const string Scrypt = "scrypt"; + public const string Sha256 = "sha256"; + public const string Shavite3 = "shavite3"; + public const string Skein = "skein"; + public const string X11 = "X11"; + public const string X13 = "X13"; + public const string X15 = "X15"; + public const string X17 = "X17"; + + // todo: add hefty1, qubit support + + /// + /// Global diff1 + /// + public static BigInteger Diff1 { get; private set; } + + static Algorithms() + { + Diff1 = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Blake.cs b/src/CoiniumServ/Cryptology/Algorithms/Blake.cs new file mode 100644 index 000000000..a9e038dd2 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Blake.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Blake : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Blake() + { + _hasher = HashFactory.Crypto.SHA3.CreateBlake256(); + + Multiplier = (UInt32) Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Fugue.cs b/src/CoiniumServ/Cryptology/Algorithms/Fugue.cs new file mode 100644 index 000000000..602e45ad5 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Fugue.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Fugue : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Fugue() + { + _hasher = HashFactory.Crypto.SHA3.CreateFugue256(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Groestl.cs b/src/CoiniumServ/Cryptology/Algorithms/Groestl.cs new file mode 100644 index 000000000..88df47b15 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Groestl.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Groestl : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Groestl() + { + _hasher = HashFactory.Crypto.SHA3.CreateGroestl512(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs b/src/CoiniumServ/Cryptology/Algorithms/IHashAlgorithm.cs similarity index 75% rename from src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs rename to src/CoiniumServ/Cryptology/Algorithms/IHashAlgorithm.cs index e33b696de..af7d6c6a5 100644 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithmFactory.cs +++ b/src/CoiniumServ/Cryptology/Algorithms/IHashAlgorithm.cs @@ -20,15 +20,15 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Crypto.Algorithms + +using System; + +namespace CoiniumServ.Cryptology.Algorithms { - public interface IHashAlgorithmFactory + public interface IHashAlgorithm { - /// - /// Gets the specified algorithm name. - /// - /// Name of the algorithm. - /// - IHashAlgorithm Get(string algorithmName); + UInt32 Multiplier { get; } + + byte[] Hash(byte[] input, dynamic config); } } \ No newline at end of file diff --git a/src/CoiniumServ/Cryptology/Algorithms/Keccak.cs b/src/CoiniumServ/Cryptology/Algorithms/Keccak.cs new file mode 100644 index 000000000..66af8f33b --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Keccak.cs @@ -0,0 +1,47 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Keccak : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Keccak() + { + _hasher = HashFactory.Crypto.SHA3.CreateKeccak256(); + + Multiplier = (UInt32)Math.Pow(2, 8); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Scrypt.cs b/src/CoiniumServ/Cryptology/Algorithms/Scrypt.cs new file mode 100644 index 000000000..17596e9be --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Scrypt.cs @@ -0,0 +1,69 @@ +#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 CryptSharp.Utility; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Scrypt : IHashAlgorithm + { + /// + /// Gets the multiplier. + /// + /// + /// The multiplier. + /// + public UInt32 Multiplier { get; private set; } + + /// + /// N parameter - CPU/memory cost parameter. + /// + private readonly int _n; + + /// + /// R parameter - block size. + /// + private readonly int _r; + + /// + /// P - parallelization parameter - a large value of p can increase computational + /// cost of scrypt without increasing the memory usage. + /// + private readonly int _p; + + public Scrypt() + { + _n = 1024; + _r = 1; + _p = 1; + + Multiplier = (UInt32) Math.Pow(2, 16); + } + + public byte[] Hash(byte[] input, dynamic config) + { + return SCrypt.ComputeDerivedKey(input, input, _n, _r, _p, null, 32); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Sha256.cs b/src/CoiniumServ/Cryptology/Algorithms/Sha256.cs new file mode 100644 index 000000000..99ebcc70a --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Sha256.cs @@ -0,0 +1,52 @@ +#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.Security.Cryptography; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Sha256:IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly SHA256Managed _algorithm; + + public Sha256() + { + _algorithm = new SHA256Managed(); + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + return DoubleDigest(input); // coins like bitcoin (sha256d coins) uses double-digest. + } + + public byte[] DoubleDigest(byte[] input) + { + var first = _algorithm.ComputeHash(input); + return _algorithm.ComputeHash(first); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Shavite3.cs b/src/CoiniumServ/Cryptology/Algorithms/Shavite3.cs new file mode 100644 index 000000000..c08f31c2b --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Shavite3.cs @@ -0,0 +1,46 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Shavite3 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Shavite3() + { + _hasher = HashFactory.Crypto.SHA3.CreateSHAvite3_512(); + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/Skein.cs b/src/CoiniumServ/Cryptology/Algorithms/Skein.cs new file mode 100644 index 000000000..a9cccd8e8 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/Skein.cs @@ -0,0 +1,46 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class Skein : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly IHash _hasher; + + public Skein() + { + _hasher = HashFactory.Crypto.SHA3.CreateSkein512(); + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + return _hasher.ComputeBytes(input).GetBytes(); + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/X11.cs b/src/CoiniumServ/Cryptology/Algorithms/X11.cs new file mode 100644 index 000000000..57cb0f9f8 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/X11.cs @@ -0,0 +1,67 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class X11 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X11() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/X13.cs b/src/CoiniumServ/Cryptology/Algorithms/X13.cs new file mode 100644 index 000000000..afea0e049 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/X13.cs @@ -0,0 +1,69 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class X13 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X13() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/X15.cs b/src/CoiniumServ/Cryptology/Algorithms/X15.cs new file mode 100644 index 000000000..a812817df --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/X15.cs @@ -0,0 +1,71 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class X15 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X15() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + HashFactory.Crypto.SHA3.CreateShabal512(), + HashFactory.Crypto.CreateWhirlpool(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Cryptology/Algorithms/X17.cs b/src/CoiniumServ/Cryptology/Algorithms/X17.cs new file mode 100644 index 000000000..102062f27 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Algorithms/X17.cs @@ -0,0 +1,73 @@ +#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 HashLib; + +namespace CoiniumServ.Cryptology.Algorithms +{ + public class X17 : IHashAlgorithm + { + public uint Multiplier { get; private set; } + + private readonly List _hashers; + + public X17() + { + _hashers = new List + { + HashFactory.Crypto.SHA3.CreateBlake512(), + HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), + HashFactory.Crypto.SHA3.CreateGroestl512(), + HashFactory.Crypto.SHA3.CreateSkein512(), + HashFactory.Crypto.SHA3.CreateJH512(), + HashFactory.Crypto.SHA3.CreateKeccak512(), + HashFactory.Crypto.SHA3.CreateLuffa512(), + HashFactory.Crypto.SHA3.CreateCubeHash512(), + HashFactory.Crypto.SHA3.CreateSHAvite3_512(), + HashFactory.Crypto.SHA3.CreateSIMD512(), + HashFactory.Crypto.SHA3.CreateEcho512(), + HashFactory.Crypto.SHA3.CreateHamsi512(), + HashFactory.Crypto.SHA3.CreateFugue512(), + HashFactory.Crypto.SHA3.CreateShabal512(), + HashFactory.Crypto.CreateWhirlpool(), + HashFactory.Crypto.CreateSHA512(), + HashFactory.Crypto.CreateHaval_5_256(), + }; + + Multiplier = 1; + } + + public byte[] Hash(byte[] input, dynamic config) + { + var buffer = input; + + foreach (var hasher in _hashers) + { + buffer = hasher.ComputeBytes(buffer).GetBytes(); + } + + return buffer; + } + } +} diff --git a/src/CoiniumServ/Crypto/Hash.cs b/src/CoiniumServ/Cryptology/Hash.cs similarity index 99% rename from src/CoiniumServ/Crypto/Hash.cs rename to src/CoiniumServ/Cryptology/Hash.cs index d036c8bd8..00ca60cd7 100644 --- a/src/CoiniumServ/Crypto/Hash.cs +++ b/src/CoiniumServ/Cryptology/Hash.cs @@ -30,7 +30,7 @@ // originally from: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Sha256Hash.cs -namespace CoiniumServ.Crypto +namespace CoiniumServ.Cryptology { /// /// A Hash just wraps a byte[] so that equals and hashcode work correctly, allowing it to be used as keys in a diff --git a/src/CoiniumServ/Cryptology/Merkle/IMerkleTree.cs b/src/CoiniumServ/Cryptology/Merkle/IMerkleTree.cs new file mode 100644 index 000000000..3eb763d66 --- /dev/null +++ b/src/CoiniumServ/Cryptology/Merkle/IMerkleTree.cs @@ -0,0 +1,47 @@ +#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; + +namespace CoiniumServ.Cryptology.Merkle +{ + /// + /// Merkle tree builder. + /// + /// + /// To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s + /// + /// https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees + /// + /// Python implementation: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-2-for-python + /// Original implementation: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Block.cs#330 + /// + public interface IMerkleTree + { + IList Steps { get; } + + List Branches { get; } + + byte[] WithFirst(byte[] first); + } +} diff --git a/src/CoiniumServ/Cryptology/Merkle/MerkleTree.cs b/src/CoiniumServ/Cryptology/Merkle/MerkleTree.cs new file mode 100644 index 000000000..1a9bf73ed --- /dev/null +++ b/src/CoiniumServ/Cryptology/Merkle/MerkleTree.cs @@ -0,0 +1,143 @@ +#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; +using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Helpers.Misc; + +namespace CoiniumServ.Cryptology.Merkle +{ + /// + /// Merkle tree builder. + /// + /// + /// To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s + /// + /// https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees + /// + /// Python implementation: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-2-for-python + /// Original implementation: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Block.cs#330 + /// + public class MerkleTree : IMerkleTree + { + /// + /// The steps in tree. + /// + public IList Steps { get; private set; } + + /// + /// List of hashes, will be used for calculation of merkle root. + /// This is not a list of all transactions, it only contains prepared hashes of steps of merkle tree algorithm. Please read some materials (http://en.wikipedia.org/wiki/Hash_tree) for understanding how merkle trees calculation works. (http://mining.bitcoin.cz/stratum-mining) + /// The coinbase transaction is hashed against the merkle branches to build the final merkle root. + /// + public List Branches + { + get + { + return Steps.Select(step => step.ToHexString()).ToList(); + } + } + + /// + /// Creates a new merkle-tree instance. + /// + /// + public MerkleTree(IEnumerable hashList) + { + Steps = CalculateSteps(hashList); + } + + /// + /// + /// + /// + /// python: http://runnable.com/U3jqtyYUmAUxtsSS/bitcoin-block-merkle-root-python + /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/merkleTree.js#L9 + /// + /// + /// + private IList CalculateSteps(IEnumerable hashList) + { + var steps = new List(); + + var L = new List {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(); + + foreach (int i in Range.From(startL).To(Ll).WithStepSize(2)) + { + Ld.Add(MerkleJoin(L[i], L[i + 1])); + } + + L = new List {null}; + L.AddRange(Ld); + Ll = L.Count; + } + } + return steps; + } + + /// + /// + /// + /// + /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/merkleTree.js#L11 + /// + /// + /// + /// + private byte[] MerkleJoin(byte[] hash1, byte[] hash2) + { + var joined = hash1.Append(hash2); + var dHashed = joined.DoubleDigest(); + return dHashed; + } + + public byte[] WithFirst(byte[] first) + { + foreach (var step in Steps) + { + first = first.Append(step).DoubleDigest(); + } + + return first; + } + } +} diff --git a/src/CoiniumServ/Crypto/Utils.cs b/src/CoiniumServ/Cryptology/Utils.cs similarity index 98% rename from src/CoiniumServ/Crypto/Utils.cs rename to src/CoiniumServ/Cryptology/Utils.cs index f4023ac78..75625662e 100644 --- a/src/CoiniumServ/Crypto/Utils.cs +++ b/src/CoiniumServ/Cryptology/Utils.cs @@ -24,7 +24,7 @@ using System; using System.Security.Cryptography; -namespace CoiniumServ.Crypto +namespace CoiniumServ.Cryptology { public static class Utils { diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs new file mode 100644 index 000000000..be5bf751b --- /dev/null +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -0,0 +1,32 @@ +#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.Factories +{ + /// + /// Configuration factory that handles configs. + /// + public class ConfigFactory:IConfigFactory + { + } +} diff --git a/src/CoiniumServ/Factories/IConfigFactory.cs b/src/CoiniumServ/Factories/IConfigFactory.cs new file mode 100644 index 000000000..07c5d1b44 --- /dev/null +++ b/src/CoiniumServ/Factories/IConfigFactory.cs @@ -0,0 +1,32 @@ +#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.Factories +{ + /// + /// Configuration factory that handles configs. + /// + public interface IConfigFactory + { + } +} diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs new file mode 100644 index 000000000..89afe98ff --- /dev/null +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -0,0 +1,40 @@ +#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 CoiniumServ.Cryptology.Algorithms; + +namespace CoiniumServ.Factories +{ + /// + /// Object factory that creates instances of objects + /// + public interface IObjectFactory + { + /// + /// Returns instance of the given hash algorithm + /// + /// + /// + IHashAlgorithm GetHashAlgorithm(string algorithm); + } +} diff --git a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs similarity index 71% rename from src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs rename to src/CoiniumServ/Factories/ObjectFactory.cs index 335db36f7..ac6678340 100644 --- a/src/CoiniumServ/Crypto/Algorithms/HashAlgorithmFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -1,4 +1,4 @@ -#region License +#region License // // CoiniumServ - Crypto Currency Mining Pool Server Software // Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org @@ -21,34 +21,38 @@ // #endregion +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Repository.Context; -namespace CoiniumServ.Crypto.Algorithms +namespace CoiniumServ.Factories { - public class HashAlgorithmFactory : IHashAlgorithmFactory + /// + /// Object factory that creates instances of objects + /// + public class ObjectFactory:IObjectFactory { /// - /// The application context. + /// The application context for internal use. /// private readonly IApplicationContext _applicationContext; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The application context. - public HashAlgorithmFactory(IApplicationContext applicationContext) + public ObjectFactory(IApplicationContext applicationContext) { _applicationContext = applicationContext; } /// - /// Gets the specified algorithm name. + /// Returns instance of the given hash algorithm. /// - /// Name of the algorithm. + /// /// - public IHashAlgorithm Get(string algorithm) + public IHashAlgorithm GetHashAlgorithm(string algorithm) { return _applicationContext.Container.Resolve(algorithm); } } -} \ No newline at end of file +} diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs index c4ebc8a14..892e5d5a5 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs @@ -22,7 +22,7 @@ #endregion using CoiniumServ.Coin.Config; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Miners; diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index dff090fc9..71b1b2725 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -24,7 +24,7 @@ using System; using System.Threading; using CoiniumServ.Coin.Config; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Mining.Jobs.Tracker; diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs index 0365e0925..71d0d728c 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs @@ -22,7 +22,7 @@ #endregion using CoiniumServ.Coin.Config; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Miners; diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index b75224e89..5837ef4d2 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -26,8 +26,9 @@ using System.Linq; using System.Security.Cryptography; using CoiniumServ.Coin.Helpers; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; +using CoiniumServ.Factories; using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; @@ -55,20 +56,21 @@ public class Pool : IPool public IPerPool Statistics { get; private set; } - private readonly IDaemonClient _daemonClient; - private readonly IServerFactory _serverFactory; + private readonly IObjectFactory _objectFactory; + private readonly IServiceFactory _serviceFactory; private readonly IJobTrackerFactory _jobTrackerFactory; private readonly IJobManagerFactory _jobManagerFactory; private readonly IShareManagerFactory _shareManagerFactory; private readonly IMinerManagerFactory _minerManagerFactory; - private readonly IHashAlgorithmFactory _hashAlgorithmFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; private readonly IBanManagerFactory _banningManagerFactory; + private readonly IDaemonClient _daemonClient; + private readonly IServerFactory _serverFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; private IJobManager _jobManager; @@ -105,7 +107,7 @@ public class Pool : IPool /// /// public Pool( - IHashAlgorithmFactory hashAlgorithmFactory, + IObjectFactory objectFactory, IServerFactory serverFactory, IServiceFactory serviceFactory, IDaemonClient client, @@ -119,7 +121,9 @@ public Pool( IVardiffManagerFactory vardiffManagerFactory, IBanManagerFactory banningManagerFactory) { - Enforce.ArgumentNotNull(hashAlgorithmFactory, "IHashAlgorithmFactory"); + + Enforce.ArgumentNotNull(objectFactory, "IObjectFactory"); + Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); Enforce.ArgumentNotNull(serviceFactory, "IServiceFactory"); Enforce.ArgumentNotNull(client, "IDaemonClient"); @@ -132,6 +136,8 @@ public Pool( Enforce.ArgumentNotNull(vardiffManagerFactory, "IVardiffManagerFactory"); Enforce.ArgumentNotNull(banningManagerFactory, "IBanningManagerFactory"); + _objectFactory = objectFactory; + _daemonClient = client; _minerManagerFactory = minerManagerFactory; _jobManagerFactory = jobManagerFactory; @@ -139,7 +145,6 @@ public Pool( _shareManagerFactory = shareManagerFactory; _serverFactory = serverFactory; _serviceFactory = serviceFactory; - _hashAlgorithmFactory = hashAlgorithmFactory; _storageFactory = storageFactory; _paymentProcessorFactory = paymentProcessorFactory; _statisticsObjectFactory = statisticsObjectFactory; @@ -178,7 +183,7 @@ private void InitDaemon() private void InitManagers() { // init the algorithm - _hashAlgorithm = _hashAlgorithmFactory.Get(Config.Coin.Algorithm); + _hashAlgorithm = _objectFactory.GetHashAlgorithm(Config.Coin.Algorithm); _storage = _storageFactory.Get(Storages.Redis, Config); diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs index 2a8284be3..77f888f6f 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools.Config; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs index 065ce1e1f..63daadf99 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs @@ -24,7 +24,7 @@ using System; using System.Dynamic; using System.Linq; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools.Config; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs index b386b69d0..cbd10ff3a 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools.Config; diff --git a/src/CoiniumServ/Mining/Shares/IShare.cs b/src/CoiniumServ/Mining/Shares/IShare.cs index 76364045f..b48997e80 100644 --- a/src/CoiniumServ/Mining/Shares/IShare.cs +++ b/src/CoiniumServ/Mining/Shares/IShare.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Crypto; +using CoiniumServ.Cryptology; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Miners; using CoiniumServ.Server.Mining.Stratum.Notifications; diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Mining/Shares/Share.cs index cc24e82ad..86b2db77b 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Mining/Shares/Share.cs @@ -23,8 +23,8 @@ using System; using CoiniumServ.Coin.Coinbase; -using CoiniumServ.Crypto; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Miners; using CoiniumServ.Server.Mining.Stratum; diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 27f4cd36e..811020634 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -26,7 +26,6 @@ using System.Reflection; using System.Threading; using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Shares; using CoiniumServ.Repository; using CoiniumServ.Server.Web; using CoiniumServ.Utils; diff --git a/src/CoiniumServ/Repository/Registries/AlgorithmRegistry.cs b/src/CoiniumServ/Repository/Registries/AlgorithmRegistry.cs new file mode 100644 index 000000000..90b910f2d --- /dev/null +++ b/src/CoiniumServ/Repository/Registries/AlgorithmRegistry.cs @@ -0,0 +1,55 @@ +#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 CoiniumServ.Cryptology.Algorithms; +using CoiniumServ.Repository.Context; + +namespace CoiniumServ.Repository.Registries +{ + public class AlgorithmRegistry : IRegistry + { + private readonly IApplicationContext _applicationContext; + + public AlgorithmRegistry(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + public void RegisterInstances() + { + // hash algorithms + _applicationContext.Container.Register(Algorithms.Blake).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Fugue).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Groestl).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Keccak).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Scrypt).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Sha256).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Shavite3).AsSingleton(); + _applicationContext.Container.Register(Algorithms.Skein).AsSingleton(); + _applicationContext.Container.Register(Algorithms.X11).AsSingleton(); + _applicationContext.Container.Register(Algorithms.X13).AsSingleton(); + _applicationContext.Container.Register(Algorithms.X15).AsSingleton(); + _applicationContext.Container.Register(Algorithms.X17).AsSingleton(); + } + } +} \ No newline at end of file diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index ce8436f16..47f1e418c 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -21,7 +21,6 @@ // #endregion -using CoiniumServ.Crypto.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Pools; @@ -45,20 +44,6 @@ public ClassRegistry(IApplicationContext applicationContext) public void RegisterInstances() { - // hash algorithms - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Blake).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Fugue).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Groestl).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Keccak).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Scrypt).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Sha256).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Shavite3).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.Skein).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X11).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X13).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X15).AsSingleton(); - _applicationContext.Container.Register(Crypto.Algorithms.Algorithms.X17).AsSingleton(); - _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 759823a67..6e841b22b 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -22,7 +22,7 @@ #endregion using CoiniumServ.Coin.Config; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Factories; using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; @@ -52,8 +52,9 @@ public FactoryRegistry(IApplicationContext applicationContext) public void RegisterInstances() { + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index ac95fe133..50922fba8 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -53,6 +53,7 @@ public void RegisterInstances() typeof(ServiceRegistry), typeof(ClassRegistry), typeof(FactoryRegistry), + typeof(AlgorithmRegistry), }); } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs index 7efb2530d..5aab2076d 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs @@ -23,8 +23,8 @@ using System; using System.Collections.Generic; -using CoiniumServ.Crypto.Algorithms; -using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Cryptology.Algorithms; +using CoiniumServ.Cryptology.Merkle; using CoiniumServ.Daemon.Responses; using CoiniumServ.Transactions; using CoiniumServ.Utils.Numerics; diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs index 549c510e4..a26d4bbcc 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs @@ -26,8 +26,8 @@ using System.Collections.Generic; using System.Globalization; using CoiniumServ.Coin.Coinbase; -using CoiniumServ.Crypto.Algorithms; -using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Cryptology.Algorithms; +using CoiniumServ.Cryptology.Merkle; using CoiniumServ.Daemon.Responses; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Utils; diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 183509a36..eb9a0e331 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -26,7 +26,7 @@ using System.IO; using System.Linq; using CoiniumServ.Coin.Coinbase; -using CoiniumServ.Crypto; +using CoiniumServ.Cryptology; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; diff --git a/src/CoiniumServ/Transactions/OutPoint.cs b/src/CoiniumServ/Transactions/OutPoint.cs index e3a2651b3..0e20009a3 100644 --- a/src/CoiniumServ/Transactions/OutPoint.cs +++ b/src/CoiniumServ/Transactions/OutPoint.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Crypto; +using CoiniumServ.Cryptology; namespace CoiniumServ.Transactions { diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index bece1ef84..e0f8bbcac 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using System.Linq; using CoiniumServ.Coin.Coinbase; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; diff --git a/src/Tests/Crypto/Merkle/MerkleRootTests.cs b/src/Tests/Crypto/Merkle/MerkleRootTests.cs deleted file mode 100644 index bdc015efc..000000000 --- a/src/Tests/Crypto/Merkle/MerkleRootTests.cs +++ /dev/null @@ -1,189 +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 CoiniumServ.Crypto.Merkle; -using CoiniumServ.Utils.Extensions; -using Should.Fluent; -using Xunit; - -namespace CoiniumServ.Tests.Crypto.Merkle -{ - public class MerkleRootTests - { - /// - /// Tests bitcoin block 300384 with only a single (generation) transaction. - /// Block: http://blockexplorer.com/block/0000000000000000646aeda800ee605632799ead6257976b3805c66682b4d34e - /// - [Fact] - public void TestBlockWithSingleTransaction() - { - var hashlist = new List - { - "d43d6fbe5e46ee82847421c1609fe1203c0f3db0992ac98a06684b10676b8428".HexToByteArray() - }; - - var merkleTree = new MerkleRoot(hashlist); - var expected = "d43d6fbe5e46ee82847421c1609fe1203c0f3db0992ac98a06684b10676b8428".HexToByteArray(); - - merkleTree.Root.Bytes.Should().Equal(expected); - } - - /// - /// Tests a block with 3 fake transactions. - /// - [Fact] - public void TestBlockWithThreeTransactions() - { - var hashlist = new List - { - "b9e8f1d2cea2b609faae19049546c8d3826d4d5268e3b1843d24234e6cc65c91".HexToByteArray(), - "26d0d04050d9d036f6677c49b558a492a6bcfb75e1de6b5c9335d26e729e5cd4".HexToByteArray(), - "c13a822f47072f9b2236cea9c22ab7e5d92c0ac4fd2a63af2c4ed1f2e306efd5".HexToByteArray(), - }; - - var merkleTree = new MerkleRoot(hashlist); - var expected = "a907cc5d1de726136e50b1899672db2728c47897902718fbcfd133ed11331a66".HexToByteArray(); - - merkleTree.Root.Bytes.Should().Equal(expected); - } - - /// - /// Test bitcoin block 286819 merkle root against our merkle functions. - /// Why this block? Because it's quite popular for so. - /// Block: http://blockexplorer.com/block/0000000000000000e067a478024addfecdc93628978aa52d91fabd4292982a50 - /// Python implementation for the block: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-286819-for-python - /// - [Fact] - public void TestBlockWithManyTransactions() - { - var hashlist = new List - { - "00baf6626abc2df808da36a518c69f09b0d2ed0a79421ccfde4f559d2e42128b".HexToByteArray(), - "91c5e9f288437262f218c60f986e8bc10fb35ab3b9f6de477ff0eb554da89dea".HexToByteArray(), - "46685c94b82b84fa05b6a0f36de6ff46475520113d5cb8c6fb060e043a0dbc5c".HexToByteArray(), - "ba7ed2544c78ad793ef5bb0ebe0b1c62e8eb9404691165ffcb08662d1733d7a8".HexToByteArray(), - "b8dc1b7b7ed847c3595e7b02dbd7372aa221756b718c5f2943c75654faf48589".HexToByteArray(), - "25074ef168a061fcc8663b4554a31b617683abc33b72d2e2834f9329c93f8214".HexToByteArray(), - "0fb8e311bffffadc6dc4928d7da9e142951d3ba726c8bde2cf1489b62fb9ebc5".HexToByteArray(), - "c67c79204e681c8bb453195db8ca7d61d4692f0098514ca198ccfd1b59dbcee3".HexToByteArray(), - "bd27570a6cbd8ad026bfdb8909fdae9321788f0643dea195f39cd84a60a1901b".HexToByteArray(), - "41a06e53ffc5108358ddcec05b029763d714ae9f33c5403735e8dee78027fe74".HexToByteArray(), - "cc2696b44cb07612c316f24c07092956f7d8b6e0d48f758572e0d611d1da6fb9".HexToByteArray(), - "8fc508772c60ace7bfeb3f5f3a507659285ea6f351ac0474a0a9710c7673d4fd".HexToByteArray(), - "62fed508c095446d971580099f976428fc069f32e966a40a991953b798b28684".HexToByteArray(), - "928eadbc39196b95147416eedf6f635dcff818916da65419904df8fde977d5db".HexToByteArray(), - "b137e685df7c1dffe031fb966a0923bb5d0e56f381e730bc01c6d5244cfe47c1".HexToByteArray(), - "b92207cee1f9e0bfbd797b05a738fab9de9c799b74f54f6b922f20bd5ec23dd6".HexToByteArray(), - "29d6f37ada0481375b6903c6480a81f8deaf2dcdba03411ed9e8d3e5684d02dd".HexToByteArray(), - "48158deb116e4fd0429fbbbae61e8e68cb6d0e0c4465ff9a6a990037f88c489c".HexToByteArray(), - "be64ea86960864cc0a0236bbb11f232faf5b19ae6e2c85518628f5fae37ec1ca".HexToByteArray(), - "081363552e9fff7461f1fc6663e1abd0fb2dd1c54931e177479a18c4c26260e8".HexToByteArray(), - "eb87c25dd2b2537b1ff3dbabc420e422e2a801f1bededa6fa49ef7980feaef70".HexToByteArray(), - "339e16fcc11deb61ccb548239270af43f5ad34c321416bada4b8d66467b1c697".HexToByteArray(), - "4ad6417a3a04179482ed2e4b7251c396e38841c6fba8d2ce9543337ab7c93c02".HexToByteArray(), - "c28a45cded020bf424b400ffc9cb6f2f85601934f18c34a4f78283247192056a".HexToByteArray(), - "882037cc9e3ee6ddc2d3eba86b7ca163533b5d3cbb16eaa38696bb0a2ea1137e".HexToByteArray(), - "179bb936305b46bb0a9df330f8701984c725a60e063ad5892fa97461570b5c04".HexToByteArray(), - "9517c585d1578cb327b7988f38e1a15c663955ea288a2292b40d27f232fbb980".HexToByteArray(), - "2c7e07d0cf42e5520bcbfe2f5ef63761a9ab9d7ccb00ea346195eae030f3b86f".HexToByteArray(), - "534f631fc42ae2d309670e01c7a0890e4bfb65bae798522ca14df09c81b09734".HexToByteArray(), - "104643385619adb848593eb668a8066d1f32650edf35e74b0fc3306cb6719448".HexToByteArray(), - "87ac990808239c768182a752f4f71cd98558397072883c7e137efb49d22b9231".HexToByteArray(), - "9b3e2f1c47d59a444e9b6dc725f0ac6baf160d22f3a9d399434e5e65b14eccb0".HexToByteArray(), - "fbe123066ae5add633a542f151663db4eb5a7053e388faadb40240671ae1b09b".HexToByteArray(), - "1dd07e92e20b3cb9208af040031f7cfc4efd46cc31ec27be20a1047965a42849".HexToByteArray(), - "2709bb9ed27353c1fd76b9240cab7576a44de68945e256ad44b2cb8d849a8060".HexToByteArray(), - "d0174db2c712573432a7869c1508f371f3a1058aeedddc1b53a7e04d7c56c725".HexToByteArray(), - "b4a16f724cddb8f77ddf3d2146a12c4be13d503885eaba3518a03da005009f62".HexToByteArray(), - "2aa706d75decbe57745e01d46f9f5d30a08dedaf3288cee14cc4948e3684e1d4".HexToByteArray(), - "ee49c5f6a5129ccaf2abebbc1d6d07a402a600af6221476b89aafaa683ca95b7".HexToByteArray(), - "bea1011c77874845e9b4c876ed2ceebd530d428dd4a564ad003d9211d40bb091".HexToByteArray(), - "f1e88ffc2b1de2aa4827002f06943ce5468735f7433f960bf01e75885b9f832b".HexToByteArray(), - "19247d017e002fb9143d1a89eb921222a94f8a3d0faaf2e05b0f594989edc4c4".HexToByteArray(), - "13f714ff62ee7d26b6d69ca980c141ebc54e9f71d2697083fe6c5efc1b02bd0f".HexToByteArray(), - "0c78cbb8246572f015fbdc53dc9798fa54d1119ec77c1f07ac310bcbcc40dbf8".HexToByteArray(), - "4bcde0ef92a6d24a2be7be50ac5e5299d776df2e6229ba5d475c2491da94f255".HexToByteArray(), - "0cfd7d1058502730cf0b2ffa880c78ef534651e06832b5d87c0d7eb84eac5b0c".HexToByteArray(), - "3a168f794d6e0c614429ad874317cc4cd67a8177214880ff6ea1704d29228c2f".HexToByteArray(), - "f9a555d817334397b402518d6fd959dc73d981ee7f5fe67969b63974ebbef127".HexToByteArray(), - "24b52691f66eaed4ce391a473902e309018257c98b9f02aaa33b399c9e6f3168".HexToByteArray(), - "a37b5e623dc26a180d9e2c9510d06885b014e86e533adb63ec40511e10b55046".HexToByteArray(), - "9dbaeb485e51d9e25a5621dc46e0bc0aaf51fb26be5acc4e370b96f62c469b80".HexToByteArray(), - "a6431d3d39f6c38c5df48405090752cab03bfdf5c77cf881b18a946807fba74a".HexToByteArray(), - "faa77e309f125373acf19855dd496fffe2f74962e545420844557a3adc7ebc11".HexToByteArray(), - "3523f52543ecfea2f78486dc91550fad0e6467d46d9d9c82ca63b2e0230bfa71".HexToByteArray(), - "a0583e358e42d77d18d1fd0533ff0a65615fc3b3112061ef92f168a00bf640c1".HexToByteArray(), - "42ae900888d5e5dde59c8e3d06e13db9e84ef05d27726d4b67fd00c50cd9406a".HexToByteArray(), - "154940777d3ff78f592ef02790131a59263c36b4958bbc836f9a767ea1a9f178".HexToByteArray(), - "6a0337de6ac75eecf748306e8ebc5bfe5c811a1481ae50f6956a9e7f26a679f5".HexToByteArray(), - "c99530c2148e09688d0b88795625943371183bf1f5d56c7446c6ed51ea133589".HexToByteArray(), - "626421dbe8ad6a0fd0d622d5dd3308a1cdc00b98575a41a91fe01a439e6f40bd".HexToByteArray(), - "b2f3a559f605a158cc395126c3cf394a7e92a53b7514c75157e1dc43a6c7f93e".HexToByteArray(), - "dffe06d1bea81f2a01c76786404bb867258f9e68013bf25454097ce935090738".HexToByteArray(), - "0860159ec7a2a51ce107c182a988c40b4bc2057a734354a1219b6c65e72640ed".HexToByteArray(), - "a405ff1bb51846b1867acc0b0da17f6f9616e592a0a7ff5ef3297c1ecfd60911".HexToByteArray(), - "a7d451924263284765f6343bca8a21b79b89ebfe611c7355dd88e0ec1c29e232".HexToByteArray(), - "41c758d08a4d3fe4d90645711589b832a2cd54dd25bd5b66e463e5d389a53aff".HexToByteArray(), - "a05c1a93a521fa5dbc1790cfbb808893453a428a65f2c6b2d51249fbb12db309".HexToByteArray(), - "90997920aa9786e10f513cfdd14e294feee6739cee1ab61b3fb1e3f42e7a915d".HexToByteArray(), - "99fcb9cb62c20a3135484a70bd3f73983f8f3b7b26266dad34f3993958a7642c".HexToByteArray(), - "e05f9a668b37e5f78bd3b9d047f29f92b33a87f11dd48390410006f858188b7b".HexToByteArray(), - "56dbc65895f7992da4a6985e7edba4d1c00879f1b28442c644c8a07658ceab27".HexToByteArray(), - "5e9004fe262b829563d0804656ba68b1de1690401f08a1915273230d8c902fc0".HexToByteArray(), - "1ea9ed3717523c5e304b7a7ac8058a87fb4f3fed8c6004769f226c9bb67e79c5".HexToByteArray(), - "f0f1a4c009b3f1b2729e89898e2f5c0fcdc312edea5df884a9c897cb90e4c566".HexToByteArray(), - "b5bb4ddf04863e6a60f33cb96c20dac8175d3bae55f335781503143c97a50e43".HexToByteArray(), - "f14cc97a20c6f627b4b78301352ae35463bc359362589cd178a06c0fa90850b7".HexToByteArray(), - "628801c8f614015c0fa0ccb2768cccc3e7b9d41ceed06071ce2534d31f7236d6".HexToByteArray(), - "3be1013c8f8da150e2195408093153b55b08b037fd92db8bb5e803f4c2538aae".HexToByteArray(), - "c9e1f8777685f54ba65c4e02915fd649ee1edcbf9c77ddf584b943d27efb86c3".HexToByteArray(), - "4274e92ed3bd02eb101baa5fb8ff7b96236830762d08273749fbb5166db8ab0b".HexToByteArray(), - "aa84c955bea04c7cee8f5bbbec97d25930fcaca363eed1b8cad37b931556d3e3".HexToByteArray(), - "d6a29c948677fb1f71aaf16debc3d071a4dd349458eb9e056dce3a000ff853da".HexToByteArray(), - "ba84bdb3d78367ca365016ac4bff9269576eb010f874c2967af73e0de5638de0".HexToByteArray(), - "1546c79951e3b541bc64d1957b565b7a2850fc87192c7b374aee6cfc69b9805e".HexToByteArray(), - "f119227d492ebe27fe9aae321980802454dfa64b2691efbe796c5075d5b07f62".HexToByteArray(), - "b8cf13d64818b32f96bbb585998b1bc9505f6a94055488e5a71fee9479c6f2a9".HexToByteArray(), - "1aaf459705b6afef2d7b83e3f181f1af55be0813daf55edce104cc59abc28ed7".HexToByteArray(), - "61ac185c8f520b5e3134953dc52ff292a40e1e96b088dab259558a9d240ec02f".HexToByteArray(), - "2da96e3154d7ec2329f787b73cb8a436b92d64cf3cc28e920d073279ea73b5f8".HexToByteArray(), - "1c4d72ce733b971b9ec4e24f37d733355f6f2ea635cc67ffb3e22748484df446".HexToByteArray(), - "2a6f89769f3272ac8c7a36a42a57627eca6b260ab2c76d8046a27d44d4034893".HexToByteArray(), - "f8d11df51a2cc113698ebf39a958fe81179d7d973d2044322771c0fe63f4d7c9".HexToByteArray(), - "f2287f17a4fa232dca5715c24a92f7112402a8101b9a7b276fb8c8f617376b90".HexToByteArray(), - "bb5ee510a4fda29cae30c97e7eee80569d3ec3598465f2d7e0674c395e0256e9".HexToByteArray(), - "647ab8c84365620d60f2523505d14bd230b5e650c96dee48be47770063ee7461".HexToByteArray(), - "34b06018fcc33ba6ebb01198d785b0629fbdc5d1948f688059158f053093f08b".HexToByteArray(), - "ff58b258dab0d7f36a2908e6c75229ce308d34806289c912a1a5f39a5aa71f9f".HexToByteArray(), - "232fc124803668a9f23b1c3bcb1134274303f5c0e1b0e27c9b6c7db59f0e2a4d".HexToByteArray(), - "27a0797cc5b042ba4c11e72a9555d13a67f00161550b32ede0511718b22dbc2c".HexToByteArray() - }; - - var merkleTree = new MerkleRoot(hashlist); - var expected = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a".HexToByteArray(); - - merkleTree.Root.Bytes.Should().Equal(expected); - } - } -} diff --git a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs b/src/Tests/Cryptology/Merkle/MerkleTreeTests.cs similarity index 99% rename from src/Tests/Crypto/Merkle/MerkleTreeTests.cs rename to src/Tests/Cryptology/Merkle/MerkleTreeTests.cs index 4cfe3d58b..581f14c17 100644 --- a/src/Tests/Crypto/Merkle/MerkleTreeTests.cs +++ b/src/Tests/Cryptology/Merkle/MerkleTreeTests.cs @@ -22,7 +22,7 @@ #endregion using System.Linq; -using CoiniumServ.Crypto.Merkle; +using CoiniumServ.Cryptology.Merkle; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Transactions.Utils; @@ -31,7 +31,7 @@ using Should.Fluent; using Xunit; -namespace CoiniumServ.Tests.Crypto.Merkle +namespace CoiniumServ.Tests.Cryptology.Merkle { public class MerkleTreeTests { diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 1db178037..f9529410c 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -22,10 +22,10 @@ #endregion using System; -using CoiniumServ.Coin.Config; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; +using CoiniumServ.Factories; using CoiniumServ.Mining.Banning; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; @@ -49,12 +49,12 @@ namespace CoiniumServ.Tests.Mining.Pools public class PoolTests { // factory mocks + private readonly IObjectFactory _objectFactory; private readonly IServerFactory _serverFactory; private readonly IServiceFactory _serviceFactory; private readonly IJobManagerFactory _jobManagerFactory; private readonly IJobTrackerFactory _jobTrackerFactory; private readonly IShareManagerFactory _shareManagerFactory; - private readonly IHashAlgorithmFactory _hashAlgorithmFactory; private readonly IMinerManagerFactory _minerManagerFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; @@ -82,9 +82,9 @@ public class PoolTests /// public PoolTests() { + _objectFactory = Substitute.For(); _jobManagerFactory = Substitute.For(); _jobTrackerFactory = Substitute.For(); - _hashAlgorithmFactory = Substitute.For(); _shareManagerFactory = Substitute.For(); _minerManagerFactory = Substitute.For(); _serverFactory = Substitute.For(); @@ -120,7 +120,7 @@ public PoolTests() public void ConstructorTest_NonNullParams_ShouldSucceed() { var pool = new Pool( - _hashAlgorithmFactory, + _objectFactory, _serverFactory, _serviceFactory, _daemonClient, @@ -144,7 +144,7 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() public void InitializationTest_NonNullParams_ShouldSuccess() { var pool = new Pool( - _hashAlgorithmFactory, + _objectFactory, _serverFactory, _serviceFactory, _daemonClient, @@ -162,7 +162,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // initialize hash algorithm var hashAlgorithm = Substitute.For(); - _hashAlgorithmFactory.Get(_config.Coin.Algorithm).Returns(hashAlgorithm); + _objectFactory.GetHashAlgorithm(_config.Coin.Algorithm).Returns(hashAlgorithm); // initialize the miner manager. _minerManagerFactory.Get(_daemonClient, _config.Coin); diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index a25eef841..1701778a6 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -24,7 +24,7 @@ using System; using System.Collections.Generic; using System.Linq; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index 8d9d73cee..09f9feb6a 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -24,7 +24,7 @@ using System; using System.Collections.Generic; using System.Linq; -using CoiniumServ.Crypto.Algorithms; +using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 7a436b161..7b5a84515 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -69,13 +69,12 @@ - - + From fbb5ef971660fcf7dcc52e57ab5afee49dafaef4 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 19 Jul 2014 15:04:56 +0300 Subject: [PATCH 101/230] Fixing the last commit --- .../Crypto/Algorithms/Algorithms.cs | 56 -------------- src/CoiniumServ/Crypto/Algorithms/Blake.cs | 47 ------------ src/CoiniumServ/Crypto/Algorithms/Fugue.cs | 47 ------------ src/CoiniumServ/Crypto/Algorithms/Groestl.cs | 47 ------------ .../Crypto/Algorithms/IHashAlgorithm.cs | 34 --------- src/CoiniumServ/Crypto/Algorithms/Keccak.cs | 47 ------------ src/CoiniumServ/Crypto/Algorithms/Scrypt.cs | 71 ------------------ src/CoiniumServ/Crypto/Algorithms/Sha256.cs | 52 ------------- src/CoiniumServ/Crypto/Algorithms/Shavite3.cs | 46 ------------ src/CoiniumServ/Crypto/Algorithms/Skein.cs | 46 ------------ src/CoiniumServ/Crypto/Algorithms/X11.cs | 67 ----------------- src/CoiniumServ/Crypto/Algorithms/X13.cs | 69 ------------------ src/CoiniumServ/Crypto/Algorithms/X15.cs | 71 ------------------ src/CoiniumServ/Crypto/Algorithms/X17.cs | 73 ------------------- 14 files changed, 773 deletions(-) delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Algorithms.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Blake.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Fugue.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Groestl.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Keccak.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Scrypt.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Sha256.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Shavite3.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/Skein.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/X11.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/X13.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/X15.cs delete mode 100644 src/CoiniumServ/Crypto/Algorithms/X17.cs diff --git a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs b/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs deleted file mode 100644 index f202a8f16..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Algorithms.cs +++ /dev/null @@ -1,56 +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.Globalization; -using CoiniumServ.Utils.Numerics; - -namespace CoiniumServ.Crypto.Algorithms -{ - public static class Algorithms - { - public const string Blake = "blake"; - public const string Fugue = "fugue"; - public const string Groestl = "groestl"; - public const string Keccak = "keccak"; - public const string Scrypt = "scrypt"; - public const string Sha256 = "sha256"; - public const string Shavite3 = "shavite3"; - public const string Skein = "skein"; - public const string X11 = "X11"; - public const string X13 = "X13"; - public const string X15 = "X15"; - public const string X17 = "X17"; - - // todo: add hefty1, qubit support - - /// - /// Global diff1 - /// - public static BigInteger Diff1 { get; private set; } - - static Algorithms() - { - Diff1 = BigInteger.Parse("00000000ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Blake.cs b/src/CoiniumServ/Crypto/Algorithms/Blake.cs deleted file mode 100644 index 06859c56f..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Blake.cs +++ /dev/null @@ -1,47 +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; -using HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Blake : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Blake() - { - _hasher = HashFactory.Crypto.SHA3.CreateBlake256(); - - Multiplier = (UInt32) Math.Pow(2, 8); - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Fugue.cs b/src/CoiniumServ/Crypto/Algorithms/Fugue.cs deleted file mode 100644 index e1850e922..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Fugue.cs +++ /dev/null @@ -1,47 +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; -using HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Fugue : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Fugue() - { - _hasher = HashFactory.Crypto.SHA3.CreateFugue256(); - - Multiplier = (UInt32)Math.Pow(2, 8); - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Groestl.cs b/src/CoiniumServ/Crypto/Algorithms/Groestl.cs deleted file mode 100644 index d1e5f8433..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Groestl.cs +++ /dev/null @@ -1,47 +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; -using HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Groestl : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Groestl() - { - _hasher = HashFactory.Crypto.SHA3.CreateGroestl512(); - - Multiplier = (UInt32)Math.Pow(2, 8); - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs b/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs deleted file mode 100644 index fe2d97d20..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/IHashAlgorithm.cs +++ /dev/null @@ -1,34 +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; - -namespace CoiniumServ.Crypto.Algorithms -{ - public interface IHashAlgorithm - { - UInt32 Multiplier { get; } - - byte[] Hash(byte[] input, dynamic config); - } -} \ No newline at end of file diff --git a/src/CoiniumServ/Crypto/Algorithms/Keccak.cs b/src/CoiniumServ/Crypto/Algorithms/Keccak.cs deleted file mode 100644 index 3f040dbd9..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Keccak.cs +++ /dev/null @@ -1,47 +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; -using HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Keccak : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Keccak() - { - _hasher = HashFactory.Crypto.SHA3.CreateKeccak256(); - - Multiplier = (UInt32)Math.Pow(2, 8); - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs b/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs deleted file mode 100644 index 37610fccb..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Scrypt.cs +++ /dev/null @@ -1,71 +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; -using System.Globalization; -using CoiniumServ.Utils.Numerics; -using CryptSharp.Utility; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Scrypt : IHashAlgorithm - { - /// - /// Gets the multiplier. - /// - /// - /// The multiplier. - /// - public UInt32 Multiplier { get; private set; } - - /// - /// N parameter - CPU/memory cost parameter. - /// - private readonly int _n; - - /// - /// R parameter - block size. - /// - private readonly int _r; - - /// - /// P - parallelization parameter - a large value of p can increase computational - /// cost of scrypt without increasing the memory usage. - /// - private readonly int _p; - - public Scrypt() - { - _n = 1024; - _r = 1; - _p = 1; - - Multiplier = (UInt32) Math.Pow(2, 16); - } - - public byte[] Hash(byte[] input, dynamic config) - { - return SCrypt.ComputeDerivedKey(input, input, _n, _r, _p, null, 32); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Sha256.cs b/src/CoiniumServ/Crypto/Algorithms/Sha256.cs deleted file mode 100644 index 27a703bce..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Sha256.cs +++ /dev/null @@ -1,52 +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.Security.Cryptography; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Sha256:IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly SHA256Managed _algorithm; - - public Sha256() - { - _algorithm = new SHA256Managed(); - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - return DoubleDigest(input); // coins like bitcoin (sha256d coins) uses double-digest. - } - - public byte[] DoubleDigest(byte[] input) - { - var first = _algorithm.ComputeHash(input); - return _algorithm.ComputeHash(first); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs b/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs deleted file mode 100644 index 6ed50ce74..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Shavite3.cs +++ /dev/null @@ -1,46 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Shavite3 : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Shavite3() - { - _hasher = HashFactory.Crypto.SHA3.CreateSHAvite3_512(); - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/Skein.cs b/src/CoiniumServ/Crypto/Algorithms/Skein.cs deleted file mode 100644 index 1e99e6b96..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/Skein.cs +++ /dev/null @@ -1,46 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class Skein : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly IHash _hasher; - - public Skein() - { - _hasher = HashFactory.Crypto.SHA3.CreateSkein512(); - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - return _hasher.ComputeBytes(input).GetBytes(); - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/X11.cs b/src/CoiniumServ/Crypto/Algorithms/X11.cs deleted file mode 100644 index 59d19baea..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/X11.cs +++ /dev/null @@ -1,67 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class X11 : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly List _hashers; - - public X11() - { - _hashers = new List - { - HashFactory.Crypto.SHA3.CreateBlake512(), - HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), - HashFactory.Crypto.SHA3.CreateGroestl512(), - HashFactory.Crypto.SHA3.CreateSkein512(), - HashFactory.Crypto.SHA3.CreateJH512(), - HashFactory.Crypto.SHA3.CreateKeccak512(), - HashFactory.Crypto.SHA3.CreateLuffa512(), - HashFactory.Crypto.SHA3.CreateCubeHash512(), - HashFactory.Crypto.SHA3.CreateSHAvite3_512(), - HashFactory.Crypto.SHA3.CreateSIMD512(), - HashFactory.Crypto.SHA3.CreateEcho512(), - }; - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - var buffer = input; - - foreach (var hasher in _hashers) - { - buffer = hasher.ComputeBytes(buffer).GetBytes(); - } - - return buffer; - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/X13.cs b/src/CoiniumServ/Crypto/Algorithms/X13.cs deleted file mode 100644 index e4069abfc..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/X13.cs +++ /dev/null @@ -1,69 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class X13 : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly List _hashers; - - public X13() - { - _hashers = new List - { - HashFactory.Crypto.SHA3.CreateBlake512(), - HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), - HashFactory.Crypto.SHA3.CreateGroestl512(), - HashFactory.Crypto.SHA3.CreateSkein512(), - HashFactory.Crypto.SHA3.CreateJH512(), - HashFactory.Crypto.SHA3.CreateKeccak512(), - HashFactory.Crypto.SHA3.CreateLuffa512(), - HashFactory.Crypto.SHA3.CreateCubeHash512(), - HashFactory.Crypto.SHA3.CreateSHAvite3_512(), - HashFactory.Crypto.SHA3.CreateSIMD512(), - HashFactory.Crypto.SHA3.CreateEcho512(), - HashFactory.Crypto.SHA3.CreateHamsi512(), - HashFactory.Crypto.SHA3.CreateFugue512(), - }; - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - var buffer = input; - - foreach (var hasher in _hashers) - { - buffer = hasher.ComputeBytes(buffer).GetBytes(); - } - - return buffer; - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/X15.cs b/src/CoiniumServ/Crypto/Algorithms/X15.cs deleted file mode 100644 index 96031c5b6..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/X15.cs +++ /dev/null @@ -1,71 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class X15 : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly List _hashers; - - public X15() - { - _hashers = new List - { - HashFactory.Crypto.SHA3.CreateBlake512(), - HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), - HashFactory.Crypto.SHA3.CreateGroestl512(), - HashFactory.Crypto.SHA3.CreateSkein512(), - HashFactory.Crypto.SHA3.CreateJH512(), - HashFactory.Crypto.SHA3.CreateKeccak512(), - HashFactory.Crypto.SHA3.CreateLuffa512(), - HashFactory.Crypto.SHA3.CreateCubeHash512(), - HashFactory.Crypto.SHA3.CreateSHAvite3_512(), - HashFactory.Crypto.SHA3.CreateSIMD512(), - HashFactory.Crypto.SHA3.CreateEcho512(), - HashFactory.Crypto.SHA3.CreateHamsi512(), - HashFactory.Crypto.SHA3.CreateFugue512(), - HashFactory.Crypto.SHA3.CreateShabal512(), - HashFactory.Crypto.CreateWhirlpool(), - }; - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - var buffer = input; - - foreach (var hasher in _hashers) - { - buffer = hasher.ComputeBytes(buffer).GetBytes(); - } - - return buffer; - } - } -} diff --git a/src/CoiniumServ/Crypto/Algorithms/X17.cs b/src/CoiniumServ/Crypto/Algorithms/X17.cs deleted file mode 100644 index 137a75c6f..000000000 --- a/src/CoiniumServ/Crypto/Algorithms/X17.cs +++ /dev/null @@ -1,73 +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 HashLib; - -namespace CoiniumServ.Crypto.Algorithms -{ - public class X17 : IHashAlgorithm - { - public uint Multiplier { get; private set; } - - private readonly List _hashers; - - public X17() - { - _hashers = new List - { - HashFactory.Crypto.SHA3.CreateBlake512(), - HashFactory.Crypto.SHA3.CreateBlueMidnightWish512(), - HashFactory.Crypto.SHA3.CreateGroestl512(), - HashFactory.Crypto.SHA3.CreateSkein512(), - HashFactory.Crypto.SHA3.CreateJH512(), - HashFactory.Crypto.SHA3.CreateKeccak512(), - HashFactory.Crypto.SHA3.CreateLuffa512(), - HashFactory.Crypto.SHA3.CreateCubeHash512(), - HashFactory.Crypto.SHA3.CreateSHAvite3_512(), - HashFactory.Crypto.SHA3.CreateSIMD512(), - HashFactory.Crypto.SHA3.CreateEcho512(), - HashFactory.Crypto.SHA3.CreateHamsi512(), - HashFactory.Crypto.SHA3.CreateFugue512(), - HashFactory.Crypto.SHA3.CreateShabal512(), - HashFactory.Crypto.CreateWhirlpool(), - HashFactory.Crypto.CreateSHA512(), - HashFactory.Crypto.CreateHaval_5_256(), - }; - - Multiplier = 1; - } - - public byte[] Hash(byte[] input, dynamic config) - { - var buffer = input; - - foreach (var hasher in _hashers) - { - buffer = hasher.ComputeBytes(buffer).GetBytes(); - } - - return buffer; - } - } -} From 5ad53b00eb901428c2c6a97e856bda2d5b81ba9d Mon Sep 17 00:00:00 2001 From: bonesoul Date: Sat, 19 Jul 2014 16:00:54 +0300 Subject: [PATCH 102/230] Fix for last commit #2. --- src/CoiniumServ/CoiniumServ.csproj | 3 + src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs | 34 ----- src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs | 47 ------ src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs | 130 ----------------- src/CoiniumServ/Crypto/Merkle/MerkleTree.cs | 143 ------------------- src/CoiniumServ/Mining/Pools/Pool.cs | 2 +- src/CoiniumServ/config/coins/namecoin.json | 5 + src/CoiniumServ/config/pools/sample.json | 2 +- 8 files changed, 10 insertions(+), 356 deletions(-) delete mode 100644 src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs delete mode 100644 src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs delete mode 100644 src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs delete mode 100644 src/CoiniumServ/Crypto/Merkle/MerkleTree.cs create mode 100644 src/CoiniumServ/config/coins/namecoin.json diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index ee72817dd..11c00bfcb 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -399,6 +399,9 @@ + + PreserveNewest + PreserveNewest diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs deleted file mode 100644 index 9429bfab6..000000000 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleRoot.cs +++ /dev/null @@ -1,34 +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; - -namespace CoiniumServ.Crypto.Merkle -{ - public interface IMerkleRoot - { - IList Tree { get; } - - Hash Root { get; } - } -} diff --git a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs deleted file mode 100644 index 245e9d83f..000000000 --- a/src/CoiniumServ/Crypto/Merkle/IMerkleTree.cs +++ /dev/null @@ -1,47 +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; - -namespace CoiniumServ.Crypto.Merkle -{ - /// - /// Merkle tree builder. - /// - /// - /// To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s - /// - /// https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees - /// - /// Python implementation: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-2-for-python - /// Original implementation: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Block.cs#330 - /// - public interface IMerkleTree - { - IList Steps { get; } - - List Branches { get; } - - byte[] WithFirst(byte[] first); - } -} diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs b/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs deleted file mode 100644 index b7824c61e..000000000 --- a/src/CoiniumServ/Crypto/Merkle/MerkleRoot.cs +++ /dev/null @@ -1,130 +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; -using System.Collections.Generic; -using CoiniumServ.Utils.Extensions; - -namespace CoiniumServ.Crypto.Merkle -{ - /// - /// Merkle tree builder. - /// - /// - /// To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s - /// - /// https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees - /// - /// Python implementation: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-2-for-python - /// Original implementation: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Block.cs#330 - /// - public class MerkleRoot:IMerkleRoot - { - /// - /// Leaves of the merkle tree. - /// - public IList Tree { get; private set; } - - /// - /// The root of the merkle tree. - /// - public Hash Root { get; private set; } - - /// - /// Creates a new merkle-tree instance. - /// - /// - public MerkleRoot(List hashList) - { - Tree = Build(hashList); - Root = Tree.Count > 0 ? new Hash(Tree[Tree.Count - 1]) : Hash.ZeroHash; - } - - /// - /// Builds merkle tree. - /// - /// - /// - private IList Build(List hashList) - { - // The Merkle root is based on a tree of hashes calculated from the transactions: - // - // root - // /\ - // / \ - // A B - // / \ / \ - // t1 t2 t3 t4 - // - // The tree is represented as a list: t1,t2,t3,t4,A,B,root where each entry is a hash. - // - // The hashing algorithm is double SHA-256. The leaves are a hash of the serialized contents of the - // transaction. The interior nodes are hashes of the concentration of the two child hashes. - // - // This structure allows the creation of proof that a transaction was included into a block without having to - // provide the full block contents. Instead, you can provide only a Merkle branch. For example to prove tx2 was - // in a block you can just provide tx2, the hash(tx1) and B. Now the other party has everything they need to - // derive the root, which can be checked against the block header. These proofs aren't used right now but - // will be helpful later when we want to download partial block contents. - // - // Note that if the number of transactions is not even the last tx is repeated to make it so (see - // tx3 above). A tree with 5 transactions would look like this: - // - // root - // / \ - // 1 \ - // / \ \ - // 2 3 4 - // / \ / \ / \ - // t1 t2 t3 t4 t5 t5 - - var tree = new List(); - - // Start by adding all the hashes of the transactions as leaves of the tree. - foreach (var item in hashList) - { - tree.Add(item); - } - - var levelOffset = 0; // Offset in the list where the currently processed level starts. - - // Step through each level, stopping when we reach the root (levelSize == 1). - for (var levelSize = hashList.Count; levelSize > 1; levelSize = (levelSize + 1) / 2) - { - // For each pair of nodes on that level: - for (var left = 0; left < levelSize; left += 2) - { - // The right hand node can be the same as the left hand, in the case where we don't have enough transactions. - var right = Math.Min(left + 1, levelSize - 1); - var leftBytes = tree[levelOffset + left].ReverseBytes(); - var rightBytes = tree[levelOffset + right].ReverseBytes(); - - tree.Add(Utils.DoubleDigestTwoBuffers(leftBytes, 0, 32, rightBytes, 0, 32).ReverseBytes()); - } - // Move to the next level. - levelOffset += levelSize; - } - return tree; - } - } -} diff --git a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs b/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs deleted file mode 100644 index d548f756f..000000000 --- a/src/CoiniumServ/Crypto/Merkle/MerkleTree.cs +++ /dev/null @@ -1,143 +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; -using CoiniumServ.Utils.Extensions; -using CoiniumServ.Utils.Helpers.Misc; - -namespace CoiniumServ.Crypto.Merkle -{ - /// - /// Merkle tree builder. - /// - /// - /// To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s - /// - /// https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees - /// - /// Python implementation: http://runnable.com/U3HnDaMrJFk3gkGW/bitcoin-block-merkle-root-2-for-python - /// Original implementation: https://code.google.com/p/bitcoinsharp/source/browse/src/Core/Block.cs#330 - /// - public class MerkleTree : IMerkleTree - { - /// - /// The steps in tree. - /// - public IList Steps { get; private set; } - - /// - /// List of hashes, will be used for calculation of merkle root. - /// This is not a list of all transactions, it only contains prepared hashes of steps of merkle tree algorithm. Please read some materials (http://en.wikipedia.org/wiki/Hash_tree) for understanding how merkle trees calculation works. (http://mining.bitcoin.cz/stratum-mining) - /// The coinbase transaction is hashed against the merkle branches to build the final merkle root. - /// - public List Branches - { - get - { - return Steps.Select(step => step.ToHexString()).ToList(); - } - } - - /// - /// Creates a new merkle-tree instance. - /// - /// - public MerkleTree(IEnumerable hashList) - { - Steps = CalculateSteps(hashList); - } - - /// - /// - /// - /// - /// python: http://runnable.com/U3jqtyYUmAUxtsSS/bitcoin-block-merkle-root-python - /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/merkleTree.js#L9 - /// - /// - /// - private IList CalculateSteps(IEnumerable hashList) - { - var steps = new List(); - - var L = new List {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(); - - foreach (int i in Range.From(startL).To(Ll).WithStepSize(2)) - { - Ld.Add(MerkleJoin(L[i], L[i + 1])); - } - - L = new List {null}; - L.AddRange(Ld); - Ll = L.Count; - } - } - return steps; - } - - /// - /// - /// - /// - /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/merkleTree.js#L11 - /// - /// - /// - /// - private byte[] MerkleJoin(byte[] hash1, byte[] hash2) - { - var joined = hash1.Append(hash2); - var dHashed = joined.DoubleDigest(); - return dHashed; - } - - public byte[] WithFirst(byte[] first) - { - foreach (var step in Steps) - { - first = first.Append(step).DoubleDigest(); - } - - return first; - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 5837ef4d2..da6d3ca97 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -243,7 +243,7 @@ private void PrintPoolInfo() var miningInfo = _daemonClient.GetMiningInfo(); // TODO: add downloading blocks information from getblocktemplate(). - // TODO: make this multi-line & readable. + // TODO: somecoins like namecoin do not have the method getmininginfo(), so divide this information and handle exceptions. // TODO: read services from config so that we can print pool info even before starting the servers. _logger.Information("Coin symbol: {0:l} algorithm: {1:l} " + "Coin version: {2} protocol: {3} wallet: {4} " + diff --git a/src/CoiniumServ/config/coins/namecoin.json b/src/CoiniumServ/config/coins/namecoin.json new file mode 100644 index 000000000..372d21688 --- /dev/null +++ b/src/CoiniumServ/config/coins/namecoin.json @@ -0,0 +1,5 @@ +{ + "name": "Namecoin", + "symbol": "NMC", + "algorithm": "sha256" +} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index 7a962a950..e9c3b0717 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -23,7 +23,7 @@ # payment processing configuration "payments": { - "enabled": false, + "enabled": true, "interval": 60, "minimum": 1 }, From caec10e77409cf2eb6e2b68b4e0015f52a870424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 19 Jul 2014 21:45:36 +0300 Subject: [PATCH 103/230] DaemonClient is now instantiated using ObjectFactory. Improved PlatformManager.cs - it'll now also flag .net 4.5. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- src/CoiniumServ/Daemon/Config/DaemonConfig.cs | 5 --- .../Daemon/Config/IDaemonConfig.cs | 2 -- src/CoiniumServ/Daemon/DaemonBase.cs | 15 ++++---- src/CoiniumServ/Daemon/DaemonClient.cs | 11 ++++-- src/CoiniumServ/Daemon/IDaemonBase.cs | 12 ------- src/CoiniumServ/Daemon/IDaemonClient.cs | 2 -- src/CoiniumServ/Factories/IObjectFactory.cs | 11 ++++++ src/CoiniumServ/Factories/ObjectFactory.cs | 21 +++++++++++ src/CoiniumServ/Mining/Pools/Pool.cs | 9 ++--- .../Mining/Pools/PoolManagerFactory.cs | 2 +- .../Net/Server/Http/Web/RootPathProvider.cs | 2 +- src/CoiniumServ/Program.cs | 2 +- .../Repository/Registries/ClassRegistry.cs | 2 +- .../Platform/{Framework.cs => Frameworks.cs} | 8 ++++- .../Utils/Platform/PlatformManager.cs | 36 +++++++++++-------- src/Tests/Mining/Pools/PoolTests.cs | 16 ++++----- 17 files changed, 92 insertions(+), 66 deletions(-) rename src/CoiniumServ/Utils/Platform/{Framework.cs => Frameworks.cs} (91%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 11c00bfcb..36f79128e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -263,7 +263,7 @@ - + diff --git a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs index 5c330b2f0..3d1fee000 100644 --- a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs @@ -34,11 +34,6 @@ public class DaemonConfig:IDaemonConfig public string Password { get; private set; } - public string Url - { - get { return string.Format("http://{0}:{1}", Host, Port); } - } - public DaemonConfig(dynamic config) { if (config == null) diff --git a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs index f3a6e3a07..7cf6c751e 100644 --- a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs @@ -35,7 +35,5 @@ public interface IDaemonConfig:IConfig string Username { get; } string Password { get; } - - string Url { get; } } } diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 283189edd..2b9941de9 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -28,7 +28,6 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Exceptions; -using CoiniumServ.Mining.Pools; using CoiniumServ.Utils; using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; @@ -43,17 +42,17 @@ public class DaemonBase : IDaemonBase public string RpcPassword { get; private set; } public Int32 RequestCounter { get; private set; } - private ILogger _logger; + private readonly ILogger _logger; - public virtual void Initialize(IDaemonConfig daemonConfig, ICoinConfig coinConfig) + public DaemonBase(IDaemonConfig daemonConfig, ICoinConfig coinConfig) { - _logger = Logging.PacketLogger.ForContext().ForContext("Component", coinConfig.Name); + _logger = Logging.PacketLogger.ForContext().ForContext("Component", coinConfig.Name); - var url = string.Format("{0}", daemonConfig.Url); - RpcUrl = url; + RpcUrl = string.Format("http://{0}:{1}", daemonConfig.Host, daemonConfig.Port); RpcUser = daemonConfig.Username; RpcPassword = daemonConfig.Password; - RequestCounter = 0; + + RequestCounter = 0; } /// @@ -66,7 +65,7 @@ public virtual void Initialize(IDaemonConfig daemonConfig, ICoinConfig coinConfi /// Method to invoke. /// Parameters to pass to the method. /// The JSON RPC response deserialized as the given type. - public T MakeRequest(string method, params object[] parameters) + protected T MakeRequest(string method, params object[] parameters) { var rpcResponse = MakeRpcRequest(new DaemonRequest(RequestCounter++, method, parameters)); return rpcResponse.Result; diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index b1f50d6ad..d707d41ad 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -24,6 +24,11 @@ using System; using System.Collections.Generic; using System.Linq; +using CoiniumServ.Coin.Config; +using CoiniumServ.Daemon.Config; +using CoiniumServ.Daemon.Requests; +using CoiniumServ.Daemon.Responses; + /* This file is based on https://github.com/BitKoot/BitcoinRpcSharp */ /* Possible alternative implementations: @@ -35,8 +40,6 @@ // Original bitcoin api call list: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list // Rpc error codes: https://github.com/bitcoin/bitcoin/blob/master/src/rpcprotocol.h#L34 -using CoiniumServ.Daemon.Requests; -using CoiniumServ.Daemon.Responses; namespace CoiniumServ.Daemon { @@ -47,6 +50,10 @@ public class DaemonClient : DaemonBase, IDaemonClient { public static readonly object[] EmptyString = {}; // used as empty parameter. + public DaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig) + :base(daemonConfig, coinConfig) + { } + /// /// Version 0.8: Attempts add or remove node from the addnode list or try a connection to node once. /// diff --git a/src/CoiniumServ/Daemon/IDaemonBase.cs b/src/CoiniumServ/Daemon/IDaemonBase.cs index 6bea103bc..8e93d37a7 100644 --- a/src/CoiniumServ/Daemon/IDaemonBase.cs +++ b/src/CoiniumServ/Daemon/IDaemonBase.cs @@ -22,23 +22,11 @@ #endregion using System; -using CoiniumServ.Coin.Config; -using CoiniumServ.Daemon.Config; namespace CoiniumServ.Daemon { public interface IDaemonBase { - string RpcUrl { get; } - - string RpcUser { get;} - string RpcPassword { get;} - Int32 RequestCounter { get; } - - T MakeRequest(string method, params object[] parameters); - string MakeRawRequest(string method, params object[] parameters); - - void Initialize(IDaemonConfig daemonConfig, ICoinConfig coinConfig); } } diff --git a/src/CoiniumServ/Daemon/IDaemonClient.cs b/src/CoiniumServ/Daemon/IDaemonClient.cs index 49b6d2b7e..787ae853a 100644 --- a/src/CoiniumServ/Daemon/IDaemonClient.cs +++ b/src/CoiniumServ/Daemon/IDaemonClient.cs @@ -59,7 +59,5 @@ public interface IDaemonClient string GetAccount(string bitcoinAddress); string SendMany(string fromAccount, Dictionary toBitcoinAddress, int minConf = 1, string comment = ""); - - void Initialize(IDaemonConfig daemonConfig, ICoinConfig coinConfig); } } diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index 89afe98ff..2b866fcdd 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -21,7 +21,10 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Config; namespace CoiniumServ.Factories { @@ -36,5 +39,13 @@ public interface IObjectFactory /// /// IHashAlgorithm GetHashAlgorithm(string algorithm); + + /// + /// Returns a new instance of daemon client. + /// + /// + /// + /// + IDaemonClient GetDaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig); } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index ac6678340..4a5ab24be 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -21,8 +21,12 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; +using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Config; using CoiniumServ.Repository.Context; +using Nancy.TinyIoc; namespace CoiniumServ.Factories { @@ -54,5 +58,22 @@ public IHashAlgorithm GetHashAlgorithm(string algorithm) { return _applicationContext.Container.Resolve(algorithm); } + + /// + /// Returns a new instance of daemon client. + /// + /// + /// + /// + public IDaemonClient GetDaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig) + { + var @params = new NamedParameterOverloads + { + {"daemonConfig", daemonConfig}, + {"coinConfig", coinConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index da6d3ca97..bb285b708 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -69,7 +69,7 @@ public class Pool : IPool private readonly IVardiffManagerFactory _vardiffManagerFactory; private readonly IBanManagerFactory _banningManagerFactory; - private readonly IDaemonClient _daemonClient; + private IDaemonClient _daemonClient; private readonly IServerFactory _serverFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; @@ -93,7 +93,7 @@ public class Pool : IPool /// /// Initializes a new instance of the class. /// - /// The hash algorithm factory. + /// /// The server factory. /// The service factory. /// The client. @@ -110,7 +110,6 @@ public Pool( IObjectFactory objectFactory, IServerFactory serverFactory, IServiceFactory serviceFactory, - IDaemonClient client, IMinerManagerFactory minerManagerFactory, IJobTrackerFactory jobTrackerFactory, IJobManagerFactory jobManagerFactory, @@ -126,7 +125,6 @@ public Pool( Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); Enforce.ArgumentNotNull(serviceFactory, "IServiceFactory"); - Enforce.ArgumentNotNull(client, "IDaemonClient"); Enforce.ArgumentNotNull(minerManagerFactory, "IMinerManagerFactory"); Enforce.ArgumentNotNull(jobTrackerFactory, "IJobTrackerFactory"); Enforce.ArgumentNotNull(jobManagerFactory, "IJobManagerFactory"); @@ -138,7 +136,6 @@ public Pool( _objectFactory = objectFactory; - _daemonClient = client; _minerManagerFactory = minerManagerFactory; _jobManagerFactory = jobManagerFactory; _jobTrackerFactory = jobTrackerFactory; @@ -177,7 +174,7 @@ private void InitDaemon() if (Config.Daemon == null || Config.Daemon.Valid == false) _logger.Error("Coin daemon configuration is not valid!"); - _daemonClient.Initialize(Config.Daemon, Config.Coin); + _daemonClient = _objectFactory.GetDaemonClient(Config.Daemon, Config.Coin); } private void InitManagers() diff --git a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs index 54d8abfba..9d93efd2c 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs @@ -41,7 +41,7 @@ public PoolManagerFactory(IApplicationContext applicationContext) public IPoolManager Get() { - return _poolManager ?? (_poolManager = _applicationContext.Container.Resolve()); + return _applicationContext.Container.Resolve(); } } } diff --git a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs index 57326fdbc..e9627972f 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/RootPathProvider.cs @@ -32,7 +32,7 @@ public class CustomRootPathProvider : IRootPathProvider { public string GetRootPath() { - return string.Format(PlatformManager.IsRunningOnMono() ? "{0}/web/default" : "{0}\\web\\default", + return string.Format(PlatformManager.Framework == Frameworks.Mono ? "{0}/web/default" : "{0}\\web\\default", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); } } diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 811020634..ab4f24d8a 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -81,7 +81,7 @@ static void Main(string[] args) // print a version banner. _logger = Log.ForContext(); _logger.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); - _logger.Information("Running over {0:l} {1:l}.", PlatformManager.Framework.ToString(), PlatformManager.FrameworkVersion); + PlatformManager.PrintPlatformBanner(); // start pool manager. var poolManager = kernel.Resolve().Get(); diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 47f1e418c..abe1e6ec7 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -56,7 +56,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Utils/Platform/Framework.cs b/src/CoiniumServ/Utils/Platform/Frameworks.cs similarity index 91% rename from src/CoiniumServ/Utils/Platform/Framework.cs rename to src/CoiniumServ/Utils/Platform/Frameworks.cs index 1d7ab1fa3..6a9a74f79 100644 --- a/src/CoiniumServ/Utils/Platform/Framework.cs +++ b/src/CoiniumServ/Utils/Platform/Frameworks.cs @@ -25,9 +25,15 @@ namespace CoiniumServ.Utils.Platform /// /// .Net frameworks. /// - public enum NetFrameworks + public enum Frameworks { DotNet, Mono } + + public enum DotNetVersion + { + DotNet4, + DotNet45 + } } diff --git a/src/CoiniumServ/Utils/Platform/PlatformManager.cs b/src/CoiniumServ/Utils/Platform/PlatformManager.cs index 584dd2975..85a851b95 100644 --- a/src/CoiniumServ/Utils/Platform/PlatformManager.cs +++ b/src/CoiniumServ/Utils/Platform/PlatformManager.cs @@ -22,6 +22,7 @@ #endregion using System; +using Serilog; namespace CoiniumServ.Utils.Platform { @@ -31,37 +32,44 @@ namespace CoiniumServ.Utils.Platform public class PlatformManager { /// - /// Current .Net framework. + /// Current framework we are running on. /// - public static NetFrameworks Framework { get; private set; } + public static Frameworks Framework { get; private set; } /// - /// Current .Net framework's version. + /// Is the framework .Net 4.5? + /// + public static bool IsDotNet45 { get; private set; } + + /// + /// Current framework's version. /// public static Version FrameworkVersion { get; private set; } + private static readonly ILogger Logger; + static PlatformManager() { + Logger = Log.ForContext(); + IdentifyPlatform(); } + public static void PrintPlatformBanner() + { + Logger.Information("Running over {0:l} {1:l} ({2:l}).", Framework == Frameworks.DotNet ? ".Net" : "Mono", + IsDotNet45 ? "4.5" : "4", + FrameworkVersion); + } + /// /// Identifies the current platform and used frameworks. /// private static void IdentifyPlatform() { - // find dot.net framework. - Framework = IsRunningOnMono() ? NetFrameworks.Mono : NetFrameworks.DotNet; + Framework = Type.GetType("Mono.Runtime") != null ? Frameworks.Mono : Frameworks.DotNet; + IsDotNet45 = Type.GetType("System.Reflection.ReflectionContext", false) != null; /* ReflectionContext exists from .NET 4.5 onwards. */ FrameworkVersion = Environment.Version; } - - /// - /// Returns true if code runs over Mono framework. - /// - /// true if running over Mono, false otherwise. - public static bool IsRunningOnMono() - { - return Type.GetType("Mono.Runtime") != null; - } } } diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index f9529410c..061c8663b 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -111,6 +111,11 @@ public PoolTests() // pool-config mockup. _config = Substitute.For(); _config.Daemon.Valid.Returns(true); + + // init daemon client + _daemonClient = _objectFactory.GetDaemonClient(_config.Daemon, _config.Coin); + _daemonClient.GetInfo().Returns(new Info()); + _daemonClient.GetMiningInfo().Returns(new MiningInfo()); } /// @@ -122,8 +127,7 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() var pool = new Pool( _objectFactory, _serverFactory, - _serviceFactory, - _daemonClient, + _serviceFactory, _minerManagerFactory, _jobTrackerFactory, _jobManagerFactory, @@ -147,7 +151,6 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _objectFactory, _serverFactory, _serviceFactory, - _daemonClient, _minerManagerFactory, _jobTrackerFactory, _jobManagerFactory, @@ -194,12 +197,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig, rewardsConfig, _config.Coin).Returns(_jobManager); - _jobManager.Initialize(pool.InstanceId); - - // init daemon client - _daemonClient.Initialize(_config.Daemon, _config.Coin); - _daemonClient.GetInfo().Returns(new Info()); - _daemonClient.GetMiningInfo().Returns(new MiningInfo()); + _jobManager.Initialize(pool.InstanceId); // init server _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager, _banManager, _config.Coin).Returns(_miningServer); From 0f660eccb942c0d9ac4f7c548a7249789f264252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sun, 20 Jul 2014 21:35:31 +0300 Subject: [PATCH 104/230] Removed BanManagerFactory,jobmaBanManagerFactory, MinerManagerFactory,sharemanaShareManagerFactory, JobTrackerFactory, PoolFactory, PoolManagerFactory - they're now instead handled by ObjectFactory.cs. --- src/CoiniumServ/CoiniumServ.csproj | 14 --- src/CoiniumServ/Daemon/DaemonBase.cs | 5 +- src/CoiniumServ/Daemon/DaemonClient.cs | 4 +- src/CoiniumServ/Factories/IObjectFactory.cs | 36 +++++- src/CoiniumServ/Factories/ObjectFactory.cs | 104 +++++++++++++++++- src/CoiniumServ/Mining/Banning/BanManager.cs | 10 +- .../Mining/Banning/BanManagerFactory.cs | 60 ---------- .../Mining/Banning/IBanManagerFactory.cs | 34 ------ src/CoiniumServ/Mining/Jobs/ExtraNonce.cs | 2 + src/CoiniumServ/Mining/Jobs/JobCounter.cs | 2 + .../Mining/Jobs/Manager/IJobManagerFactory.cs | 52 --------- .../Mining/Jobs/Manager/JobManager.cs | 7 +- .../Mining/Jobs/Manager/JobManagerFactory.cs | 80 -------------- .../Mining/Jobs/Tracker/IJobTrackerFactory.cs | 30 ----- .../Mining/Jobs/Tracker/JobTrackerFactory.cs | 49 --------- .../Mining/Miners/IMinerManagerFactory.cs | 39 ------- src/CoiniumServ/Mining/Miners/MinerManager.cs | 4 +- .../Mining/Miners/MinerManagerFactory.cs | 58 ---------- src/CoiniumServ/Mining/Pools/IPool.cs | 6 - src/CoiniumServ/Mining/Pools/IPoolFactory.cs | 37 ------- .../Mining/Pools/IPoolManagerFactory.cs | 29 ----- src/CoiniumServ/Mining/Pools/Pool.cs | 62 +++-------- src/CoiniumServ/Mining/Pools/PoolFactory.cs | 58 ---------- src/CoiniumServ/Mining/Pools/PoolManager.cs | 9 +- .../Mining/Pools/PoolManagerFactory.cs | 47 -------- .../Mining/Shares/IShareManagerFactory.cs | 42 ------- src/CoiniumServ/Mining/Shares/ShareManager.cs | 6 +- .../Mining/Shares/ShareManagerFactory.cs | 69 ------------ src/CoiniumServ/Program.cs | 3 +- .../Repository/Registries/FactoryRegistry.cs | 7 -- src/Tests/Mining/Pools/PoolTests.cs | 44 +++----- 31 files changed, 192 insertions(+), 817 deletions(-) delete mode 100644 src/CoiniumServ/Mining/Banning/BanManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/IPoolFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/PoolFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 36f79128e..4418c5df3 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -127,9 +127,7 @@ - - @@ -151,15 +149,11 @@ - - - - @@ -222,8 +216,6 @@ - - @@ -300,9 +292,7 @@ - - @@ -311,13 +301,9 @@ - - - - diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 2b9941de9..9b2c44b6e 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -25,7 +25,6 @@ using System.IO; using System.Net; using System.Text; -using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Utils; @@ -44,9 +43,9 @@ public class DaemonBase : IDaemonBase private readonly ILogger _logger; - public DaemonBase(IDaemonConfig daemonConfig, ICoinConfig coinConfig) + public DaemonBase(string pool, IDaemonConfig daemonConfig) { - _logger = Logging.PacketLogger.ForContext().ForContext("Component", coinConfig.Name); + _logger = Logging.PacketLogger.ForContext().ForContext("Component", pool); RpcUrl = string.Format("http://{0}:{1}", daemonConfig.Host, daemonConfig.Port); RpcUser = daemonConfig.Username; diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index d707d41ad..c50288d1e 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -50,8 +50,8 @@ public class DaemonClient : DaemonBase, IDaemonClient { public static readonly object[] EmptyString = {}; // used as empty parameter. - public DaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig) - :base(daemonConfig, coinConfig) + public DaemonClient(string pool, IDaemonConfig daemonConfig) + :base(pool, daemonConfig) { } /// diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index 2b866fcdd..d14000389 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -25,6 +25,14 @@ using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Config; +using CoiniumServ.Mining.Banning; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Persistance; namespace CoiniumServ.Factories { @@ -33,6 +41,8 @@ namespace CoiniumServ.Factories /// public interface IObjectFactory { + #region hash algorithms + /// /// Returns instance of the given hash algorithm /// @@ -40,12 +50,34 @@ public interface IObjectFactory /// IHashAlgorithm GetHashAlgorithm(string algorithm); + #endregion + + #region pool objects + + IPoolManager GetPoolManager(); + + IPool GetPool(IPoolConfig poolConfig); + /// /// Returns a new instance of daemon client. /// + /// /// - /// /// - IDaemonClient GetDaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig); + IDaemonClient GetDaemonClient(string pool, IDaemonConfig daemonConfig); + + IMinerManager GetMiningManager(string pool, IDaemonClient daemonClient); + + IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, + IRewardsConfig rewardsConfig); + + IJobTracker GetJobTracker(); + + IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage); + + IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig); + + #endregion } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index 4a5ab24be..bb51af84a 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -21,10 +21,17 @@ // #endregion -using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Config; +using CoiniumServ.Mining.Banning; +using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Mining.Miners; +using CoiniumServ.Mining.Pools; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Shares; +using CoiniumServ.Persistance; using CoiniumServ.Repository.Context; using Nancy.TinyIoc; @@ -35,6 +42,8 @@ namespace CoiniumServ.Factories /// public class ObjectFactory:IObjectFactory { + #region context + /// /// The application context for internal use. /// @@ -49,6 +58,10 @@ public ObjectFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; } + #endregion + + #region hash algorithms + /// /// Returns instance of the given hash algorithm. /// @@ -59,21 +72,102 @@ public IHashAlgorithm GetHashAlgorithm(string algorithm) return _applicationContext.Container.Resolve(algorithm); } + public IPoolManager GetPoolManager() + { + return _applicationContext.Container.Resolve(); + } + + public IPool GetPool(IPoolConfig poolConfig) + { + var @params = new NamedParameterOverloads + { + {"poolConfig", poolConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + #endregion + + #region pool objects + /// /// Returns a new instance of daemon client. /// + /// /// - /// /// - public IDaemonClient GetDaemonClient(IDaemonConfig daemonConfig, ICoinConfig coinConfig) + public IDaemonClient GetDaemonClient(string pool, IDaemonConfig daemonConfig) { var @params = new NamedParameterOverloads { - {"daemonConfig", daemonConfig}, - {"coinConfig", coinConfig}, + {"pool", pool}, + {"daemonConfig", daemonConfig}, }; return _applicationContext.Container.Resolve(@params); } + + public IMinerManager GetMiningManager(string pool, IDaemonClient daemonClient) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"daemonClient", daemonClient}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + public IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"daemonClient", daemonClient}, + {"jobTracker", jobTracker}, + {"shareManager", shareManager}, + {"minerManager", minerManager}, + {"hashAlgorithm", hashAlgorithm}, + {"walletConfig", walletConfig}, + {"rewardsConfig", rewardsConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + public IJobTracker GetJobTracker() + { + return _applicationContext.Container.Resolve(); + } + + public IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"daemonClient", daemonClient}, + {"jobTracker", jobTracker}, + {"storage", storage}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + + public IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"shareManager", shareManager}, + {"banConfig", banConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + #endregion } } diff --git a/src/CoiniumServ/Mining/Banning/BanManager.cs b/src/CoiniumServ/Mining/Banning/BanManager.cs index 0a59e6398..63da0cba3 100644 --- a/src/CoiniumServ/Mining/Banning/BanManager.cs +++ b/src/CoiniumServ/Mining/Banning/BanManager.cs @@ -47,19 +47,19 @@ public class BanManager:IBanManager private readonly ILogger _logger; - public BanManager(IShareManager shareManager, IBanConfig banConfig, ICoinConfig coinConfig) - { - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); - + public BanManager(string pool, IShareManager shareManager, IBanConfig banConfig) + { Config = banConfig; if (!Config.Enabled) return; + _logger = Log.ForContext().ForContext("Component", pool); _bannedIps = new Dictionary(); + _timer = new Timer(CheckBans, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + shareManager.ShareSubmitted += OnShare; - _timer = new Timer(CheckBans, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. CheckBans(null); } diff --git a/src/CoiniumServ/Mining/Banning/BanManagerFactory.cs b/src/CoiniumServ/Mining/Banning/BanManagerFactory.cs deleted file mode 100644 index f93ac5338..000000000 --- a/src/CoiniumServ/Mining/Banning/BanManagerFactory.cs +++ /dev/null @@ -1,60 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Banning -{ - public class BanManagerFactory : IBanManagerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public BanManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IBanManager Get(IShareManager shareManager, IBanConfig banConfig, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"shareManager", shareManager}, - {"banConfig", banConfig}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs b/src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs deleted file mode 100644 index b674703aa..000000000 --- a/src/CoiniumServ/Mining/Banning/IBanManagerFactory.cs +++ /dev/null @@ -1,34 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; - -namespace CoiniumServ.Mining.Banning -{ - public interface IBanManagerFactory - { - IBanManager Get(IShareManager shareManager, IBanConfig banConfig, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs index c80b4a77a..a5a0745f6 100644 --- a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs +++ b/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs @@ -32,6 +32,8 @@ namespace CoiniumServ.Mining.Jobs /// public class ExtraNonce:IExtraNonce { + // TODO: use ioc for extranonce too + private UInt32 _counter; /// diff --git a/src/CoiniumServ/Mining/Jobs/JobCounter.cs b/src/CoiniumServ/Mining/Jobs/JobCounter.cs index f108f0625..cd82f884c 100644 --- a/src/CoiniumServ/Mining/Jobs/JobCounter.cs +++ b/src/CoiniumServ/Mining/Jobs/JobCounter.cs @@ -30,6 +30,8 @@ namespace CoiniumServ.Mining.Jobs /// public class JobCounter : IJobCounter { + // use ioc for job-counter too + private UInt64 Current { get; set; } public JobCounter() diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs deleted file mode 100644 index 892e5d5a5..000000000 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManagerFactory.cs +++ /dev/null @@ -1,52 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Cryptology.Algorithms; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; - -namespace CoiniumServ.Mining.Jobs.Manager -{ - public interface IJobManagerFactory - { - /// - /// Gets the specified daemon client. - /// - /// The daemon client. - /// - /// - /// The miner manager. - /// - /// - /// - /// - /// - IJobManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, - IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, - IRewardsConfig rewardsConfig, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 71b1b2725..6b2c1787f 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -67,7 +67,9 @@ public class JobManager : IJobManager private Timer _timer; private const int TimerExpiration = 60; - public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig, ICoinConfig coinConfig) + public JobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, + IRewardsConfig rewardsConfig) { _daemonClient = daemonClient; _jobTracker = jobTracker; @@ -77,7 +79,8 @@ public JobManager(IDaemonClient daemonClient, IJobTracker jobTracker, IShareMana _walletConfig = walletConfig; _rewardsConfig = rewardsConfig; _jobCounter = new JobCounter(); // todo make this ioc based too. - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + + _logger = Log.ForContext().ForContext("Component", pool); } public void Initialize(UInt32 instanceId) diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs deleted file mode 100644 index 71d0d728c..000000000 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManagerFactory.cs +++ /dev/null @@ -1,80 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Cryptology.Algorithms; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Jobs.Manager -{ - public class JobManagerFactory : IJobManagerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public JobManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Gets the specified daemon client. - /// - /// The daemon client. - /// - /// - /// The miner manager. - /// - /// - /// - /// - public IJobManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"jobTracker", jobTracker}, - {"shareManager", shareManager}, - {"minerManager", minerManager}, - {"hashAlgorithm", hashAlgorithm}, - {"walletConfig", walletConfig}, - {"rewardsConfig", rewardsConfig}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs deleted file mode 100644 index 0b9bac211..000000000 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTrackerFactory.cs +++ /dev/null @@ -1,30 +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.Mining.Jobs.Tracker -{ - public interface IJobTrackerFactory - { - IJobTracker Get(); - } -} diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs b/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs deleted file mode 100644 index 0ac401a9f..000000000 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTrackerFactory.cs +++ /dev/null @@ -1,49 +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 CoiniumServ.Repository.Context; - -namespace CoiniumServ.Mining.Jobs.Tracker -{ - public class JobTrackerFactory:IJobTrackerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public JobTrackerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IJobTracker Get() - { - return _applicationContext.Container.Resolve(); - } - } -} diff --git a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs deleted file mode 100644 index 8be418363..000000000 --- a/src/CoiniumServ/Mining/Miners/IMinerManagerFactory.cs +++ /dev/null @@ -1,39 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; - -namespace CoiniumServ.Mining.Miners -{ - public interface IMinerManagerFactory - { - /// - /// Gets the specified daemon client. - /// - /// The daemon client. - /// - /// - IMinerManager Get(IDaemonClient daemonClient, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Mining/Miners/MinerManager.cs index cb41a4cae..1a440b0c8 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Mining/Miners/MinerManager.cs @@ -47,11 +47,11 @@ public class MinerManager : IMinerManager private readonly ILogger _logger; - public MinerManager(IDaemonClient daemonClient, ICoinConfig coinConfig) + public MinerManager(string pool, IDaemonClient daemonClient) { _daemonClient = daemonClient; _miners = new Dictionary(); - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", pool); } public IMiner GetMiner(Int32 id) diff --git a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs b/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs deleted file mode 100644 index 75d0a2a0b..000000000 --- a/src/CoiniumServ/Mining/Miners/MinerManagerFactory.cs +++ /dev/null @@ -1,58 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Miners -{ - public class MinerManagerFactory : IMinerManagerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public MinerManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IMinerManager Get(IDaemonClient daemonClient, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"coinConfig",coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Mining/Pools/IPool.cs index 3c39d1dd7..312b6764a 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Mining/Pools/IPool.cs @@ -32,12 +32,6 @@ public interface IPool IPerPool Statistics { get; } - /// - /// Initializes the specified bind ip. - /// - /// The configuration. - void Initialize(IPoolConfig config); - void Start(); void Stop(); diff --git a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolFactory.cs deleted file mode 100644 index df21f089f..000000000 --- a/src/CoiniumServ/Mining/Pools/IPoolFactory.cs +++ /dev/null @@ -1,37 +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 CoiniumServ.Mining.Pools.Config; - -namespace CoiniumServ.Mining.Pools -{ - public interface IPoolFactory - { - /// - /// Creates the specified bind ip. - /// - /// The pool configuration. - /// - IPool Create(IPoolConfig poolConfig); - } -} diff --git a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.cs deleted file mode 100644 index 7fe05a678..000000000 --- a/src/CoiniumServ/Mining/Pools/IPoolManagerFactory.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.Mining.Pools -{ - public interface IPoolManagerFactory - { - IPoolManager Get(); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index bb285b708..0481ac938 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -59,15 +59,10 @@ public class Pool : IPool private readonly IObjectFactory _objectFactory; private readonly IServiceFactory _serviceFactory; - private readonly IJobTrackerFactory _jobTrackerFactory; - private readonly IJobManagerFactory _jobManagerFactory; - private readonly IShareManagerFactory _shareManagerFactory; - private readonly IMinerManagerFactory _minerManagerFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; - private readonly IBanManagerFactory _banningManagerFactory; private IDaemonClient _daemonClient; private readonly IServerFactory _serverFactory; @@ -93,77 +88,50 @@ public class Pool : IPool /// /// Initializes a new instance of the class. /// + /// /// /// The server factory. /// The service factory. - /// The client. - /// The miner manager factory. - /// - /// The job manager factory. - /// The share manager factory. /// /// /// /// - /// public Pool( + IPoolConfig poolConfig, IObjectFactory objectFactory, IServerFactory serverFactory, IServiceFactory serviceFactory, - IMinerManagerFactory minerManagerFactory, - IJobTrackerFactory jobTrackerFactory, - IJobManagerFactory jobManagerFactory, - IShareManagerFactory shareManagerFactory, IStorageFactory storageFactory, IPaymentProcessorFactory paymentProcessorFactory, IStatisticsObjectFactory statisticsObjectFactory, - IVardiffManagerFactory vardiffManagerFactory, - IBanManagerFactory banningManagerFactory) + IVardiffManagerFactory vardiffManagerFactory) { Enforce.ArgumentNotNull(objectFactory, "IObjectFactory"); Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); Enforce.ArgumentNotNull(serviceFactory, "IServiceFactory"); - Enforce.ArgumentNotNull(minerManagerFactory, "IMinerManagerFactory"); - Enforce.ArgumentNotNull(jobTrackerFactory, "IJobTrackerFactory"); - Enforce.ArgumentNotNull(jobManagerFactory, "IJobManagerFactory"); - Enforce.ArgumentNotNull(shareManagerFactory, "IShareManagerFactory"); Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); Enforce.ArgumentNotNull(vardiffManagerFactory, "IVardiffManagerFactory"); - Enforce.ArgumentNotNull(banningManagerFactory, "IBanningManagerFactory"); _objectFactory = objectFactory; - _minerManagerFactory = minerManagerFactory; - _jobManagerFactory = jobManagerFactory; - _jobTrackerFactory = jobTrackerFactory; - _shareManagerFactory = shareManagerFactory; _serverFactory = serverFactory; _serviceFactory = serviceFactory; _storageFactory = storageFactory; _paymentProcessorFactory = paymentProcessorFactory; _statisticsObjectFactory = statisticsObjectFactory; _vardiffManagerFactory = vardiffManagerFactory; - _banningManagerFactory = banningManagerFactory; - } - /// - /// Initializes the specified bind ip. - /// - /// The configuration. - /// config;config.Daemon can not be null! - public void Initialize(IPoolConfig config) - { - Config = config; - _logger = Log.ForContext().ForContext("Component", Config.Coin.Name); - // TODO: validate pool central wallet & rewards within the startup. - GenerateInstanceId(); + Config = poolConfig; + + _logger = Log.ForContext().ForContext("Component", Config.Coin.Name); - InitDaemon(); + GenerateInstanceId(); + InitDaemon(); InitManagers(); InitServers(); PrintPoolInfo(); @@ -174,7 +142,7 @@ private void InitDaemon() if (Config.Daemon == null || Config.Daemon.Valid == false) _logger.Error("Coin daemon configuration is not valid!"); - _daemonClient = _objectFactory.GetDaemonClient(Config.Daemon, Config.Coin); + _daemonClient = _objectFactory.GetDaemonClient(Config.Coin.Name, Config.Daemon); } private void InitManagers() @@ -187,18 +155,18 @@ private void InitManagers() _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage, Config.Wallet, Config.Coin); _paymentProcessor.Initialize(Config.Payments); - _minerManager = _minerManagerFactory.Get(_daemonClient, Config.Coin); + _minerManager = _objectFactory.GetMiningManager(Config.Coin.Name, _daemonClient); - _jobTracker = _jobTrackerFactory.Get(); + _jobTracker = _objectFactory.GetJobTracker(); - _shareManager = _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage, Config.Coin); + _shareManager = _objectFactory.GetShareManager(Config.Coin.Name, _daemonClient, _jobTracker, _storage); _vardiffManager = _vardiffManagerFactory.Get(_shareManager, Config.Stratum.Vardiff, Config.Coin); - _banningManager = _banningManagerFactory.Get( _shareManager,Config.Banning,Config.Coin); + _banningManager = _objectFactory.GetBanManager(Config.Coin.Name, _shareManager, Config.Banning); - _jobManager = _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, - _hashAlgorithm, Config.Wallet, Config.Rewards, Config.Coin); + _jobManager = _objectFactory.GetJobManager(Config.Coin.Name, _daemonClient, _jobTracker, _shareManager, _minerManager, + _hashAlgorithm, Config.Wallet, Config.Rewards); _jobManager.Initialize(InstanceId); diff --git a/src/CoiniumServ/Mining/Pools/PoolFactory.cs b/src/CoiniumServ/Mining/Pools/PoolFactory.cs deleted file mode 100644 index 96583ddb9..000000000 --- a/src/CoiniumServ/Mining/Pools/PoolFactory.cs +++ /dev/null @@ -1,58 +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 CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Repository.Context; - -namespace CoiniumServ.Mining.Pools -{ - public class PoolFactory : IPoolFactory - { - - /// - /// The _application context - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public PoolFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Creates the specified bind ip. - /// - /// The pool configuration. - /// - public IPool Create(IPoolConfig poolConfig) - { - var pool = _applicationContext.Container.Resolve(); - pool.Initialize(poolConfig); - return pool; - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index aea9cb443..2d2938cdf 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -24,6 +24,7 @@ using System; using System.Collections.Generic; using System.Linq; +using CoiniumServ.Factories; using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Utils.Configuration; using CoiniumServ.Utils.Helpers.IO; @@ -35,15 +36,15 @@ public class PoolManager : IPoolManager { private readonly List _pools = new List(); - private readonly IPoolFactory _poolFactory; + private readonly IObjectFactory _objectFactory; private readonly IPoolConfigFactory _poolConfigFactory; private readonly ILogger _logger; - public PoolManager(IPoolFactory poolFactory, IPoolConfigFactory poolConfigFactory) + public PoolManager(IObjectFactory objectFactory, IPoolConfigFactory poolConfigFactory) { - _poolFactory = poolFactory; + _objectFactory = objectFactory; _poolConfigFactory = poolConfigFactory; _logger = Log.ForContext(); } @@ -95,7 +96,7 @@ public IPool GetBySymbol(string symbol) public IPool AddPool(IPoolConfig poolConfig) { - var pool = _poolFactory.Create(poolConfig); + var pool = _objectFactory.GetPool(poolConfig); _pools.Add(pool); return pool; diff --git a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs b/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs deleted file mode 100644 index 9d93efd2c..000000000 --- a/src/CoiniumServ/Mining/Pools/PoolManagerFactory.cs +++ /dev/null @@ -1,47 +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 CoiniumServ.Repository.Context; - -namespace CoiniumServ.Mining.Pools -{ - public class PoolManagerFactory:IPoolManagerFactory - { - /// - /// The _application context - /// - private readonly IApplicationContext _applicationContext; - - private IPoolManager _poolManager; - - public PoolManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IPoolManager Get() - { - return _applicationContext.Container.Resolve(); - } - } -} diff --git a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs deleted file mode 100644 index 4fea00b00..000000000 --- a/src/CoiniumServ/Mining/Shares/IShareManagerFactory.cs +++ /dev/null @@ -1,42 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Persistance; - -namespace CoiniumServ.Mining.Shares -{ - public interface IShareManagerFactory - { - /// - /// Gets the specified daemon client. - /// - /// The daemon client. - /// - /// - /// - IShareManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Mining/Shares/ShareManager.cs index c24f21ec6..f56292815 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Mining/Shares/ShareManager.cs @@ -52,16 +52,16 @@ public class ShareManager : IShareManager /// /// Initializes a new instance of the class. /// + /// /// /// /// - /// - public ShareManager(IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, ICoinConfig coinConfig) + public ShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) { _daemonClient = daemonClient; _jobTracker = jobTracker; _storage = storage; - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", pool); } /// diff --git a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs b/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs deleted file mode 100644 index f32e5e4a9..000000000 --- a/src/CoiniumServ/Mining/Shares/ShareManagerFactory.cs +++ /dev/null @@ -1,69 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Persistance; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Shares -{ - public class ShareManagerFactory : IShareManagerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public ShareManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Gets the specified daemon client. - /// - /// The job manager. - /// - /// - /// - public IShareManager Get(IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"jobTracker", jobTracker}, - {"storage", storage}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index ab4f24d8a..aad75b477 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -25,6 +25,7 @@ using System.Globalization; using System.Reflection; using System.Threading; +using CoiniumServ.Factories; using CoiniumServ.Mining.Pools; using CoiniumServ.Repository; using CoiniumServ.Server.Web; @@ -84,7 +85,7 @@ static void Main(string[] args) PlatformManager.PrintPlatformBanner(); // start pool manager. - var poolManager = kernel.Resolve().Get(); + var poolManager = kernel.Resolve().GetPoolManager(); poolManager.Run(); // start web server. diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 6e841b22b..0c9fcd884 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -54,14 +54,8 @@ public void RegisterInstances() { _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); @@ -69,7 +63,6 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index 061c8663b..fd77ab4b3 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -52,15 +52,10 @@ public class PoolTests private readonly IObjectFactory _objectFactory; private readonly IServerFactory _serverFactory; private readonly IServiceFactory _serviceFactory; - private readonly IJobManagerFactory _jobManagerFactory; - private readonly IJobTrackerFactory _jobTrackerFactory; - private readonly IShareManagerFactory _shareManagerFactory; - private readonly IMinerManagerFactory _minerManagerFactory; private readonly IStorageFactory _storageFactory; private readonly IPaymentProcessorFactory _paymentProcessorFactory; private readonly IStatisticsObjectFactory _statisticsObjectFactory; private readonly IVardiffManagerFactory _vardiffManagerFactory; - private readonly IBanManagerFactory _banManagerFactory; // object mocks. private readonly IDaemonClient _daemonClient; @@ -83,17 +78,13 @@ public class PoolTests public PoolTests() { _objectFactory = Substitute.For(); - _jobManagerFactory = Substitute.For(); - _jobTrackerFactory = Substitute.For(); - _shareManagerFactory = Substitute.For(); - _minerManagerFactory = Substitute.For(); + _serverFactory = Substitute.For(); _serviceFactory = Substitute.For(); _storageFactory = Substitute.For(); _paymentProcessorFactory = Substitute.For(); _statisticsObjectFactory = Substitute.For(); _vardiffManagerFactory = Substitute.For(); - _banManagerFactory = Substitute.For(); _daemonClient = Substitute.For(); _minerManager = Substitute.For(); @@ -113,7 +104,7 @@ public PoolTests() _config.Daemon.Valid.Returns(true); // init daemon client - _daemonClient = _objectFactory.GetDaemonClient(_config.Daemon, _config.Coin); + _daemonClient = _objectFactory.GetDaemonClient(_config.Coin.Name, _config.Daemon); _daemonClient.GetInfo().Returns(new Info()); _daemonClient.GetMiningInfo().Returns(new MiningInfo()); } @@ -125,18 +116,15 @@ public PoolTests() public void ConstructorTest_NonNullParams_ShouldSucceed() { var pool = new Pool( + _config, _objectFactory, _serverFactory, _serviceFactory, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, _storageFactory, _paymentProcessorFactory, _statisticsObjectFactory, - _vardiffManagerFactory, - _banManagerFactory); + _vardiffManagerFactory + ); pool.Should().Not.Be.Null(); } @@ -148,18 +136,15 @@ public void ConstructorTest_NonNullParams_ShouldSucceed() public void InitializationTest_NonNullParams_ShouldSuccess() { var pool = new Pool( + _config, _objectFactory, _serverFactory, _serviceFactory, - _minerManagerFactory, - _jobTrackerFactory, - _jobManagerFactory, - _shareManagerFactory, _storageFactory, _paymentProcessorFactory, _statisticsObjectFactory, - _vardiffManagerFactory, - _banManagerFactory); + _vardiffManagerFactory + ); pool.Should().Not.Be.Null(); @@ -168,7 +153,7 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _objectFactory.GetHashAlgorithm(_config.Coin.Algorithm).Returns(hashAlgorithm); // initialize the miner manager. - _minerManagerFactory.Get(_daemonClient, _config.Coin); + _objectFactory.GetMiningManager(_config.Coin.Name, _daemonClient); var walletConfig = Substitute.For(); var rewardsConfig = Substitute.For(); @@ -180,10 +165,10 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _storageFactory.Get(Storages.Redis, _config); // initialize the job tracker - _jobTrackerFactory.Get(); + _objectFactory.GetJobTracker(); // initialize share manager. - _shareManagerFactory.Get(_daemonClient, _jobTracker, _storage, _config.Coin).Returns(_shareManager); + _objectFactory.GetShareManager(_config.Coin.Name, _daemonClient, _jobTracker, _storage).Returns(_shareManager); // vardiff manager var vardiffConfig = Substitute.For(); @@ -191,11 +176,11 @@ public void InitializationTest_NonNullParams_ShouldSuccess() // banning manager var banConfig = Substitute.For(); - _banManagerFactory.Get(_shareManager, banConfig, _config.Coin); + _objectFactory.GetBanManager(_config.Coin.Name, _shareManager, banConfig); // initalize job manager. - _jobManagerFactory.Get(_daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig, - rewardsConfig, _config.Coin).Returns(_jobManager); + _objectFactory.GetJobManager(_config.Coin.Name, _daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig, + rewardsConfig).Returns(_jobManager); _jobManager.Initialize(pool.InstanceId); @@ -209,7 +194,6 @@ public void InitializationTest_NonNullParams_ShouldSuccess() _miningServer.Initialize(_config.Stratum); // initialize the pool. - pool.Initialize(_config); pool.InstanceId.Should().Be.GreaterThan((UInt32)0); } } From b3b09e39c883a5b2522b0b69fd7736500aea8815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 03:51:46 +0300 Subject: [PATCH 105/230] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a1459f958..2fd631fc2 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ You can send tips and furher support the project or get tips for contributing by [![tip for next commit](http://tip4commit.com/projects/760.svg)](http://tip4commit.com/projects/760) +### Status + +Expect a functioning alpha soon. + ### Features ###### Platform Agnostic @@ -99,7 +103,7 @@ _Under Development_ * ✓ __Hefty1__ ###### Development Model -* Strictly [follows](https://github.com/CoiniumServ/CoiniumServ/tree/develop/src/Tests) the [Test Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) model. We have implemented extensive tests for all important functionality and never merge in code that breaks tests and stuff. Yet again, when a new functionality is introduced we also expect proper tests to be implemented within the PR. In simple words, most probably you won't notice any functionality-breaking changes within the repository. +* Strictly [follows](https://github.com/CoiniumServ/CoiniumServ/tree/develop/src/Tests) the [Test Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) model. We have implemented extensive [tests](https://github.com/CoiniumServ/CoiniumServ/tree/develop/src/Tests) for all important functionality and never merge in code that breaks tests and stuff. Yet again, when a new functionality is introduced we also expect proper tests to be implemented within the PR. In simple words, most probably you won't notice any functionality-breaking changes within the repository. * A strict ruleset for the [Development Model](https://github.com/CoiniumServ/CoiniumServ/wiki/Development-Model). You can follow our bleeding-edge [Develop](https://github.com/CoiniumServ/CoiniumServ) branch or stay with-in the stable [Master](https://github.com/CoiniumServ/CoiniumServ/tree/master) branch. From 2a41a4610c42c8760e69f9696abfee695592a334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 04:22:30 +0300 Subject: [PATCH 106/230] removed unused references from gui project. --- src/CoiniumServGui/CoiniumServGui.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CoiniumServGui/CoiniumServGui.csproj b/src/CoiniumServGui/CoiniumServGui.csproj index a48406ee8..3d3399319 100644 --- a/src/CoiniumServGui/CoiniumServGui.csproj +++ b/src/CoiniumServGui/CoiniumServGui.csproj @@ -48,8 +48,6 @@ False ..\..\build\packages\ConsoleControl.1.0.3.1\lib\net40\ConsoleControlAPI.dll - - From 943224bdd6f53e313af07f6bff9ffe74c5b4b296 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 13:46:32 +0300 Subject: [PATCH 107/230] removed paymentprocessorfactory, serverfactory, servicefactory, storagefactory,vardiffmanagerfactory - they're instead handled by objectfactor.cs. Improved PoolTests.cs. Belongs to #247. --- src/CoiniumServ/CoiniumServ.csproj | 14 -- src/CoiniumServ/Factories/IObjectFactory.cs | 44 ++++++ src/CoiniumServ/Factories/ObjectFactory.cs | 141 +++++++++++++++++ src/CoiniumServ/Mining/Pools/Pool.cs | 61 ++------ .../Statistics/IStatisticsObjectFactory.cs | 48 ------ .../Mining/Pools/Statistics/Statistics.cs | 3 +- .../Statistics/StatisticsObjectFactory.cs | 106 ------------- .../Mining/Vardiff/IVardiffManagerFactory.cs | 33 ---- .../Mining/Vardiff/VardiffManager.cs | 4 +- .../Mining/Vardiff/VardiffManagerFactory.cs | 59 ------- .../Payments/IPaymentProcessorFactory.cs | 35 ----- src/CoiniumServ/Payments/PaymentProcessor.cs | 4 +- .../Payments/PaymentProcessorFactory.cs | 62 -------- .../Persistance/IStorageFactory.cs | 36 ----- src/CoiniumServ/Persistance/StorageFactory.cs | 61 -------- src/CoiniumServ/Program.cs | 7 +- .../Repository/Registries/FactoryRegistry.cs | 6 - .../Repository/Registries/Registry.cs | 1 - .../Repository/Registries/ServerRegistry.cs | 15 +- .../Repository/Registries/ServiceRegistry.cs | 46 ------ src/CoiniumServ/Server/IServerFactory.cs | 41 ----- .../Server/Mining/Service/IServiceFactory.cs | 42 ----- .../Server/Mining/Service/ServiceFactory.cs | 66 -------- src/CoiniumServ/Server/ServerFactory.cs | 78 ---------- src/CoiniumServ/Server/Servers.cs | 31 ---- .../Utils/Helpers/Validation/Enforce.cs | 10 +- src/Tests/Mining/Pools/PoolTests.cs | 145 +++--------------- 27 files changed, 242 insertions(+), 957 deletions(-) delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs delete mode 100644 src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs delete mode 100644 src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs delete mode 100644 src/CoiniumServ/Payments/IPaymentProcessorFactory.cs delete mode 100644 src/CoiniumServ/Payments/PaymentProcessorFactory.cs delete mode 100644 src/CoiniumServ/Persistance/IStorageFactory.cs delete mode 100644 src/CoiniumServ/Persistance/StorageFactory.cs delete mode 100644 src/CoiniumServ/Repository/Registries/ServiceRegistry.cs delete mode 100644 src/CoiniumServ/Server/IServerFactory.cs delete mode 100644 src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs delete mode 100644 src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs delete mode 100644 src/CoiniumServ/Server/ServerFactory.cs delete mode 100644 src/CoiniumServ/Server/Servers.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 4418c5df3..6f1c2742e 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -138,9 +138,7 @@ - - @@ -165,10 +163,8 @@ - - @@ -177,12 +173,10 @@ - - @@ -201,7 +195,6 @@ - @@ -230,9 +223,7 @@ - - @@ -283,7 +274,6 @@ - @@ -308,10 +298,6 @@ - - - - diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index d14000389..2846a30a3 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -31,8 +31,14 @@ using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Payments; using CoiniumServ.Persistance; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Server.Web; namespace CoiniumServ.Factories { @@ -76,8 +82,46 @@ IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker j IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage); + IPaymentProcessor GetPaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig); + IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig); + IVardiffManager GetVardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig); + + #endregion + + #region pool statistics objects + + IStatistics GetStatistics(); + + IGlobal GetGlobalStatistics(); + + IAlgorithms GetAlgorithmStatistics(); + + IPools GetPoolStats(); + + IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage); + + IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage); + + ILatestBlocks GetLatestBlocks(IStorage storage); + + #endregion + + #region server & service objects + + IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManager, IJobManager jobManager, + IBanManager banManager, ICoinConfig coinConfig); + + IRpcService GetMiningService(string type, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient); + + IWebServer GetWebServer(); + + #endregion + + #region storage objects + IStorage GetStorage(string type, IPoolConfig poolConfig); + #endregion } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index bb51af84a..4af455fd0 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Config; @@ -30,9 +31,15 @@ using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Mining.Pools.Statistics; using CoiniumServ.Mining.Shares; +using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Server.Web; using Nancy.TinyIoc; namespace CoiniumServ.Factories @@ -155,6 +162,19 @@ public IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJ return _applicationContext.Container.Resolve(@params); } + public IPaymentProcessor GetPaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage, + IWalletConfig walletConfig) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"daemonClient", daemonClient}, + {"storage", storage}, + {"walletConfig", walletConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } public IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig) { @@ -168,6 +188,127 @@ public IBanManager GetBanManager(string pool, IShareManager shareManager, IBanCo return _applicationContext.Container.Resolve(@params); } + public IVardiffManager GetVardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"shareManager", shareManager}, + {"vardiffConfig", vardiffConfig}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + #endregion + + #region pool statistics objects + + public IStatistics GetStatistics() + { + return _applicationContext.Container.Resolve(); + } + + public IGlobal GetGlobalStatistics() + { + return _applicationContext.Container.Resolve(); + } + + public IAlgorithms GetAlgorithmStatistics() + { + return _applicationContext.Container.Resolve(); + } + + public IPools GetPoolStats() + { + return _applicationContext.Container.Resolve(); + } + + public IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"poolConfig", poolConfig}, + {"daemonClient", daemonClient}, + {"minerManager",minerManager}, + {"hashAlgorithm", hashAlgorithm}, + {"blockStatistics", blockStatistics}, + {"storage", storage}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + public ILatestBlocks GetLatestBlocks(IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"storage", storage} + }; + + return _applicationContext.Container.Resolve(@params); + } + + public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) + { + var @params = new NamedParameterOverloads + { + {"latestBlocks", latestBlocks}, + {"storage", storage}, + }; + + return _applicationContext.Container.Resolve(@params); + } + + #endregion + + #region server & service objects + + public IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManager, IJobManager jobManager, + IBanManager banManager, ICoinConfig coinConfig) + { + var @params = new NamedParameterOverloads + { + {"pool", pool}, + {"minerManager", minerManager}, + {"jobManager", jobManager}, + {"banManager", banManager}, + {"coinConfig", coinConfig} + }; + + return _applicationContext.Container.Resolve(type, @params); + } + + public IRpcService GetMiningService(string type, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient) + { + var @params = new NamedParameterOverloads + { + {"coinConfig", coinConfig}, + {"shareManager", shareManager}, + {"daemonClient", daemonClient} + }; + return _applicationContext.Container.Resolve(type, @params); + } + + public IWebServer GetWebServer() + { + return _applicationContext.Container.Resolve(); + } + + #endregion + + #region storage objects + + public IStorage GetStorage(string type, IPoolConfig poolConfig) + { + var @params = new NamedParameterOverloads + { + {"poolConfig", poolConfig} + }; + + return _applicationContext.Container.Resolve(type, @params); + } + #endregion } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index 0481ac938..f8d68521c 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -39,7 +39,6 @@ using CoiniumServ.Mining.Vardiff; using CoiniumServ.Payments; using CoiniumServ.Persistance; -using CoiniumServ.Server; using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Utils.Helpers.Validation; @@ -58,14 +57,7 @@ public class Pool : IPool private readonly IObjectFactory _objectFactory; - private readonly IServiceFactory _serviceFactory; - private readonly IStorageFactory _storageFactory; - private readonly IPaymentProcessorFactory _paymentProcessorFactory; - private readonly IStatisticsObjectFactory _statisticsObjectFactory; - private readonly IVardiffManagerFactory _vardiffManagerFactory; - private IDaemonClient _daemonClient; - private readonly IServerFactory _serverFactory; private IMinerManager _minerManager; private IJobTracker _jobTracker; private IJobManager _jobManager; @@ -78,7 +70,7 @@ public class Pool : IPool private Dictionary _servers; - private ILogger _logger; + private readonly ILogger _logger; /// /// Instance id of the pool. @@ -90,40 +82,15 @@ public class Pool : IPool /// /// /// - /// The server factory. - /// The service factory. - /// - /// - /// - /// public Pool( IPoolConfig poolConfig, - IObjectFactory objectFactory, - IServerFactory serverFactory, - IServiceFactory serviceFactory, - IStorageFactory storageFactory, - IPaymentProcessorFactory paymentProcessorFactory, - IStatisticsObjectFactory statisticsObjectFactory, - IVardiffManagerFactory vardiffManagerFactory) + IObjectFactory objectFactory) { - - Enforce.ArgumentNotNull(objectFactory, "IObjectFactory"); - - Enforce.ArgumentNotNull(serverFactory, "IServerFactory"); - Enforce.ArgumentNotNull(serviceFactory, "IServiceFactory"); - Enforce.ArgumentNotNull(storageFactory, "IStorageFactory"); - Enforce.ArgumentNotNull(paymentProcessorFactory, "IPaymentProcessorFactory"); - Enforce.ArgumentNotNull(vardiffManagerFactory, "IVardiffManagerFactory"); + Enforce.ArgumentNotNull(() => poolConfig); // make sure we have a config instance supplied. + Enforce.ArgumentNotNull(() => objectFactory); // make sure we have a objectFactory instance supplied. _objectFactory = objectFactory; - _serverFactory = serverFactory; - _serviceFactory = serviceFactory; - _storageFactory = storageFactory; - _paymentProcessorFactory = paymentProcessorFactory; - _statisticsObjectFactory = statisticsObjectFactory; - _vardiffManagerFactory = vardiffManagerFactory; - // TODO: validate pool central wallet & rewards within the startup. Config = poolConfig; @@ -150,9 +117,9 @@ private void InitManagers() // init the algorithm _hashAlgorithm = _objectFactory.GetHashAlgorithm(Config.Coin.Algorithm); - _storage = _storageFactory.Get(Storages.Redis, Config); + _storage = _objectFactory.GetStorage(Storages.Redis, Config); - _paymentProcessor = _paymentProcessorFactory.Get(_daemonClient, _storage, Config.Wallet, Config.Coin); + _paymentProcessor = _objectFactory.GetPaymentProcessor(Config.Coin.Name, _daemonClient, _storage, Config.Wallet); _paymentProcessor.Initialize(Config.Payments); _minerManager = _objectFactory.GetMiningManager(Config.Coin.Name, _daemonClient); @@ -161,7 +128,7 @@ private void InitManagers() _shareManager = _objectFactory.GetShareManager(Config.Coin.Name, _daemonClient, _jobTracker, _storage); - _vardiffManager = _vardiffManagerFactory.Get(_shareManager, Config.Stratum.Vardiff, Config.Coin); + _vardiffManager = _objectFactory.GetVardiffManager(Config.Coin.Name, _shareManager, Config.Stratum.Vardiff); _banningManager = _objectFactory.GetBanManager(Config.Coin.Name, _shareManager, Config.Banning); @@ -170,9 +137,9 @@ private void InitManagers() _jobManager.Initialize(InstanceId); - var latestBlocks = _statisticsObjectFactory.GetLatestBlocks(_storage); - var blockStats = _statisticsObjectFactory.GetBlockStats(latestBlocks, _storage); - Statistics = _statisticsObjectFactory.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); } private void InitServers() @@ -184,8 +151,8 @@ private void InitServers() if (Config.Stratum != null && Config.Stratum.Enabled) { - var stratumServer = _serverFactory.Get("Stratum", this, _minerManager, _jobManager, _banningManager, Config.Coin); - var stratumService = _serviceFactory.Get("Stratum", Config.Coin, _shareManager, _daemonClient); + var stratumServer = _objectFactory.GetMiningServer("Stratum", this, _minerManager, _jobManager, _banningManager, Config.Coin); + var stratumService = _objectFactory.GetMiningService("Stratum", Config.Coin, _shareManager, _daemonClient); stratumServer.Initialize(Config.Stratum); _servers.Add(stratumServer, stratumService); @@ -193,8 +160,8 @@ private void InitServers() if (Config.Vanilla != null && Config.Vanilla.Enabled) { - var vanillaServer = _serverFactory.Get("Vanilla", this, _minerManager, _jobManager, _banningManager, Config.Coin); - var vanillaService = _serviceFactory.Get("Vanilla", Config.Coin, _shareManager, _daemonClient); + var vanillaServer = _objectFactory.GetMiningServer("Vanilla", this, _minerManager, _jobManager, _banningManager, Config.Coin); + var vanillaService = _objectFactory.GetMiningService("Vanilla", Config.Coin, _shareManager, _daemonClient); vanillaServer.Initialize(Config.Vanilla); diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs deleted file mode 100644 index 77f888f6f..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsObjectFactory.cs +++ /dev/null @@ -1,48 +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 CoiniumServ.Cryptology.Algorithms; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance; - -namespace CoiniumServ.Mining.Pools.Statistics -{ - public interface IStatisticsObjectFactory - { - IStatistics GetStatistics(); - - IGlobal GetGlobalStatistics(); - - IAlgorithms GetAlgorithmStatistics(); - - IPools GetPoolStats(); - - IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage); - - IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage); - - ILatestBlocks GetLatestBlocks(IStorage storage); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs index c647aa4e1..8b5275808 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs @@ -22,6 +22,7 @@ #endregion using System.Threading; +using CoiniumServ.Factories; namespace CoiniumServ.Mining.Pools.Statistics { @@ -34,7 +35,7 @@ public class Statistics:IStatistics, IStatisticsProvider private readonly Timer _timer; private const int TimerExpiration = 10; - public Statistics(IStatisticsObjectFactory statisticsObjectFactory) + public Statistics(IObjectFactory statisticsObjectFactory) { Pools = statisticsObjectFactory.GetPoolStats(); Global = statisticsObjectFactory.GetGlobalStatistics(); diff --git a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs b/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs deleted file mode 100644 index cbd10ff3a..000000000 --- a/src/CoiniumServ/Mining/Pools/Statistics/StatisticsObjectFactory.cs +++ /dev/null @@ -1,106 +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 CoiniumServ.Cryptology.Algorithms; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Pools.Statistics -{ - public class StatististicsObjectFactory : IStatisticsObjectFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public StatististicsObjectFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IStatistics GetStatistics() - { - return _applicationContext.Container.Resolve(); - } - - public IGlobal GetGlobalStatistics() - { - return _applicationContext.Container.Resolve(); - } - - public IAlgorithms GetAlgorithmStatistics() - { - return _applicationContext.Container.Resolve(); - } - - public IPools GetPoolStats() - { - return _applicationContext.Container.Resolve(); - } - - public IPerPool GetPerPoolStats(IPoolConfig poolConfig, IDaemonClient daemonClient, IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) - { - var @params = new NamedParameterOverloads - { - {"poolConfig", poolConfig}, - {"daemonClient", daemonClient}, - {"minerManager",minerManager}, - {"hashAlgorithm", hashAlgorithm}, - {"blockStatistics", blockStatistics}, - {"storage", storage}, - }; - - return _applicationContext.Container.Resolve(@params); - } - - public ILatestBlocks GetLatestBlocks(IStorage storage) - { - var @params = new NamedParameterOverloads - { - {"storage", storage} - }; - - return _applicationContext.Container.Resolve(@params); - } - - public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) - { - var @params = new NamedParameterOverloads - { - {"latestBlocks", latestBlocks}, - {"storage", storage}, - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.cs deleted file mode 100644 index 4232717eb..000000000 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManagerFactory.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 - -using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Shares; - -namespace CoiniumServ.Mining.Vardiff -{ - public interface IVardiffManagerFactory - { - IVardiffManager Get(IShareManager shareManager, IVardiffConfig vardiffConfig, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index afb34b284..c6e760b51 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -39,9 +39,9 @@ public class VardiffManager:IVardiffManager private readonly float _tMax; private readonly ILogger _logger; - public VardiffManager(IShareManager shareManager, IVardiffConfig vardiffConfig, ICoinConfig coinConfig ) + public VardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig) { - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", pool); Config = vardiffConfig; diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs deleted file mode 100644 index 4d3c064f7..000000000 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManagerFactory.cs +++ /dev/null @@ -1,59 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Vardiff -{ - public class VardiffManagerFactory : IVardiffManagerFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public VardiffManagerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IVardiffManager Get(IShareManager shareManager, IVardiffConfig vardiffConfig, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"shareManager", shareManager}, - {"vardiffConfig", vardiffConfig}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs b/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs deleted file mode 100644 index b35fe07c0..000000000 --- a/src/CoiniumServ/Payments/IPaymentProcessorFactory.cs +++ /dev/null @@ -1,35 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance; - -namespace CoiniumServ.Payments -{ - public interface IPaymentProcessorFactory - { - IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig, ICoinConfig coinConfig); - } -} diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 528e9adf7..9eedc7161 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -57,12 +57,12 @@ public class PaymentProcessor : IPaymentProcessor private readonly ILogger _logger; - public PaymentProcessor(IDaemonClient daemonClient, IStorage storage , IWalletConfig walletConfig, ICoinConfig coinConfig) + public PaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage , IWalletConfig walletConfig) { _daemonClient = daemonClient; _storage = storage; _walletConfig = walletConfig; - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", pool); } public void Initialize(IPaymentConfig config) diff --git a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs b/src/CoiniumServ/Payments/PaymentProcessorFactory.cs deleted file mode 100644 index c971b468e..000000000 --- a/src/CoiniumServ/Payments/PaymentProcessorFactory.cs +++ /dev/null @@ -1,62 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Payments -{ - public class PaymentProcessorFactory : IPaymentProcessorFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public PaymentProcessorFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IPaymentProcessor Get(IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"daemonClient", daemonClient}, - {"storage", storage}, - {"walletConfig", walletConfig}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Persistance/IStorageFactory.cs b/src/CoiniumServ/Persistance/IStorageFactory.cs deleted file mode 100644 index 055df1729..000000000 --- a/src/CoiniumServ/Persistance/IStorageFactory.cs +++ /dev/null @@ -1,36 +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 CoiniumServ.Mining.Pools.Config; - -namespace CoiniumServ.Persistance -{ - public interface IStorageFactory - { - /// - /// Gets the specified daemon client. - /// - /// - IStorage Get(string storageName, IPoolConfig poolConfig); - } -} diff --git a/src/CoiniumServ/Persistance/StorageFactory.cs b/src/CoiniumServ/Persistance/StorageFactory.cs deleted file mode 100644 index 371a10505..000000000 --- a/src/CoiniumServ/Persistance/StorageFactory.cs +++ /dev/null @@ -1,61 +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 CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Persistance -{ - public class StorageFactory:IStorageFactory - { - - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public StorageFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public IStorage Get(string storageName, IPoolConfig poolConfig) - { - // Default to redis - if (string.IsNullOrWhiteSpace(storageName)) - storageName = Storages.Redis; - - var @params = new NamedParameterOverloads - { - {"poolConfig", poolConfig} - }; - - return _applicationContext.Container.Resolve(storageName, @params); - } - } -} diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index aad75b477..dc0003c3b 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -84,12 +84,15 @@ static void Main(string[] args) _logger.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); PlatformManager.PrintPlatformBanner(); + // object factory + var objectFactory = kernel.Resolve(); + // start pool manager. - var poolManager = kernel.Resolve().GetPoolManager(); + var poolManager = objectFactory.GetPoolManager(); poolManager.Run(); // start web server. - var webServer = kernel.Resolve("Web"); + var webServer = objectFactory.GetWebServer(); while (true) // idle loop & command parser { diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 0c9fcd884..03d79951d 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -54,15 +54,9 @@ public void RegisterInstances() { _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index 50922fba8..8886f6c13 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -50,7 +50,6 @@ public void RegisterInstances() { typeof(ManagerRegistry), typeof(ServerRegistry), - typeof(ServiceRegistry), typeof(ClassRegistry), typeof(FactoryRegistry), typeof(AlgorithmRegistry), diff --git a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs index 04a93fbc5..44a3f66ef 100644 --- a/src/CoiniumServ/Repository/Registries/ServerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ServerRegistry.cs @@ -22,10 +22,12 @@ #endregion using CoiniumServ.Repository.Context; -using CoiniumServ.Server; using CoiniumServ.Server.Mining; +using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Stratum.Service; using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Server.Mining.Vanilla.Service; using CoiniumServ.Server.Web; namespace CoiniumServ.Repository.Registries @@ -41,9 +43,14 @@ public ServerRegistry(IApplicationContext applicationContext) public void RegisterInstances() { - _applicationContext.Container.Register(Servers.Vanilla).AsMultiInstance(); - _applicationContext.Container.Register(Servers.Stratum).AsMultiInstance(); - _applicationContext.Container.Register(Servers.Web).AsSingleton(); + // servers. + _applicationContext.Container.Register(Services.Vanilla).AsMultiInstance(); + _applicationContext.Container.Register(Services.Stratum).AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); + + // services. + _applicationContext.Container.Register(Services.Vanilla).AsMultiInstance(); + _applicationContext.Container.Register(Services.Stratum).AsMultiInstance(); } } } diff --git a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs b/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs deleted file mode 100644 index 889408715..000000000 --- a/src/CoiniumServ/Repository/Registries/ServiceRegistry.cs +++ /dev/null @@ -1,46 +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 CoiniumServ.Repository.Context; -using CoiniumServ.Server.Mining.Service; -using CoiniumServ.Server.Mining.Stratum.Service; -using CoiniumServ.Server.Mining.Vanilla.Service; - -namespace CoiniumServ.Repository.Registries -{ - public class ServiceRegistry:IRegistry - { - private readonly IApplicationContext _applicationContext; - - public ServiceRegistry(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public void RegisterInstances() - { - _applicationContext.Container.Register(Services.Vanilla).AsMultiInstance(); - _applicationContext.Container.Register(Services.Stratum).AsMultiInstance(); - } - } -} diff --git a/src/CoiniumServ/Server/IServerFactory.cs b/src/CoiniumServ/Server/IServerFactory.cs deleted file mode 100644 index 27fcb5e05..000000000 --- a/src/CoiniumServ/Server/IServerFactory.cs +++ /dev/null @@ -1,41 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Server.Mining; -using CoiniumServ.Server.Web; - -namespace CoiniumServ.Server -{ - public interface IServerFactory - { - IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager, - IBanManager banManager, ICoinConfig coinConfig); - - IWebServer Get(string serverName, IPoolManager poolManager); - } -} diff --git a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs deleted file mode 100644 index b8b798213..000000000 --- a/src/CoiniumServ/Server/Mining/Service/IServiceFactory.cs +++ /dev/null @@ -1,42 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Shares; - -namespace CoiniumServ.Server.Mining.Service -{ - public interface IServiceFactory - { - /// - /// Gets the specified service name. - /// - /// Name of the service. - /// - /// The share manager. - /// The daemon client. - /// - IRpcService Get(string serviceName, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient); - } -} diff --git a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs b/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs deleted file mode 100644 index 16187d1f3..000000000 --- a/src/CoiniumServ/Server/Mining/Service/ServiceFactory.cs +++ /dev/null @@ -1,66 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Daemon; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Server.Mining.Service -{ - public class ServiceFactory : IServiceFactory - { - /// - /// The _kernel - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - public ServiceFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Gets the specified service name. - /// - /// Name of the service. - /// - /// The share manager. - /// The daemon client. - /// - public IRpcService Get(string serviceName, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient) - { - var @params = new NamedParameterOverloads - { - {"coinConfig", coinConfig}, - {"shareManager", shareManager}, - {"daemonClient", daemonClient} - }; - return _applicationContext.Container.Resolve(serviceName, @params); - } - } -} diff --git a/src/CoiniumServ/Server/ServerFactory.cs b/src/CoiniumServ/Server/ServerFactory.cs deleted file mode 100644 index ac7e9a0d3..000000000 --- a/src/CoiniumServ/Server/ServerFactory.cs +++ /dev/null @@ -1,78 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Repository.Context; -using CoiniumServ.Server.Mining; -using CoiniumServ.Server.Web; -using Nancy.TinyIoc; - -namespace CoiniumServ.Server -{ - public class ServerFactory : IServerFactory - { - private readonly IApplicationContext _applicationContext; - - public ServerFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Gets the specified service name. - /// - /// Name of the service. - /// - /// The miner manager. - /// - /// - /// - public IMiningServer Get(string serverName, IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager, ICoinConfig coinConfig) - { - var @params = new NamedParameterOverloads - { - {"pool", pool}, - {"minerManager", minerManager}, - {"jobManager", jobManager}, - {"banManager", banManager}, - {"coinConfig", coinConfig} - }; - - return _applicationContext.Container.Resolve(serverName, @params); - } - - public IWebServer Get(string serverName, IPoolManager poolManager) - { - var @params = new NamedParameterOverloads - { - {"poolManager", poolManager}, - }; - - return _applicationContext.Container.Resolve(serverName, @params); - } - } -} diff --git a/src/CoiniumServ/Server/Servers.cs b/src/CoiniumServ/Server/Servers.cs deleted file mode 100644 index e50f61704..000000000 --- a/src/CoiniumServ/Server/Servers.cs +++ /dev/null @@ -1,31 +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.Server -{ - public class Servers - { - public const string Vanilla = "Vanilla"; - public const string Stratum = "Stratum"; - public const string Web = "Web"; - } -} diff --git a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs index fe88f9a9d..aa25f0376 100644 --- a/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs +++ b/src/CoiniumServ/Utils/Helpers/Validation/Enforce.cs @@ -45,9 +45,7 @@ public static class Enforce public static void ArgumentIsValid(T value, string message, Func predicate) { if (!predicate(value)) - { throw new ArgumentException(message); - } } /// @@ -70,9 +68,7 @@ public static void ArgumentNotNull(Expression> argument) where T : cl public static void ArgumentNotNull(object value, string name) { if (value == null) - { - throw new ArgumentNullException(string.Format("{0} cannot be passed as null. Check the DI configuration or consuming class.", name)); - } + throw new ArgumentNullException(name); } /// @@ -85,9 +81,7 @@ public static void ArgumentNotNull(object value, string name) public static void HasItems(ICollection collection, string name) { if (collection == null || collection.Count == 0) - { throw new ArgumentException(string.Format("{0} does not contain elements and elements are required. Check the consuming class.", name)); - } } /// @@ -99,9 +93,7 @@ public static void HasItems(ICollection collection, string name) public static void EnumValueIsDefined(TEnum value, string name) { if (!Enum.IsDefined(typeof(TEnum), value)) - { throw new ArgumentException(string.Format("The enum value {0} does not exist in {1}.", value, typeof(TEnum).Name)); - } } /// diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Mining/Pools/PoolTests.cs index fd77ab4b3..0c456e3b4 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Mining/Pools/PoolTests.cs @@ -22,24 +22,11 @@ #endregion using System; -using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Factories; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; -using CoiniumServ.Payments; -using CoiniumServ.Persistance; -using CoiniumServ.Server; -using CoiniumServ.Server.Mining; -using CoiniumServ.Server.Mining.Service; using NSubstitute; using Should.Fluent; using Xunit; @@ -48,28 +35,9 @@ namespace CoiniumServ.Tests.Mining.Pools { public class PoolTests { - // factory mocks - private readonly IObjectFactory _objectFactory; - private readonly IServerFactory _serverFactory; - private readonly IServiceFactory _serviceFactory; - private readonly IStorageFactory _storageFactory; - private readonly IPaymentProcessorFactory _paymentProcessorFactory; - private readonly IStatisticsObjectFactory _statisticsObjectFactory; - private readonly IVardiffManagerFactory _vardiffManagerFactory; - // object mocks. + private readonly IObjectFactory _objectFactory; private readonly IDaemonClient _daemonClient; - private readonly IMinerManager _minerManager; - private readonly IJobManager _jobManager; - private readonly IJobTracker _jobTracker; - private readonly IShareManager _shareManager; - private readonly IStorage _storage; - private readonly IMiningServer _miningServer; - private readonly IRpcService _rpcService; - private readonly IPaymentProcessor _paymentProcessor; - private readonly IStatistics _statistics; - private readonly IVardiffManager _vardiffManager; - private readonly IBanManager _banManager; private readonly IPoolConfig _config; /// @@ -77,124 +45,51 @@ public class PoolTests /// public PoolTests() { + // factory mockup. _objectFactory = Substitute.For(); - _serverFactory = Substitute.For(); - _serviceFactory = Substitute.For(); - _storageFactory = Substitute.For(); - _paymentProcessorFactory = Substitute.For(); - _statisticsObjectFactory = Substitute.For(); - _vardiffManagerFactory = Substitute.For(); - - _daemonClient = Substitute.For(); - _minerManager = Substitute.For(); - _jobManager = Substitute.For(); - _jobTracker = Substitute.For(); - _shareManager = Substitute.For(); - _miningServer = Substitute.For(); - _rpcService = Substitute.For(); - _storage = Substitute.For(); - _paymentProcessor = Substitute.For(); - _statistics = Substitute.For(); - _vardiffManager = Substitute.For(); - _banManager = Substitute.For(); - // pool-config mockup. _config = Substitute.For(); _config.Daemon.Valid.Returns(true); - // init daemon client + // daemon client mockup. _daemonClient = _objectFactory.GetDaemonClient(_config.Coin.Name, _config.Daemon); _daemonClient.GetInfo().Returns(new Info()); _daemonClient.GetMiningInfo().Returns(new MiningInfo()); } + /// /// Tests pool constructor with all valid parameters. Should succeed. /// [Fact] - public void ConstructorTest_NonNullParams_ShouldSucceed() + public void ConstructorTest_NonNullParams_ShouldSuccess() { - var pool = new Pool( - _config, - _objectFactory, - _serverFactory, - _serviceFactory, - _storageFactory, - _paymentProcessorFactory, - _statisticsObjectFactory, - _vardiffManagerFactory - ); + var pool = new Pool(_config, _objectFactory); // create the pool instance. pool.Should().Not.Be.Null(); + pool.InstanceId.Should().Be.GreaterThan((UInt32)0); // pool should be already created an instance id. } - + /// - /// Initializes pool with all valid parameters, should succeed. + /// Tests pool constructor with null paramets and expects exceptions being thronw. /// [Fact] - public void InitializationTest_NonNullParams_ShouldSuccess() + public void ConstructorTest_NullParams_ShouldThrowException() { - var pool = new Pool( - _config, - _objectFactory, - _serverFactory, - _serviceFactory, - _storageFactory, - _paymentProcessorFactory, - _statisticsObjectFactory, - _vardiffManagerFactory - ); - - pool.Should().Not.Be.Null(); - - // initialize hash algorithm - var hashAlgorithm = Substitute.For(); - _objectFactory.GetHashAlgorithm(_config.Coin.Algorithm).Returns(hashAlgorithm); - - // initialize the miner manager. - _objectFactory.GetMiningManager(_config.Coin.Name, _daemonClient); - - var walletConfig = Substitute.For(); - var rewardsConfig = Substitute.For(); - - // payment processor - _paymentProcessorFactory.Get(_daemonClient, _storage, walletConfig, _config.Coin); - - // initialize storage manager - _storageFactory.Get(Storages.Redis, _config); - - // initialize the job tracker - _objectFactory.GetJobTracker(); - - // initialize share manager. - _objectFactory.GetShareManager(_config.Coin.Name, _daemonClient, _jobTracker, _storage).Returns(_shareManager); - - // vardiff manager - var vardiffConfig = Substitute.For(); - _vardiffManagerFactory.Get(_shareManager, vardiffConfig, _config.Coin); - - // banning manager - var banConfig = Substitute.For(); - _objectFactory.GetBanManager(_config.Coin.Name, _shareManager, banConfig); - - // initalize job manager. - _objectFactory.GetJobManager(_config.Coin.Name, _daemonClient, _jobTracker, _shareManager, _minerManager, hashAlgorithm, walletConfig, - rewardsConfig).Returns(_jobManager); - - _jobManager.Initialize(pool.InstanceId); - - // init server - _serverFactory.Get(Services.Stratum, pool, _minerManager, _jobManager, _banManager, _config.Coin).Returns(_miningServer); + var configException = Assert.Throws(() => + { + var pool = new Pool(null, _objectFactory); + }); - // init service - _serviceFactory.Get(Services.Stratum, _config.Coin, _shareManager, _daemonClient).Returns(_rpcService); + configException.Message.Should().Contain("poolConfig"); - // initalize the server. - _miningServer.Initialize(_config.Stratum); + var factoryException = Assert.Throws(() => + { + var pool = new Pool(_config, null); + }); - // initialize the pool. - pool.InstanceId.Should().Be.GreaterThan((UInt32)0); + factoryException.Message.Should().Contain("objectFactory"); } } } From df1791be7cc2d54dd5fdfb1e3b83d84a4c88ad5c Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 15:37:42 +0300 Subject: [PATCH 108/230] Renamed config.json "logs" as "logging" - you have to fix your config.json file! Improved log-manager configuration code. Implemented new singleton log-manager. Started implementing new config factory. --- src/CoiniumServ/CoiniumServ.csproj | 9 +- src/CoiniumServ/Daemon/DaemonBase.cs | 9 +- src/CoiniumServ/Daemon/DaemonClient.cs | 3 +- src/CoiniumServ/Factories/ConfigFactory.cs | 46 +++++ src/CoiniumServ/Factories/IConfigFactory.cs | 13 ++ src/CoiniumServ/Factories/IObjectFactory.cs | 5 +- src/CoiniumServ/Factories/ObjectFactory.cs | 8 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 6 +- src/CoiniumServ/Program.cs | 20 +- .../Repository/Registries/ClassRegistry.cs | 3 + .../Repository/Registries/FactoryRegistry.cs | 2 +- .../Server/Mining/Stratum/StratumMiner.cs | 17 +- .../Server/Mining/Vanilla/VanillaMiner.cs | 13 +- src/CoiniumServ/Server/Web/WebServer.cs | 10 +- .../Configuration/GlobalConfigFactory.cs | 65 ------ src/CoiniumServ/Utils/Logging.cs | 185 ------------------ src/CoiniumServ/Utils/Logging/ILogManager.cs | 30 +++ .../ILogTarget.cs} | 28 +-- .../Utils/Logging/ILoggingConfig.cs | 34 ++++ src/CoiniumServ/Utils/Logging/LogManager.cs | 135 +++++++++++++ src/CoiniumServ/Utils/Logging/LogTarget.cs | 80 ++++++++ .../Utils/Logging/LoggingConfig.cs | 44 +++++ src/CoiniumServ/config/config-sample.json | 2 +- 23 files changed, 460 insertions(+), 307 deletions(-) delete mode 100644 src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs delete mode 100644 src/CoiniumServ/Utils/Logging.cs create mode 100644 src/CoiniumServ/Utils/Logging/ILogManager.cs rename src/CoiniumServ/Utils/{Configuration/IGlobalConfigFactory.cs => Logging/ILogTarget.cs} (73%) create mode 100644 src/CoiniumServ/Utils/Logging/ILoggingConfig.cs create mode 100644 src/CoiniumServ/Utils/Logging/LogManager.cs create mode 100644 src/CoiniumServ/Utils/Logging/LogTarget.cs create mode 100644 src/CoiniumServ/Utils/Logging/LoggingConfig.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 6f1c2742e..f467781de 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -204,8 +204,6 @@ - - @@ -245,7 +243,12 @@ - + + + + + + diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 9b2c44b6e..e6b0f121f 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -27,8 +27,9 @@ using System.Text; using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Exceptions; -using CoiniumServ.Utils; +using CoiniumServ.Factories; using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Logging; using Newtonsoft.Json; using Serilog; @@ -45,13 +46,11 @@ public class DaemonBase : IDaemonBase public DaemonBase(string pool, IDaemonConfig daemonConfig) { - _logger = Logging.PacketLogger.ForContext().ForContext("Component", pool); - RpcUrl = string.Format("http://{0}:{1}", daemonConfig.Host, daemonConfig.Port); RpcUser = daemonConfig.Username; RpcPassword = daemonConfig.Password; - - RequestCounter = 0; + RequestCounter = 0; + _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool); } /// diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index c50288d1e..4e7f3c04f 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -24,7 +24,6 @@ using System; using System.Collections.Generic; using System.Linq; -using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Requests; using CoiniumServ.Daemon.Responses; @@ -51,7 +50,7 @@ public class DaemonClient : DaemonBase, IDaemonClient public static readonly object[] EmptyString = {}; // used as empty parameter. public DaemonClient(string pool, IDaemonConfig daemonConfig) - :base(pool, daemonConfig) + : base(pool, daemonConfig) { } /// diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs index be5bf751b..1a896f318 100644 --- a/src/CoiniumServ/Factories/ConfigFactory.cs +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -21,6 +21,12 @@ // #endregion +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Configuration; +using CoiniumServ.Utils.Logging; + namespace CoiniumServ.Factories { /// @@ -28,5 +34,45 @@ namespace CoiniumServ.Factories /// public class ConfigFactory:IConfigFactory { + public bool GlobalConfigExists { get { return _globalConfigData != null; }} + public dynamic Logging { get { return _globalConfigData.logging; } } + + private const string GlobalConfigFilename = "config/config.json"; // global config filename. + private readonly dynamic _globalConfigData; // global config data. + + private readonly IRedisConfig _redisConfig; + private readonly IWebServerConfig _webServerConfig; + private readonly ILoggingConfig _logConfig; + + /// + /// The _application context + /// + private IApplicationContext _applicationContext; + + public ConfigFactory(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. + _redisConfig = new RedisConfig(_globalConfigData.storage.redis); + _webServerConfig = new WebServerConfig(_globalConfigData.web); + _logConfig = new LoggingConfig(_globalConfigData.logging); + } + + // todo: should be per-pool! + public IRedisConfig GetRedisConfig() + { + return _redisConfig; + } + + public IWebServerConfig GetWebServerConfig() + { + return _webServerConfig; + } + + public ILoggingConfig GetLoggingConfig() + { + return _logConfig; + } } } + \ No newline at end of file diff --git a/src/CoiniumServ/Factories/IConfigFactory.cs b/src/CoiniumServ/Factories/IConfigFactory.cs index 07c5d1b44..fc15c39ad 100644 --- a/src/CoiniumServ/Factories/IConfigFactory.cs +++ b/src/CoiniumServ/Factories/IConfigFactory.cs @@ -21,6 +21,10 @@ // #endregion +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Logging; + namespace CoiniumServ.Factories { /// @@ -28,5 +32,14 @@ namespace CoiniumServ.Factories /// public interface IConfigFactory { + bool GlobalConfigExists { get; } + + dynamic Logging { get; } + + IRedisConfig GetRedisConfig(); + + IWebServerConfig GetWebServerConfig(); + + ILoggingConfig GetLoggingConfig(); } } diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index 2846a30a3..ca9b238e3 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -39,6 +39,7 @@ using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Logging; namespace CoiniumServ.Factories { @@ -119,9 +120,11 @@ IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManage #endregion - #region storage objects + #region other objects IStorage GetStorage(string type, IPoolConfig poolConfig); + ILogManager GetLogManager(); + #endregion } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index 4af455fd0..e836cc214 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -40,6 +40,7 @@ using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Logging; using Nancy.TinyIoc; namespace CoiniumServ.Factories @@ -297,7 +298,7 @@ public IWebServer GetWebServer() #endregion - #region storage objects + #region other objects public IStorage GetStorage(string type, IPoolConfig poolConfig) { @@ -309,6 +310,11 @@ public IStorage GetStorage(string type, IPoolConfig poolConfig) return _applicationContext.Container.Resolve(type, @params); } + public ILogManager GetLogManager() + { + return _applicationContext.Container.Resolve(); + } + #endregion } } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 41a832180..964cc4e9f 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -27,7 +27,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; -using CoiniumServ.Mining.Pools; +using CoiniumServ.Factories; using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Mining.Shares; using CoiniumServ.Payments; @@ -55,12 +55,12 @@ public class Redis:IStorage, IRedis private readonly ILogger _logger; - public Redis(IGlobalConfigFactory globalConfigFactory, IPoolConfig poolConfig) + public Redis(ConfigFactory configFactory, IPoolConfig poolConfig) { _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); _poolConfig = poolConfig; // the pool config. - _redisConfig = globalConfigFactory.GetRedisConfig(); // read the redis config. + _redisConfig = configFactory.GetRedisConfig(); // read the redis config. IsEnabled = _redisConfig.Enabled; diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index dc0003c3b..93cb60612 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -26,12 +26,10 @@ using System.Reflection; using System.Threading; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools; using CoiniumServ.Repository; -using CoiniumServ.Server.Web; using CoiniumServ.Utils; using CoiniumServ.Utils.Commands; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Utils.Logging; using CoiniumServ.Utils.Platform; using Nancy.TinyIoc; using Serilog; @@ -59,16 +57,16 @@ static void Main(string[] args) // start the ioc kernel. var kernel = TinyIoCContainer.Current; - new Bootstrapper(kernel); + var bootstrapper = new Bootstrapper(kernel); + var objectFactory = kernel.Resolve(); // print intro texts. ConsoleWindow.PrintBanner(); ConsoleWindow.PrintLicense(); // check if we have a valid config file. - var globalConfig = kernel.Resolve().Get(); - - if (globalConfig == null) + var configFactory = kernel.Resolve(); + if (!configFactory.GlobalConfigExists) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Couldn't read config/config.json! Make sure you rename config/config-sample.json as config/config.json."); @@ -76,17 +74,15 @@ static void Main(string[] args) return; } - // init logging facilities. - Logging.Init(globalConfig); + // initialize log-manager. + var logManager = objectFactory.GetLogManager(); + logManager.Initialize(); // print a version banner. _logger = Log.ForContext(); _logger.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); PlatformManager.PrintPlatformBanner(); - // object factory - var objectFactory = kernel.Resolve(); - // start pool manager. var poolManager = objectFactory.GetPoolManager(); poolManager.Run(); diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index abe1e6ec7..03adf7746 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -30,6 +30,8 @@ using CoiniumServ.Persistance; using CoiniumServ.Persistance.Redis; using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Logging; namespace CoiniumServ.Repository.Registries { @@ -57,6 +59,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 03d79951d..a071d062a 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -53,10 +53,10 @@ public FactoryRegistry(IApplicationContext applicationContext) public void RegisterInstances() { _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 4d8a5e06c..60e021356 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -22,7 +22,6 @@ #endregion using System; -using System.Configuration; using System.Text; using AustinHarris.JsonRpc; using CoiniumServ.Mining.Miners; @@ -31,12 +30,11 @@ using CoiniumServ.Server.Mining.Stratum.Errors; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Stratum.Service; -using CoiniumServ.Utils; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Logging; using Newtonsoft.Json; using Serilog; -using Serilog.Context; namespace CoiniumServ.Server.Mining.Stratum { @@ -85,6 +83,8 @@ public class StratumMiner : IClient, IStratumMiner private readonly IMinerManager _minerManager; + private readonly ILogger _logger; + /// /// Creates a new miner instance. /// @@ -93,6 +93,7 @@ public class StratumMiner : IClient, IStratumMiner /// /// /// + /// public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool pool, IMinerManager minerManager) { Id = id; // the id of the miner. @@ -105,6 +106,8 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo Subscribed = false; // miner has to subscribe. Authenticated = false; // miner has to authenticate. + + _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool.Config.Coin.Name); } /// @@ -138,7 +141,7 @@ public bool Authenticate(string user, string password) /// public void Parse(ConnectionDataEventArgs e) { - Logging.PacketLogger.ForContext().Verbose("rx: {0}", e.Data.ToEncodedString().PrettifyJson()); + _logger.Verbose("rx: {0}", e.Data.ToEncodedString().PrettifyJson()); var rpcResultHandler = new AsyncCallback( callback => @@ -152,7 +155,7 @@ public void Parse(ConnectionDataEventArgs e) var miner = (StratumMiner)context.Miner; miner.Connection.Send(response); - Logging.PacketLogger.ForContext().Verbose("tx: {0}", result.PrettifyJson()); + _logger.Verbose("tx: {0}", result.PrettifyJson()); }); var line = e.Data.ToEncodedString(); @@ -182,7 +185,7 @@ public void SendDifficulty() var data = Encoding.UTF8.GetBytes(json); Connection.Send(data); - Logging.PacketLogger.ForContext().Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); + _logger.Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); } /// @@ -202,7 +205,7 @@ public void SendJob(IJob job) var data = Encoding.UTF8.GetBytes(json); Connection.Send(data); - Logging.PacketLogger.ForContext().Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); + _logger.Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); } } } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 1b49cbd4b..981412f80 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -26,11 +26,13 @@ using System.Net; using System.Text; using AustinHarris.JsonRpc; +using CoiniumServ.Factories; using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools; using CoiniumServ.Server.Mining.Vanilla.Service; -using CoiniumServ.Utils; using CoiniumServ.Utils.Extensions; +using CoiniumServ.Utils.Logging; +using Serilog; namespace CoiniumServ.Server.Mining.Vanilla { @@ -58,12 +60,15 @@ public class VanillaMiner : IVanillaMiner private readonly IMinerManager _minerManager; + private readonly ILogger _logger; + /// /// /// /// /// /// + /// public VanillaMiner(int id, IPool pool, IMinerManager minerManager) { Id = id; // the id of the miner. @@ -71,6 +76,8 @@ public VanillaMiner(int id, IPool pool, IMinerManager minerManager) _minerManager = minerManager; Authenticated = false; // miner has to authenticate. + + _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool.Config.Coin.Name); } public bool Authenticate(string user, string password) @@ -99,13 +106,13 @@ public void Parse(HttpListenerContext httpContext) context.Request.Response.ContentLength64 = response.Length; context.Request.Response.OutputStream.Write(response, 0, response.Length); - Logging.PacketLogger.ForContext().Verbose("tx: {0}", result.PrettifyJson()); + _logger.Verbose("tx: {0}", result.PrettifyJson()); }); using (var reader = new StreamReader(httpRequest.InputStream, Encoding.UTF8)) { var line = reader.ReadToEnd(); - Logging.PacketLogger.ForContext().Verbose("rx: {0}", line.PrettifyJson()); + _logger.Verbose("rx: {0}", line.PrettifyJson()); var rpcRequest = new HttpServiceRequest(line, httpContext); var rpcContext = new HttpServiceContext(this, rpcRequest); diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index a8e781bb1..ea2d6dee2 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -21,10 +21,9 @@ // #endregion -using CoiniumServ.Mining.Pools; +using CoiniumServ.Factories; using CoiniumServ.Net.Server.Http.Web; using CoiniumServ.Repository.Context; -using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Server.Web { @@ -32,13 +31,10 @@ public class WebServer : HttpServer, IWebServer { public IWebServerConfig Config { get; private set; } - private IPoolManager _poolManager; - - public WebServer(IApplicationContext applicationContext, IGlobalConfigFactory globalConfigFactory, IPoolManager poolManager) + public WebServer(IApplicationContext applicationContext, IConfigFactory configFactory) : base(applicationContext) { - _poolManager = poolManager; - Config = globalConfigFactory.GetWebServerConfig(); + Config = configFactory.GetWebServerConfig(); BindIP = Config.BindInterface; Port = Config.Port; diff --git a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs deleted file mode 100644 index 4bac7f765..000000000 --- a/src/CoiniumServ/Utils/Configuration/GlobalConfigFactory.cs +++ /dev/null @@ -1,65 +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 CoiniumServ.Persistance.Redis; -using CoiniumServ.Repository.Context; -using CoiniumServ.Server.Web; - -namespace CoiniumServ.Utils.Configuration -{ - public class GlobalConfigFactory : IGlobalConfigFactory - { - private const string FileName = "config/config.json"; - - private dynamic _data; - private IRedisConfig _redisConfig; - private IWebServerConfig _webServerConfig; - - /// - /// The _application context - /// - private IApplicationContext _applicationContext; - - public GlobalConfigFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - public dynamic Get() - { - // return the global config, if we haven't read it yet, do so. - return _data ?? (_data = JsonConfigReader.Read(FileName)); - } - - public IRedisConfig GetRedisConfig() - { - // return the redis config, if we haven't read it yet, do so. - return _redisConfig ?? (_redisConfig = new RedisConfig(Get().storage.redis)); - } - - public IWebServerConfig GetWebServerConfig() - { - return _webServerConfig ?? (_webServerConfig = new WebServerConfig(Get().web)); - } - } -} diff --git a/src/CoiniumServ/Utils/Logging.cs b/src/CoiniumServ/Utils/Logging.cs deleted file mode 100644 index 0dafdddd4..000000000 --- a/src/CoiniumServ/Utils/Logging.cs +++ /dev/null @@ -1,185 +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; -using System.IO; -using System.Linq; -using System.Threading; -using Microsoft.CSharp.RuntimeBinder; -using Serilog; -using Serilog.Core; -using Serilog.Events; - -namespace CoiniumServ.Utils -{ - /// - /// Controls the logging facilities. - /// - public static class Logging - { - // TODO: change to singleton. - - public static ILogger PacketLogger { get; private set; } - - private const string ConsoleLogFormat = "{Timestamp:HH:mm:ss} [{Level}] [{Source:l}] [{Component:l}] {Message}{NewLine}{Exception}"; - private const string FileLogFormat = "{Timestamp} [{Level}] [{Source:l}] [{Component:l}] {Message}{NewLine}{Exception}"; - - private static string _rootFolder; - - public static void Init(dynamic config) - { - try - { - // read the root folder for logs. - _rootFolder = !string.IsNullOrEmpty(config.logs.root) ? config.logs.root : "logs"; - - if (!Directory.Exists(_rootFolder)) // make sure log root exists. - Directory.CreateDirectory(_rootFolder); - - // create the global logger. - var globalConfig = new LoggerConfiguration(); - var packetLoggerConfig = new LoggerConfiguration(); - - // add enrichers - globalConfig.Enrich.With(new SourceEnricher()); - globalConfig.Enrich.With(new ComponentEnricher()); - - packetLoggerConfig.Enrich.With(new SourceEnricher()); - packetLoggerConfig.Enrich.With(new ComponentEnricher()); - - // read log targets. - var targets = config.logs.targets; - foreach (dynamic target in targets) - { - var enabled = target.enabled; - - if (!enabled) - continue; - - switch ((string) target.type) - { - case "console": - AddConsoleLog(globalConfig, target); - break; - case "file": - AddLogFile(globalConfig, target); - break; - case "packet": - AddPacketLog(packetLoggerConfig, target); - break; - } - } - - // lower the default minimum level to verbose as sinks can only rise them but not lower. - globalConfig.MinimumLevel.Verbose(); - packetLoggerConfig.MinimumLevel.Verbose(); - - Log.Logger = globalConfig.CreateLogger(); // bind the config to global log. - PacketLogger = packetLoggerConfig.CreateLogger(); - } - catch (RuntimeBinderException e) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Couldn't read log targets in config.json! [{0}]", e); - Console.ResetColor(); - Environment.Exit(-1); - } - } - - private static void AddConsoleLog(LoggerConfiguration config, dynamic target) - { - LogEventLevel level = GetLogLevel(target.level); - - config.WriteTo.ColoredConsole(level, ConsoleLogFormat); - } - - private static void AddLogFile(LoggerConfiguration config, dynamic target) - { - LogEventLevel level = GetLogLevel(target.level); - - bool rolling = target.rolling; - var fileName = target.filename; - - string filePath = String.Format("{0}/{1}", _rootFolder, fileName); - - if (rolling) - config.WriteTo.RollingFile(filePath, level, FileLogFormat); - else - config.WriteTo.File(filePath, level, FileLogFormat); - } - - private static void AddPacketLog(LoggerConfiguration config, dynamic target) - { - LogEventLevel level = GetLogLevel(target.level); - - bool rolling = target.rolling; - var fileName = target.filename; - - string filePath = String.Format("{0}/{1}", _rootFolder, fileName); - - if (rolling) - config.WriteTo.RollingFile(filePath, level, FileLogFormat); - else - config.WriteTo.File(filePath, level, FileLogFormat); - } - - private static LogEventLevel GetLogLevel(dynamic level) - { - switch ((string)level) - { - case "verbose": - return LogEventLevel.Verbose; - case "debug": - return LogEventLevel.Debug; - case "information": - return LogEventLevel.Information; - case "warning": - return LogEventLevel.Warning; - case "error": - return LogEventLevel.Error; - case "fatal": - return LogEventLevel.Fatal; - default: - return LogEventLevel.Verbose; - } - } - } - - public class SourceEnricher : ILogEventEnricher - { - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { - logEvent.AddPropertyIfAbsent(logEvent.Properties.Keys.Contains("SourceContext") - ? propertyFactory.CreateProperty("Source", logEvent.Properties["SourceContext"].ToString().Replace("\"","").Split('.').Last()) - : propertyFactory.CreateProperty("Source", "n/a")); - } - } - - public class ComponentEnricher : ILogEventEnricher - { - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { - logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Component", "global")); - } - } -} diff --git a/src/CoiniumServ/Utils/Logging/ILogManager.cs b/src/CoiniumServ/Utils/Logging/ILogManager.cs new file mode 100644 index 000000000..746259797 --- /dev/null +++ b/src/CoiniumServ/Utils/Logging/ILogManager.cs @@ -0,0 +1,30 @@ +#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.Utils.Logging +{ + public interface ILogManager + { + void Initialize(); + } +} diff --git a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs b/src/CoiniumServ/Utils/Logging/ILogTarget.cs similarity index 73% rename from src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs rename to src/CoiniumServ/Utils/Logging/ILogTarget.cs index 839dc110d..5ff5f01b4 100644 --- a/src/CoiniumServ/Utils/Configuration/IGlobalConfigFactory.cs +++ b/src/CoiniumServ/Utils/Logging/ILogTarget.cs @@ -21,21 +21,27 @@ // #endregion -using CoiniumServ.Persistance.Redis; -using CoiniumServ.Server.Web; +using Serilog.Events; -namespace CoiniumServ.Utils.Configuration +namespace CoiniumServ.Utils.Logging { - public interface IGlobalConfigFactory + public interface ILogTarget { - /// - /// Gets the configuration. - /// - /// - dynamic Get(); + bool Enabled { get; } - IRedisConfig GetRedisConfig(); + LogTargetType Type { get; } - IWebServerConfig GetWebServerConfig(); + string Filename { get; } + + bool Rolling { get; } + + LogEventLevel Level { get; } + } + + public enum LogTargetType + { + Console, + File, + Packet } } diff --git a/src/CoiniumServ/Utils/Logging/ILoggingConfig.cs b/src/CoiniumServ/Utils/Logging/ILoggingConfig.cs new file mode 100644 index 000000000..6f5873877 --- /dev/null +++ b/src/CoiniumServ/Utils/Logging/ILoggingConfig.cs @@ -0,0 +1,34 @@ +#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; + +namespace CoiniumServ.Utils.Logging +{ + public interface ILoggingConfig + { + string Root { get; } + + List Targets { get; } + } +} diff --git a/src/CoiniumServ/Utils/Logging/LogManager.cs b/src/CoiniumServ/Utils/Logging/LogManager.cs new file mode 100644 index 000000000..af3298524 --- /dev/null +++ b/src/CoiniumServ/Utils/Logging/LogManager.cs @@ -0,0 +1,135 @@ +#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.IO; +using System.Linq; +using CoiniumServ.Factories; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace CoiniumServ.Utils.Logging +{ + public class LogManager:ILogManager + { + public static ILogger PacketLogger { get; private set; } + + private const string ConsoleLogFormat = "{Timestamp:HH:mm:ss} [{Level}] [{Source:l}] [{Component:l}] {Message}{NewLine}{Exception}"; + private const string FileLogFormat = "{Timestamp} [{Level}] [{Source:l}] [{Component:l}] {Message}{NewLine}{Exception}"; + + private string _rootFolder; + + private readonly ILoggingConfig _config; + + public LogManager(IConfigFactory configFactory) + { + _config = configFactory.GetLoggingConfig(); + } + + public void Initialize() + { + // read the root folder for logs. + _rootFolder = !string.IsNullOrEmpty(_config.Root) ? _config.Root : "logs"; + + if (!Directory.Exists(_rootFolder)) // make sure log root exists. + Directory.CreateDirectory(_rootFolder); + + // create the global logger. + var globalConfig = new LoggerConfiguration(); + var packetLoggerConfig = new LoggerConfiguration(); + + // add enrichers + globalConfig.Enrich.With(new SourceEnricher()); + globalConfig.Enrich.With(new ComponentEnricher()); + + packetLoggerConfig.Enrich.With(new SourceEnricher()); + packetLoggerConfig.Enrich.With(new ComponentEnricher()); + + foreach (var target in _config.Targets) + { + switch (target.Type) + { + case LogTargetType.Console: + CreateConsoleLog(globalConfig, target); + break; + case LogTargetType.File: + CreateFileLog(globalConfig, target); + break; + case LogTargetType.Packet: + CreatePacketLog(packetLoggerConfig, target); + break; + } + } + + // lower the default minimum level to verbose as sinks can only rise them but not lower. + globalConfig.MinimumLevel.Verbose(); + packetLoggerConfig.MinimumLevel.Verbose(); + + Log.Logger = globalConfig.CreateLogger(); // bind the config to global log. + PacketLogger = packetLoggerConfig.CreateLogger(); + } + + private void CreateConsoleLog(LoggerConfiguration config, ILogTarget target) + { + config.WriteTo.ColoredConsole(target.Level, ConsoleLogFormat); + } + + private void CreateFileLog(LoggerConfiguration config, ILogTarget target) + { + string filePath = string.Format("{0}/{1}", _rootFolder, target.Filename); + + if (target.Rolling) + config.WriteTo.RollingFile(filePath, target.Level, FileLogFormat); + else + config.WriteTo.File(filePath, target.Level, FileLogFormat); + } + + private void CreatePacketLog(LoggerConfiguration config, ILogTarget target) + { + string filePath = string.Format("{0}/{1}", _rootFolder, target.Filename); + + if (target.Rolling) + config.WriteTo.RollingFile(filePath, target.Level, FileLogFormat); + else + config.WriteTo.File(filePath, target.Level, FileLogFormat); + } + } + + public class SourceEnricher : ILogEventEnricher + { + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + logEvent.AddPropertyIfAbsent(logEvent.Properties.Keys.Contains("SourceContext") + ? propertyFactory.CreateProperty("Source", logEvent.Properties["SourceContext"].ToString().Replace("\"", "").Split('.').Last()) + : propertyFactory.CreateProperty("Source", "n/a")); + } + } + + public class ComponentEnricher : ILogEventEnricher + { + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Component", "global")); + } + } +} diff --git a/src/CoiniumServ/Utils/Logging/LogTarget.cs b/src/CoiniumServ/Utils/Logging/LogTarget.cs new file mode 100644 index 000000000..f7cdc2e82 --- /dev/null +++ b/src/CoiniumServ/Utils/Logging/LogTarget.cs @@ -0,0 +1,80 @@ +#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 Serilog; +using Serilog.Events; + +namespace CoiniumServ.Utils.Logging +{ + public class LogTarget:ILogTarget + { + public bool Enabled { get; private set; } + public LogTargetType Type { get; private set; } + public string Filename { get; private set; } + public bool Rolling { get; private set; } + public LogEventLevel Level { get; private set; } + + public LogTarget(dynamic config) + { + Enabled = config.enabled; + Filename = config.filename; + Rolling = config.rolling; + + switch ((string) config.type) + { + case "console": + Type = LogTargetType.Console; + break; + case "file": + Type = LogTargetType.File; + break; + case "packet": + Type = LogTargetType.Packet; + break; + } + + switch ((string) config.level) + { + case "verbose": + Level = LogEventLevel.Verbose; + break; + case "debug": + Level = LogEventLevel.Debug; + break; + case "information": + Level = LogEventLevel.Information; + break; + case "warning": + Level = LogEventLevel.Warning; + break; + case "error": + Level = LogEventLevel.Error; + break; + case "fatal": + Level = LogEventLevel.Fatal; + break; + } + } + } +} diff --git a/src/CoiniumServ/Utils/Logging/LoggingConfig.cs b/src/CoiniumServ/Utils/Logging/LoggingConfig.cs new file mode 100644 index 000000000..b39a6d033 --- /dev/null +++ b/src/CoiniumServ/Utils/Logging/LoggingConfig.cs @@ -0,0 +1,44 @@ +#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; + +namespace CoiniumServ.Utils.Logging +{ + public class LoggingConfig : ILoggingConfig + { + public string Root { get; private set; } + public List Targets { get; private set; } + + public LoggingConfig(dynamic config) + { + Root = config.root; + + Targets = new List(); + foreach (var target in config.targets) + { + Targets.Add(new LogTarget(target)); + } + } + } +} diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-sample.json index 604f45417..2393eb260 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-sample.json @@ -18,7 +18,7 @@ }, # log configuration - "logs": { + "logging": { "root": "logs", "targets": [ { From f23263c4a701193a12c66d19a5b0fb0da0cb6f40 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 15:54:20 +0300 Subject: [PATCH 109/230] renamed web section config.json as "website". httpserver is now being injected correct arguments. renamed NancyBootstrapper.cs as WebBootstrapper.cs. Removed block hash & txhash from website. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- src/CoiniumServ/Factories/ConfigFactory.cs | 2 +- src/CoiniumServ/Factories/IObjectFactory.cs | 3 +++ src/CoiniumServ/Factories/ObjectFactory.cs | 6 ++++++ src/CoiniumServ/Mining/Vardiff/VardiffManager.cs | 1 - src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs | 12 ++++-------- .../{NancyBootstrapper.cs => WebBootstrapper.cs} | 4 ++-- .../Repository/Registries/ClassRegistry.cs | 3 +++ .../Repository/Registries/FactoryRegistry.cs | 13 ------------- src/CoiniumServ/Repository/Registries/Registry.cs | 4 ---- src/CoiniumServ/Server/Web/WebServer.cs | 13 ++++++++++--- src/CoiniumServ/config/config-sample.json | 4 ++-- src/CoiniumServ/web/default/pool.cshtml | 4 ---- 13 files changed, 32 insertions(+), 39 deletions(-) rename src/CoiniumServ/Net/Server/Http/Web/{NancyBootstrapper.cs => WebBootstrapper.cs} (96%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index f467781de..c663be67b 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -166,7 +166,7 @@ - + diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs index 1a896f318..39f39593b 100644 --- a/src/CoiniumServ/Factories/ConfigFactory.cs +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -54,7 +54,7 @@ public ConfigFactory(IApplicationContext applicationContext) _applicationContext = applicationContext; _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. _redisConfig = new RedisConfig(_globalConfigData.storage.redis); - _webServerConfig = new WebServerConfig(_globalConfigData.web); + _webServerConfig = new WebServerConfig(_globalConfigData.website); _logConfig = new LoggingConfig(_globalConfigData.logging); } diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index ca9b238e3..0c1f9d22f 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -40,6 +40,7 @@ using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Logging; +using Nancy.Bootstrapper; namespace CoiniumServ.Factories { @@ -118,6 +119,8 @@ IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManage IWebServer GetWebServer(); + INancyBootstrapper GetWebBootstrapper(); + #endregion #region other objects diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index e836cc214..d1ab66b7f 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -41,6 +41,7 @@ using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Logging; +using Nancy.Bootstrapper; using Nancy.TinyIoc; namespace CoiniumServ.Factories @@ -296,6 +297,11 @@ public IWebServer GetWebServer() return _applicationContext.Container.Resolve(); } + public INancyBootstrapper GetWebBootstrapper() + { + return _applicationContext.Container.Resolve(); + } + #endregion #region other objects diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs index c6e760b51..37e5477c8 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs @@ -22,7 +22,6 @@ #endregion using System; -using CoiniumServ.Coin.Config; using CoiniumServ.Mining.Shares; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Helpers.Time; diff --git a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index 3a983c14b..b5082bc71 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -46,16 +46,13 @@ public class HttpServer : IServer, IDisposable /// public bool IsListening { get; protected set; } - /// - /// The application context - /// - private readonly IApplicationContext _applicationContext; + private readonly INancyBootstrapper _webBootstrapper; private readonly ILogger _logger; - public HttpServer(IApplicationContext applicationContext) + public HttpServer(INancyBootstrapper webBootstrapper) { - _applicationContext = applicationContext; + _webBootstrapper = webBootstrapper; _logger = Log.ForContext(); } @@ -68,8 +65,7 @@ public bool Start() hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; hostConfiguration.UrlReservations.CreateAutomatically = true; - var bootstrapper = _applicationContext.Container.Resolve(); - var host = new NancyHost(bootstrapper, hostConfiguration, uri); + var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); try { diff --git a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs b/src/CoiniumServ/Net/Server/Http/Web/WebBootstrapper.cs similarity index 96% rename from src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs rename to src/CoiniumServ/Net/Server/Http/Web/WebBootstrapper.cs index d694967f8..3a51910ef 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/NancyBootstrapper.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/WebBootstrapper.cs @@ -31,14 +31,14 @@ namespace CoiniumServ.Net.Server.Http.Web { - public class NancyBootstrapper : DefaultNancyBootstrapper + public class WebBootstrapper : DefaultNancyBootstrapper { /// /// The _application context /// private readonly IApplicationContext _applicationContext; - public NancyBootstrapper(IApplicationContext applicationContext) + public WebBootstrapper(IApplicationContext applicationContext) { _applicationContext = applicationContext; } diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 03adf7746..9a1442013 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -26,12 +26,14 @@ using CoiniumServ.Mining.Pools; using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Net.Server.Http.Web; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Redis; using CoiniumServ.Repository.Context; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Logging; +using Nancy.Bootstrapper; namespace CoiniumServ.Repository.Registries { @@ -60,6 +62,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } \ No newline at end of file diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index a071d062a..3fa88d12b 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -23,21 +23,8 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Factories; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; -using CoiniumServ.Payments; -using CoiniumServ.Persistance; using CoiniumServ.Repository.Context; -using CoiniumServ.Server; -using CoiniumServ.Server.Mining.Service; -using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Repository.Registries { diff --git a/src/CoiniumServ/Repository/Registries/Registry.cs b/src/CoiniumServ/Repository/Registries/Registry.cs index 8886f6c13..2a9335ec1 100644 --- a/src/CoiniumServ/Repository/Registries/Registry.cs +++ b/src/CoiniumServ/Repository/Registries/Registry.cs @@ -23,9 +23,7 @@ using System; using System.Collections.Generic; -using CoiniumServ.Net.Server.Http.Web; using CoiniumServ.Repository.Context; -using Nancy.Bootstrapper; using Nancy.TinyIoc; namespace CoiniumServ.Repository.Registries @@ -43,8 +41,6 @@ public void RegisterInstances() { _kernel.Register().AsSingleton(); - _kernel.Register().AsSingleton(); - _kernel.RegisterMultiple( new List { diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index ea2d6dee2..2ebdb6244 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -23,7 +23,8 @@ using CoiniumServ.Factories; using CoiniumServ.Net.Server.Http.Web; -using CoiniumServ.Repository.Context; +using Nancy.Bootstrapper; +using Serilog; namespace CoiniumServ.Server.Web { @@ -31,9 +32,13 @@ public class WebServer : HttpServer, IWebServer { public IWebServerConfig Config { get; private set; } - public WebServer(IApplicationContext applicationContext, IConfigFactory configFactory) - : base(applicationContext) + private readonly ILogger _logger; + + public WebServer(INancyBootstrapper webBootstrapper, IConfigFactory configFactory) + : base(webBootstrapper) { + _logger = Log.ForContext(); + Config = configFactory.GetWebServerConfig(); BindIP = Config.BindInterface; @@ -41,6 +46,8 @@ public WebServer(IApplicationContext applicationContext, IConfigFactory configFa if (Config.Enabled) Start(); + else + _logger.Verbose("Skipping web-server initialization as it disabled."); } } } diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-sample.json index 2393eb260..850ef8e9a 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-sample.json @@ -1,6 +1,6 @@ { # website configuration - "web": { + "website": { "enabled": true, "bind": "127.0.0.1", "port": 91 @@ -17,7 +17,7 @@ } }, - # log configuration + # logging configuration "logging": { "root": "logs", "targets": [ diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index e518ea735..91adcca5d 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -89,8 +89,6 @@ Block Status Amount - Hash - TxHash @@ -114,8 +112,6 @@ } @block.Amount - @block.BlockHash.Substring(0, block.BlockHash.Length > 10 ? 10 : block.BlockHash.Length).. - @block.TransactionHash.Substring(0, block.TransactionHash.Length > 10 ? 10 : block.TransactionHash.Length).. } From 957fab8902a9bb1ca5d132438a36e85c288a7837 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 17:45:04 +0300 Subject: [PATCH 110/230] Misc /api fixes & improvements. Removed coinconfigfactory, poolconfigfactory. Fixed configfactory.cs implementation. We have now a central configmanager object that's responsible for loading & parsing configs. PoolManager doesn't handle loading of pool configs any more. Closes #247. --- .../Coin/Config/CoinConfigFactory.cs | 53 -------- src/CoiniumServ/CoiniumServ.csproj | 10 +- src/CoiniumServ/Factories/ConfigFactory.cs | 46 ++++--- src/CoiniumServ/Factories/IConfigFactory.cs | 16 +-- src/CoiniumServ/Factories/ObjectFactory.cs | 1 + .../Mining/Pools/Config/IPoolConfigFactory.cs | 37 ------ .../Mining/Pools/Config/PoolConfig.cs | 8 +- .../Mining/Pools/Config/PoolConfigFactory.cs | 62 ---------- src/CoiniumServ/Mining/Pools/IPoolManager.cs | 6 +- src/CoiniumServ/Mining/Pools/PoolManager.cs | 69 ++--------- .../Mining/Pools/Statistics/Algorithms.cs | 6 +- .../Mining/Pools/Statistics/IPerPool.cs | 3 + .../Mining/Pools/Statistics/IPools.cs | 1 + .../Mining/Pools/Statistics/PerPool.cs | 16 ++- .../Mining/Pools/Statistics/Pools.cs | 13 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 4 +- src/CoiniumServ/Program.cs | 8 +- .../Repository/Registries/ClassRegistry.cs | 2 + .../Repository/Registries/FactoryRegistry.cs | 5 - .../Repository/Registries/ManagerRegistry.cs | 2 + src/CoiniumServ/Server/Web/IWebServer.cs | 4 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 3 +- src/CoiniumServ/Server/Web/Modules/Index.cs | 4 +- src/CoiniumServ/Server/Web/WebServer.cs | 17 ++- .../Utils/Configuration/ConfigManager.cs | 114 ++++++++++++++++++ .../Configuration/IConfigManager.cs} | 28 +++-- .../{ILoggingConfig.cs => ILogConfig.cs} | 2 +- .../{LoggingConfig.cs => LogConfig.cs} | 4 +- src/CoiniumServ/Utils/Logging/LogManager.cs | 7 +- 29 files changed, 239 insertions(+), 312 deletions(-) delete mode 100644 src/CoiniumServ/Coin/Config/CoinConfigFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs delete mode 100644 src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs create mode 100644 src/CoiniumServ/Utils/Configuration/ConfigManager.cs rename src/CoiniumServ/{Coin/Config/ICoinConfigFactory.cs => Utils/Configuration/IConfigManager.cs} (67%) rename src/CoiniumServ/Utils/Logging/{ILoggingConfig.cs => ILogConfig.cs} (97%) rename src/CoiniumServ/Utils/Logging/{LoggingConfig.cs => LogConfig.cs} (93%) diff --git a/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs b/src/CoiniumServ/Coin/Config/CoinConfigFactory.cs deleted file mode 100644 index f56e83dbb..000000000 --- a/src/CoiniumServ/Coin/Config/CoinConfigFactory.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 - -using CoiniumServ.Repository.Context; -using CoiniumServ.Utils.Configuration; - -namespace CoiniumServ.Coin.Config -{ - public class CoinConfigFactory : ICoinConfigFactory - { - /// - /// The _application context - /// - private IApplicationContext _applicationContext; - - public CoinConfigFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - - public ICoinConfig GetConfig(string name) - { - var fileName = string.Format("config/coins/{0}.json", name); - var file = JsonConfigReader.Read(fileName); - - if (file == null) - return null; - - return new CoinConfig(file); - } - } -} diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index c663be67b..27cf77f56 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -204,6 +204,8 @@ + + @@ -233,8 +235,6 @@ - - @@ -243,10 +243,10 @@ - + - + @@ -258,9 +258,7 @@ - - diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs index 39f39593b..fb06dde07 100644 --- a/src/CoiniumServ/Factories/ConfigFactory.cs +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -21,11 +21,11 @@ // #endregion -using CoiniumServ.Persistance.Redis; +using CoiniumServ.Coin.Config; +using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Repository.Context; -using CoiniumServ.Server.Web; using CoiniumServ.Utils.Configuration; -using CoiniumServ.Utils.Logging; +using Nancy.TinyIoc; namespace CoiniumServ.Factories { @@ -34,44 +34,40 @@ namespace CoiniumServ.Factories /// public class ConfigFactory:IConfigFactory { - public bool GlobalConfigExists { get { return _globalConfigData != null; }} - public dynamic Logging { get { return _globalConfigData.logging; } } - - private const string GlobalConfigFilename = "config/config.json"; // global config filename. - private readonly dynamic _globalConfigData; // global config data. - - private readonly IRedisConfig _redisConfig; - private readonly IWebServerConfig _webServerConfig; - private readonly ILoggingConfig _logConfig; - /// /// The _application context /// - private IApplicationContext _applicationContext; + private readonly IApplicationContext _applicationContext; public ConfigFactory(IApplicationContext applicationContext) { _applicationContext = applicationContext; - _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. - _redisConfig = new RedisConfig(_globalConfigData.storage.redis); - _webServerConfig = new WebServerConfig(_globalConfigData.website); - _logConfig = new LoggingConfig(_globalConfigData.logging); } - // todo: should be per-pool! - public IRedisConfig GetRedisConfig() + public IConfigManager GetConfigManager() { - return _redisConfig; + return _applicationContext.Container.Resolve(); } - public IWebServerConfig GetWebServerConfig() + public IPoolConfig GetPoolConfig(dynamic config, ICoinConfig coinConfig) { - return _webServerConfig; + var @params = new NamedParameterOverloads + { + {"config", config}, + {"coinConfig", coinConfig} + }; + + return _applicationContext.Container.Resolve(@params); } - public ILoggingConfig GetLoggingConfig() + public ICoinConfig GetCoinConfig(dynamic config) { - return _logConfig; + var @params = new NamedParameterOverloads + { + {"config", config}, + }; + + return _applicationContext.Container.Resolve(@params); } } } diff --git a/src/CoiniumServ/Factories/IConfigFactory.cs b/src/CoiniumServ/Factories/IConfigFactory.cs index fc15c39ad..5fec6f1f2 100644 --- a/src/CoiniumServ/Factories/IConfigFactory.cs +++ b/src/CoiniumServ/Factories/IConfigFactory.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Persistance.Redis; -using CoiniumServ.Server.Web; -using CoiniumServ.Utils.Logging; +using CoiniumServ.Coin.Config; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Factories { @@ -32,14 +32,10 @@ namespace CoiniumServ.Factories /// public interface IConfigFactory { - bool GlobalConfigExists { get; } + IConfigManager GetConfigManager(); - dynamic Logging { get; } + IPoolConfig GetPoolConfig(dynamic config, ICoinConfig coinConfig); - IRedisConfig GetRedisConfig(); - - IWebServerConfig GetWebServerConfig(); - - ILoggingConfig GetLoggingConfig(); + ICoinConfig GetCoinConfig(dynamic config); } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index d1ab66b7f..45949b832 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -289,6 +289,7 @@ public IRpcService GetMiningService(string type, ICoinConfig coinConfig, IShareM {"shareManager", shareManager}, {"daemonClient", daemonClient} }; + return _applicationContext.Container.Resolve(type, @params); } diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs deleted file mode 100644 index 2bcd773cd..000000000 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfigFactory.cs +++ /dev/null @@ -1,37 +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.Mining.Pools.Config -{ - /// - /// Returns an instance of IPoolConfig based on the parsed config file - /// - public interface IPoolConfigFactory - { - /// - /// Gets the specified read configuration. - /// - /// The read configuration. - /// - IPoolConfig Get(dynamic readConfig); - } -} diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 2c5111952..607be8341 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -24,6 +24,7 @@ using System.IO; using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; +using CoiniumServ.Factories; using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Vanilla.Config; @@ -60,9 +61,9 @@ public class PoolConfig : IPoolConfig /// /// Initializes a new instance of the class. /// - /// The coin configuration factory. /// The configuration. - public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) + /// + public PoolConfig(dynamic config, ICoinConfig coinConfig) { if (config == null) { @@ -78,8 +79,7 @@ public PoolConfig(ICoinConfigFactory coinConfigFactory, dynamic config) Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); - var coinName = Path.GetFileNameWithoutExtension(config.coin); - Coin = coinConfigFactory.GetConfig(coinName); + Coin = coinConfig; if (Coin == null) { diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs deleted file mode 100644 index d16957be2..000000000 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfigFactory.cs +++ /dev/null @@ -1,62 +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 CoiniumServ.Coin.Config; -using CoiniumServ.Repository.Context; -using Nancy.TinyIoc; - -namespace CoiniumServ.Mining.Pools.Config -{ - public class PoolConfigFactory : IPoolConfigFactory - { - /// - /// The _application context - /// - private readonly IApplicationContext _applicationContext; - - /// - /// Initializes a new instance of the class. - /// - /// The application context. - public PoolConfigFactory(IApplicationContext applicationContext) - { - _applicationContext = applicationContext; - } - - /// - /// Gets the specified read configuration. - /// - /// The read configuration. - /// - public IPoolConfig Get(dynamic readConfig) - { - var @params = new NamedParameterOverloads - { - { "coinConfigFactory", _applicationContext.Container.Resolve() }, - { "config", readConfig } - }; - - return _applicationContext.Container.Resolve(@params); - } - } -} diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Mining/Pools/IPoolManager.cs index bdc37a8e6..041de1b3e 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/IPoolManager.cs @@ -22,19 +22,15 @@ #endregion using System.Collections.Generic; -using CoiniumServ.Mining.Pools.Config; namespace CoiniumServ.Mining.Pools { public interface IPoolManager { - - IList GetPools(); + IReadOnlyCollection Pools { get; } IPool GetBySymbol(string symbol); - IPool AddPool(IPoolConfig poolConfig); - void Run(); } } diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Mining/Pools/PoolManager.cs index 2d2938cdf..990791f52 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Mining/Pools/PoolManager.cs @@ -25,86 +25,41 @@ using System.Collections.Generic; using System.Linq; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Utils.Configuration; -using CoiniumServ.Utils.Helpers.IO; using Serilog; namespace CoiniumServ.Mining.Pools { public class PoolManager : IPoolManager { - private readonly List _pools = new List(); + public IReadOnlyCollection Pools { get { return _pools.Values.ToList(); } } - private readonly IObjectFactory _objectFactory; - - private readonly IPoolConfigFactory _poolConfigFactory; + private readonly Dictionary _pools; private readonly ILogger _logger; - public PoolManager(IObjectFactory objectFactory, IPoolConfigFactory poolConfigFactory) + public PoolManager(IObjectFactory objectFactory , IConfigManager configManager) { - _objectFactory = objectFactory; - _poolConfigFactory = poolConfigFactory; _logger = Log.ForContext(); - } - - public void Run() - { - // load pool configs. - LoadConfigs(); + _pools = new Dictionary(); - // run pools. - foreach (var pool in _pools) + foreach (var config in configManager.PoolConfigs) { - pool.Start(); - } - } - - public void LoadConfigs() - { - const string configRoot = "config/pools"; - - var files = FileHelpers.GetFilesByExtensionRecursive(configRoot, ".json"); - - var pools = new List(); - var names = new List(); - - foreach (var file in files) - { - var poolConfig = _poolConfigFactory.Get(JsonConfigReader.Read(file)); - - if (!poolConfig.Enabled) // skip pools that are not enabled. - continue; - - pools.Add(poolConfig); - names.Add(poolConfig.Coin.Name); - } - - _logger.Information("Discovered a total of {0} enabled pool configurations: {1}.", pools.Count, names); - - foreach (var config in pools) - { - AddPool(config); + _pools.Add(config.Coin.Symbol, objectFactory.GetPool(config)); } } public IPool GetBySymbol(string symbol) { - return _pools.FirstOrDefault(pool => pool.Config.Coin.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase)); + return _pools.Values.FirstOrDefault(pair => pair.Config.Coin.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase)); } - public IPool AddPool(IPoolConfig poolConfig) - { - var pool = _objectFactory.GetPool(poolConfig); - _pools.Add(pool); - - return pool; - } - - public IList GetPools() + public void Run() { - return _pools; + foreach (var kvp in _pools) + { + kvp.Value.Start(); + } } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs index 5f39d3413..6ce2978dc 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs @@ -21,8 +21,10 @@ // #endregion +using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; namespace CoiniumServ.Mining.Pools.Statistics @@ -50,7 +52,7 @@ public void Recache(object state) pair.Value.Reset(); } - foreach (var pool in _poolManager.GetPools()) + foreach (var pool in _poolManager.Pools) { if (!_algorithms.ContainsKey(pool.Config.Coin.Algorithm)) _algorithms.Add(pool.Config.Coin.Algorithm, new PerAlgorithm(pool.Config.Coin.Algorithm)); @@ -72,7 +74,7 @@ public void Recache(object state) public IPerAlgorithm GetByName(string name) { - return !_algorithms.ContainsKey(name) ? null : _algorithms[name]; + return _algorithms.Values.FirstOrDefault(pair => pair.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); } public IEnumerator> GetEnumerator() diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs index 86caacc22..b83b42058 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs @@ -22,6 +22,7 @@ #endregion using System; +using CoiniumServ.Mining.Pools.Config; namespace CoiniumServ.Mining.Pools.Statistics { @@ -38,5 +39,7 @@ public interface IPerPool:IJsonResponse, IStatisticsProvider int CurrentBlock { get; } IBlocks Blocks { get; } + + IPoolConfig Config { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs index 84d1b40ce..1db85a011 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs @@ -27,5 +27,6 @@ namespace CoiniumServ.Mining.Pools.Statistics { public interface IPools : IEnumerable>,IJsonResponse, IStatisticsProvider { + IPerPool GetBySymbol(string symbol); } } diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs index 63daadf99..b218cf6d7 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs @@ -42,14 +42,13 @@ public class PerPool:IPerPool public double Difficulty { get; private set; } public int CurrentBlock { get; private set; } public IBlocks Blocks { get; private set; } + public IPoolConfig Config { get; private set; } public string Json { get; private set; } private readonly IDaemonClient _daemonClient; private readonly IStorage _storage; - private readonly IHashAlgorithm _hashAlgorithm; private readonly IMinerManager _minerManager; - private readonly IPoolConfig _poolConfig; private readonly dynamic _response; private readonly double _shareMultiplier; @@ -57,15 +56,14 @@ public class PerPool:IPerPool public PerPool(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) { - _poolConfig = poolConfig; - _daemonClient = daemonClient; - _hashAlgorithm = hashAlgorithm; + Config = poolConfig; + _daemonClient = daemonClient; _minerManager = minerManager; Blocks = blockStatistics; _storage = storage; _response = new ExpandoObject(); - _shareMultiplier = Math.Pow(2, 32) / _hashAlgorithm.Multiplier; + _shareMultiplier = Math.Pow(2, 32) / hashAlgorithm.Multiplier; } public void Recache(object state) @@ -82,9 +80,9 @@ public void Recache(object state) _response.hashrate = Hashrate; _response.coin = new ExpandoObject(); - _response.coin.symbol = _poolConfig.Coin.Symbol; - _response.coin.name = _poolConfig.Coin.Name; - _response.coin.algorithm = _poolConfig.Coin.Algorithm; + _response.coin.symbol = Config.Coin.Symbol; + _response.coin.name = Config.Coin.Name; + _response.coin.algorithm = Config.Coin.Algorithm; _response.network = new ExpandoObject(); _response.network.currentBlock = CurrentBlock; diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs index d7e169ad6..fa9b2ce05 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs +++ b/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs @@ -21,9 +21,11 @@ // #endregion +using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; +using System.Linq; using Newtonsoft.Json; namespace CoiniumServ.Mining.Pools.Statistics @@ -42,12 +44,17 @@ public Pools(IPoolManager poolManager) _pools = new Dictionary(); _response = new Dictionary(); - foreach (var pool in poolManager.GetPools()) + foreach (var pool in poolManager.Pools) { _pools.Add(pool.Config.Coin.Name, pool.Statistics); } } + public IPerPool GetBySymbol(string symbol) + { + return _pools.Values.FirstOrDefault(pair => pair.Config.Coin.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase)); + } + public IEnumerator> GetEnumerator() { return _pools.GetEnumerator(); @@ -61,7 +68,7 @@ IEnumerator IEnumerable.GetEnumerator() public void Recache(object state) { // recache data. - foreach (var pool in _poolManager.GetPools()) + foreach (var pool in _poolManager.Pools) { pool.Statistics.Recache(state); } @@ -69,7 +76,7 @@ public void Recache(object state) // recache response. _response.Clear(); - foreach (var pool in _poolManager.GetPools()) + foreach (var pool in _poolManager.Pools) { _response.Add(pool.Config.Coin.Symbol.ToLower(), (ExpandoObject)pool.Statistics.GetResponseObject()); } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index 964cc4e9f..f44cba1ec 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -55,12 +55,12 @@ public class Redis:IStorage, IRedis private readonly ILogger _logger; - public Redis(ConfigFactory configFactory, IPoolConfig poolConfig) + public Redis(IConfigManager configManager, IPoolConfig poolConfig) { _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); _poolConfig = poolConfig; // the pool config. - _redisConfig = configFactory.GetRedisConfig(); // read the redis config. + _redisConfig = configManager.RedisConfig; // read the redis config. IsEnabled = _redisConfig.Enabled; diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 93cb60612..6970ae1da 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -59,14 +59,15 @@ static void Main(string[] args) var kernel = TinyIoCContainer.Current; var bootstrapper = new Bootstrapper(kernel); var objectFactory = kernel.Resolve(); + var configFactory = kernel.Resolve(); // print intro texts. ConsoleWindow.PrintBanner(); ConsoleWindow.PrintLicense(); // check if we have a valid config file. - var configFactory = kernel.Resolve(); - if (!configFactory.GlobalConfigExists) + var configManager = configFactory.GetConfigManager(); + if (!configManager.ConfigExists) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Couldn't read config/config.json! Make sure you rename config/config-sample.json as config/config.json."); @@ -83,6 +84,9 @@ static void Main(string[] args) _logger.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); PlatformManager.PrintPlatformBanner(); + // initialize config manager. + configManager.Initialize(); + // start pool manager. var poolManager = objectFactory.GetPoolManager(); poolManager.Run(); diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index 9a1442013..d89f5e29d 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Mining.Jobs.Tracker; using CoiniumServ.Mining.Pools; @@ -51,6 +52,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs index 3fa88d12b..62fe1170b 100644 --- a/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/FactoryRegistry.cs @@ -21,9 +21,7 @@ // #endregion -using CoiniumServ.Coin.Config; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Repository.Context; namespace CoiniumServ.Repository.Registries @@ -41,9 +39,6 @@ public void RegisterInstances() { _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index d3fd4da32..8aa0b8cfa 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -28,6 +28,7 @@ using CoiniumServ.Mining.Shares; using CoiniumServ.Mining.Vardiff; using CoiniumServ.Repository.Context; +using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Repository.Registries { @@ -49,6 +50,7 @@ public void RegisterInstances() _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Server/Web/IWebServer.cs b/src/CoiniumServ/Server/Web/IWebServer.cs index 22f3aa33e..d8650e24d 100644 --- a/src/CoiniumServ/Server/Web/IWebServer.cs +++ b/src/CoiniumServ/Server/Web/IWebServer.cs @@ -26,7 +26,5 @@ namespace CoiniumServ.Server.Web { public interface IWebServer: IServer - { - IWebServerConfig Config { get; } - } + { } } diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index b41e2d56d..1573ee38a 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -38,9 +38,10 @@ public ApiModule(IPoolManager poolManager, IStatistics statistics) Get["/api/global"] = _ => Response.AsJson(statistics.Global.GetResponseObject()); Get["/api/pools"] = _ => Response.AsJson(statistics.Pools.GetResponseObject()); + Get["/api/pool/{slug}"] = _ => { - var pool = poolManager.GetBySymbol(_.slug); + var pool = statistics.Pools.GetBySymbol(_.slug); Response response; diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index 6af90f436..4feced4d7 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -34,7 +34,7 @@ public IndexModule(IPoolManager poolManager, IStatistics statistics) { Get["/"] = _ => View["index", new IndexModel { - Pools = poolManager.GetPools(), + Pools = poolManager.Pools, Statistics = statistics, }]; } @@ -42,7 +42,7 @@ public IndexModule(IPoolManager poolManager, IStatistics statistics) public class IndexModel { - public IList Pools { get; set; } + public IReadOnlyCollection Pools { get; set; } public IStatistics Statistics { get; set; } } diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 2ebdb6244..69b25fd88 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -21,8 +21,8 @@ // #endregion -using CoiniumServ.Factories; using CoiniumServ.Net.Server.Http.Web; +using CoiniumServ.Utils.Configuration; using Nancy.Bootstrapper; using Serilog; @@ -30,21 +30,18 @@ namespace CoiniumServ.Server.Web { public class WebServer : HttpServer, IWebServer { - public IWebServerConfig Config { get; private set; } - private readonly ILogger _logger; - public WebServer(INancyBootstrapper webBootstrapper, IConfigFactory configFactory) + public WebServer(INancyBootstrapper webBootstrapper, IConfigManager configManager) : base(webBootstrapper) { - _logger = Log.ForContext(); + var config = configManager.WebServerConfig; + BindIP = config.BindInterface; + Port = config.Port; - Config = configFactory.GetWebServerConfig(); + _logger = Log.ForContext(); - BindIP = Config.BindInterface; - Port = Config.Port; - - if (Config.Enabled) + if (config.Enabled) Start(); else _logger.Verbose("Skipping web-server initialization as it disabled."); diff --git a/src/CoiniumServ/Utils/Configuration/ConfigManager.cs b/src/CoiniumServ/Utils/Configuration/ConfigManager.cs new file mode 100644 index 000000000..83c3ced7d --- /dev/null +++ b/src/CoiniumServ/Utils/Configuration/ConfigManager.cs @@ -0,0 +1,114 @@ +#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.IO; +using System.Linq; +using CoiniumServ.Coin.Config; +using CoiniumServ.Factories; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Helpers.IO; +using CoiniumServ.Utils.Logging; +using Serilog; + +namespace CoiniumServ.Utils.Configuration +{ + public class ConfigManager:IConfigManager + { + public bool ConfigExists { get { return _globalConfigData != null; } } + public IRedisConfig RedisConfig { get; private set; } + public IWebServerConfig WebServerConfig { get; private set; } + public ILogConfig LogConfig { get; private set; } + + public List PoolConfigs { get; private set; } + + private const string GlobalConfigFilename = "config/config.json"; // global config filename. + private const string PoolConfigRoot = "config/pools"; // root of pool configs. + private const string CoinConfigRoot = "config/coins"; // root of pool configs. + + private readonly Dictionary _coinConfigs; // cache for loaded coin configs. + + private readonly dynamic _globalConfigData; // global config data. + private readonly IConfigFactory _configFactory; + private ILogger _logger; + + public ConfigManager(IConfigFactory configFactory) + { + _configFactory = configFactory; + + _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. + PoolConfigs = new List(); + _coinConfigs = new Dictionary(); + + LogConfig = new LogConfig(_globalConfigData.logging); + RedisConfig = new RedisConfig(_globalConfigData.storage.redis); + WebServerConfig = new WebServerConfig(_globalConfigData.website); + } + + public void Initialize() + { + _logger = Log.ForContext(); + + LoadPoolConfigs(); + } + + private void LoadPoolConfigs() + { + _logger.Verbose("Discovering enabled pool configs.."); + + var files = FileHelpers.GetFilesByExtensionRecursive(PoolConfigRoot, ".json"); + + foreach (var file in files) + { + var data = JsonConfigReader.Read(file); + + if (!data.enabled) // skip pools that are not enabled. + continue; + + var coinName = Path.GetFileNameWithoutExtension(data.coin); + var coinConfig = GetCoinConfig(coinName); + + PoolConfigs.Add(_configFactory.GetPoolConfig(data, coinConfig)); + } + + _logger.Information("Discovered a total of {0} enabled pool configurations: {1:l}", PoolConfigs.Count, + PoolConfigs.Select(config => config.Coin.Name).ToList()); + } + + private ICoinConfig GetCoinConfig(string name) + { + if (!_coinConfigs.ContainsKey(name)) + { + var fileName = string.Format("{0}/{1}.json", CoinConfigRoot, name); + var data = JsonConfigReader.Read(fileName); + var coinConfig = _configFactory.GetCoinConfig(data); + + _coinConfigs.Add(name, coinConfig); + } + + return _coinConfigs[name]; + } + } +} diff --git a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs similarity index 67% rename from src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs rename to src/CoiniumServ/Utils/Configuration/IConfigManager.cs index f31052ffc..a747e320c 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfigFactory.cs +++ b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs @@ -20,15 +20,27 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Coin.Config + +using System.Collections.Generic; +using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Persistance.Redis; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Logging; + +namespace CoiniumServ.Utils.Configuration { - public interface ICoinConfigFactory + public interface IConfigManager { - /// - /// Gets the configuration. - /// - /// The name. - /// - ICoinConfig GetConfig(string name); + bool ConfigExists { get; } + + IRedisConfig RedisConfig { get; } + + IWebServerConfig WebServerConfig { get; } + + ILogConfig LogConfig { get; } + + List PoolConfigs { get; } + + void Initialize(); } } diff --git a/src/CoiniumServ/Utils/Logging/ILoggingConfig.cs b/src/CoiniumServ/Utils/Logging/ILogConfig.cs similarity index 97% rename from src/CoiniumServ/Utils/Logging/ILoggingConfig.cs rename to src/CoiniumServ/Utils/Logging/ILogConfig.cs index 6f5873877..e72cda913 100644 --- a/src/CoiniumServ/Utils/Logging/ILoggingConfig.cs +++ b/src/CoiniumServ/Utils/Logging/ILogConfig.cs @@ -25,7 +25,7 @@ namespace CoiniumServ.Utils.Logging { - public interface ILoggingConfig + public interface ILogConfig { string Root { get; } diff --git a/src/CoiniumServ/Utils/Logging/LoggingConfig.cs b/src/CoiniumServ/Utils/Logging/LogConfig.cs similarity index 93% rename from src/CoiniumServ/Utils/Logging/LoggingConfig.cs rename to src/CoiniumServ/Utils/Logging/LogConfig.cs index b39a6d033..b92bbe144 100644 --- a/src/CoiniumServ/Utils/Logging/LoggingConfig.cs +++ b/src/CoiniumServ/Utils/Logging/LogConfig.cs @@ -25,12 +25,12 @@ namespace CoiniumServ.Utils.Logging { - public class LoggingConfig : ILoggingConfig + public class LogConfig : ILogConfig { public string Root { get; private set; } public List Targets { get; private set; } - public LoggingConfig(dynamic config) + public LogConfig(dynamic config) { Root = config.root; diff --git a/src/CoiniumServ/Utils/Logging/LogManager.cs b/src/CoiniumServ/Utils/Logging/LogManager.cs index af3298524..0d58b7f83 100644 --- a/src/CoiniumServ/Utils/Logging/LogManager.cs +++ b/src/CoiniumServ/Utils/Logging/LogManager.cs @@ -24,6 +24,7 @@ using System.IO; using System.Linq; using CoiniumServ.Factories; +using CoiniumServ.Utils.Configuration; using Serilog; using Serilog.Core; using Serilog.Events; @@ -39,11 +40,11 @@ public class LogManager:ILogManager private string _rootFolder; - private readonly ILoggingConfig _config; + private readonly ILogConfig _config; - public LogManager(IConfigFactory configFactory) + public LogManager(IConfigManager configManager) { - _config = configFactory.GetLoggingConfig(); + _config = configManager.LogConfig; } public void Initialize() From 472fc88e9328eaf6467fe2206ffe145886ea64ee Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 18:19:39 +0300 Subject: [PATCH 111/230] Added a sample-detailed.json file that explicitly sets all settings. sample.json file will now only set settings specific to a pool. added default.json file for default pool settings. --- src/CoiniumServ/CoiniumServ.csproj | 6 ++ .../Mining/Pools/Config/PoolConfig.cs | 2 + src/CoiniumServ/config/config-sample.json | 2 +- src/CoiniumServ/config/pools/default.json | 62 +++++++++++++ .../config/pools/sample-detailed.json | 87 +++++++++++++++++++ src/CoiniumServ/config/pools/sample.json | 38 +++----- 6 files changed, 172 insertions(+), 25 deletions(-) create mode 100644 src/CoiniumServ/config/pools/default.json create mode 100644 src/CoiniumServ/config/pools/sample-detailed.json diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 27cf77f56..0579ae3b9 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -783,6 +783,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 607be8341..da433cfba 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -65,6 +65,8 @@ public class PoolConfig : IPoolConfig /// public PoolConfig(dynamic config, ICoinConfig coinConfig) { + // todo - read per pool redis config. + if (config == null) { Valid = false; diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-sample.json index 850ef8e9a..be4ebebf1 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-sample.json @@ -6,7 +6,7 @@ "port": 91 }, - # storage configuration. + # global storage configuration. "storage": { "redis": { "enabled": true, diff --git a/src/CoiniumServ/config/pools/default.json b/src/CoiniumServ/config/pools/default.json new file mode 100644 index 000000000..9302184e7 --- /dev/null +++ b/src/CoiniumServ/config/pools/default.json @@ -0,0 +1,62 @@ +{ + # default pool configuration + # if a per-pool config file doesn't override a setting, default value from this file will be applied + + # coin daemon connection configuration + "daemon": { + "host": "127.0.0.1" + }, + + # payment processing configuration + "payments": { + "interval": 60, + "minimum": 1 + }, + + # stratum server configuration + "stratum": { + "bind": "0.0.0.0", + "diff": 16, + "vardiff": { + "minDiff": 8, + "maxDiff": 512, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + }, + + # vanilla server configuration - experimental! + "vanilla": { + "bind": "localhost" + }, + + # banning support + "banning": { + "enabled": true, + "duration": 600, + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 + }, + + # per-pool storage configuration + "storage": { + "redis": { + "host": "127.0.0.1", + "port": 6379, + "password": "", + "databaseId": 0 + } + }, + + # mpos compat mode configuration - not implemented yet! + "mpos": { + "database": { + "host": "127.0.0.1", + "port": 3306, + "user": "username", + "password": "password" + } + } +} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/sample-detailed.json b/src/CoiniumServ/config/pools/sample-detailed.json new file mode 100644 index 000000000..6b75ca212 --- /dev/null +++ b/src/CoiniumServ/config/pools/sample-detailed.json @@ -0,0 +1,87 @@ +{ + # detailed sample config file for pool which explicility defines all settings + + "enabled": false, + + "coin": "litecoin.json", + + # central wallet configuration + "wallet" : { + "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" + }, + + # coin daemon connection configuration + "daemon": { + "host": "127.0.0.1", + "port": 9333, + "username": "user", + "password": "password" + }, + + # rewards configuration + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + + # payment processing configuration + "payments": { + "enabled": true, + "interval": 60, + "minimum": 1 + }, + + # stratum server configuration + "stratum": { + "enabled": true, + "bind": "0.0.0.0", + "port": 3333, + "diff": 16, + "vardiff": { + "enabled": true, + "minDiff": 8, + "maxDiff": 512, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + }, + + # vanilla server configuration - experimental! + "vanilla": { + "enabled": false, + "bind": "localhost", + "port": 2223 + }, + + # banning support + "banning": { + "enabled": true, + "duration": 600, + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 + }, + + # per-pool storage configuration + "storage": { + "redis": { + "enabled": true, + "host": "127.0.0.1", + "port": 6379, + "password": "", + "databaseId": 0 + } + }, + + # mpos compat mode configuration - not implemented yet! + "mpos": { + "enabled": false, + "database": { + "host": "127.0.0.1", + "port": 3306, + "name": "db-name", + "user": "username", + "password": "password" + } + } +} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index e9c3b0717..ca0472c76 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -1,4 +1,6 @@ -{ +{ + # sample pool config file that only sets specific settings for the pool and gets the others from default.json + "enabled": false, "coin": "litecoin.json", @@ -10,7 +12,6 @@ # coin daemon connection configuration "daemon": { - "host": "127.0.0.1", "port": 9333, "username": "user", "password": "password" @@ -23,52 +24,41 @@ # payment processing configuration "payments": { - "enabled": true, - "interval": 60, - "minimum": 1 + "enabled": true }, # stratum server configuration "stratum": { "enabled": true, - "bind": "0.0.0.0", "port": 3333, - "diff": 16, "vardiff": { - "enabled": true, - "minDiff": 8, - "maxDiff": 512, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30 + "enabled": true } }, # vanilla server configuration - experimental! "vanilla": { "enabled": false, - "bind": "localhost", "port": 2223 }, # banning support "banning": { - "enabled": true, - "duration": 600, - "invalidPercent": 50, - "checkThreshold": 500, - "purgeInterval": 300 + "enabled": true }, + # per-pool storage config + "storage": { + "redis": { + "enabled": true + } + }, + # mpos compat mode configuration - not implemented yet! "mpos": { "enabled": false, "database": { - "host": "127.0.0.1", - "port": 3306, - "name": "db-name", - "user": "username", - "password": "password" + "name": "db-name" } } } \ No newline at end of file From e39a02206db8942e9164cf6aa72a1f9f7e634543 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Mon, 21 Jul 2014 18:48:14 +0300 Subject: [PATCH 112/230] Started documenting config files. Added new config options to be implemented. --- src/CoiniumServ/config/pools/default.json | 10 +-- .../config/pools/sample-detailed.json | 84 ++++++++++++++++--- src/CoiniumServ/config/pools/sample.json | 13 ++- 3 files changed, 84 insertions(+), 23 deletions(-) diff --git a/src/CoiniumServ/config/pools/default.json b/src/CoiniumServ/config/pools/default.json index 9302184e7..b4705183d 100644 --- a/src/CoiniumServ/config/pools/default.json +++ b/src/CoiniumServ/config/pools/default.json @@ -2,17 +2,17 @@ # default pool configuration # if a per-pool config file doesn't override a setting, default value from this file will be applied - # coin daemon connection configuration - "daemon": { - "host": "127.0.0.1" - }, - # payment processing configuration "payments": { "interval": 60, "minimum": 1 }, + # coin daemon connection configuration + "daemon": { + "host": "127.0.0.1" + }, + # stratum server configuration "stratum": { "bind": "0.0.0.0", diff --git a/src/CoiniumServ/config/pools/sample-detailed.json b/src/CoiniumServ/config/pools/sample-detailed.json index 6b75ca212..fd31a1f99 100644 --- a/src/CoiniumServ/config/pools/sample-detailed.json +++ b/src/CoiniumServ/config/pools/sample-detailed.json @@ -1,16 +1,34 @@ { - # detailed sample config file for pool which explicility defines all settings + # detailed sample config file for pool which explicility sets all settings - "enabled": false, - + "enabled": false, "coin": "litecoin.json", - # central wallet configuration + # ------------------------------- + # Wallet & Rewards Configuration + # ------------------------------- + + # address: generated coins will arrive here. + "wallet" : { "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" }, - # coin daemon connection configuration + # rewards: list of addresses that gets a percentage from each mined block (ie, pool fee.) + + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + + # ------------------------------- + # Coin Daemon RPC Connection + # ------------------------------- + + # host: ip/hostname of coin-daemon. + # port: the port coin daemon is listening on. + # username: username for rpc connection. + # password: password for rpc connection. + "daemon": { "host": "127.0.0.1", "port": 9333, @@ -18,19 +36,56 @@ "password": "password" }, - # rewards configuration - "rewards": [ - {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} - ], + # ------------------------------- + # Payment Processing Configuration + # ------------------------------- + + # enabled: Set this true to let CoiniumServ handle the payments, false if you would like some other software like mpos to handle them. + # interval: Interval in seconds that payment-processor will be running. + # minimum: Minimum amount of coins before a miner is eligable for getting a payment. - # payment processing configuration "payments": { "enabled": true, "interval": 60, "minimum": 1 }, - # stratum server configuration + # ------------------------------- + # Job Manager Configuration + # ------------------------------- + + "jobs": { + "blockRefresh": 1000, + "rebroadcast": 55 + }, + + # ------------------------------- + # Miner Manager Configuration + # ------------------------------- + + "miners": { + "timeout": 600, + "validateUsernames": "true" + }, + + # ------------------------------- + # Stratum Server Configuration + # ------------------------------- + + # stratum: + # enabled: Set this true to enable stratum server. + # bind: Interface to bind stratum server. + # port: Port to listen for stratum connections. + # diff: Default difficulty assigned to newly connected miners. + + # vardiff: + # enabled: Set this true to enable variable-difficulty support. + # minDiff: Minimum difficulty that can be assigned to miners. + # maxDiff: Maximum difficulty that can be assigned to miners. + # targetTime: Try to get a single share per this many seconds from miner. + # retargetTime: Retarget a miners difficulty ever this many seconds. + # variancePercent: Allow difficulty for a miner to vary this percent without retargeting. + "stratum": { "enabled": true, "bind": "0.0.0.0", @@ -45,6 +100,13 @@ "variancePercent": 30 } }, + + # ------------------------------- + # Getwork Server Configuration + # ------------------------------- + + # EXPERIMENTAL!; This feature is still in development and still not complete yet. + # enabled: Set this true to enable getwork server. # vanilla server configuration - experimental! "vanilla": { diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json index ca0472c76..23e2ecec3 100644 --- a/src/CoiniumServ/config/pools/sample.json +++ b/src/CoiniumServ/config/pools/sample.json @@ -1,8 +1,7 @@ { # sample pool config file that only sets specific settings for the pool and gets the others from default.json - "enabled": false, - + "enabled": false, "coin": "litecoin.json", # central wallet configuration @@ -10,6 +9,11 @@ "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" }, + # rewards configuration + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + # coin daemon connection configuration "daemon": { "port": 9333, @@ -17,11 +21,6 @@ "password": "password" }, - # rewards configuration - "rewards": [ - {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} - ], - # payment processing configuration "payments": { "enabled": true From 613ca54f487d055406af93fe605f46c0f0b57856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 19:04:20 +0300 Subject: [PATCH 113/230] changed irc channels; #coiniumserv, #coiniumserv-dev --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2fd631fc2..9c85bd595 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) * Official site: [coiniumserv.com](http://www.coiniumserv.com) * [Support forums](http://forum.coinium.org/forum/19-support/) * IRC (**irc.freenode.net**): - - **#coinium-serv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) - - **#coinium-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) + - **#coiniumserv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) + - **#coiniumserv-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) * [Twitter](http://twitter.com/coinium) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) From 350af68a4f5c07778135d4f7089d9a970bd044b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 19:05:05 +0300 Subject: [PATCH 114/230] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c85bd595..1ab3d2ecd 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ You can also use our [issues](https://github.com/CoiniumServ/CoiniumServ/issues) * Official site: [coiniumserv.com](http://www.coiniumserv.com) * [Support forums](http://forum.coinium.org/forum/19-support/) * IRC (**irc.freenode.net**): - - **#coiniumserv** [user support](http://webchat.freenode.net/?channels=%23coinium-serv&prompt=1&uio=OT10cnVlde) - - **#coiniumserv-dev** [dev talk](http://webchat.freenode.net/?channels=%23coinium-dev&prompt=1&uio=OT10cnVlde) + - **#coiniumserv** [user support](http://webchat.freenode.net/?channels=%23coiniumserv&prompt=1&uio=OT10cnVlde) + - **#coiniumserv-dev** [dev talk](http://webchat.freenode.net/?channels=%23coiniumserv-dev&prompt=1&uio=OT10cnVlde) - **#coinium** [official pools](http://webchat.freenode.net/?channels=%23coinium&prompt=1&uio=OT10cnVlde) * [Twitter](http://twitter.com/coinium) * [Bitcointalk.org](https://bitcointalk.org/index.php?topic=604476.0) From a5f91e6f86ee8b35147f569986dffd39397b8f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 19:05:48 +0300 Subject: [PATCH 115/230] updated travis irc channel --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ccdb02b3a..c3915e2fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,5 @@ script: - chmod +x ./build/extra/run-tests.sh - ./build/extra/run-tests.sh notifications: - irc: chat.freenode.net#coinium-dev + irc: chat.freenode.net#coiniumserv-dev email: false From f9ff3e24703a4129215e4c1f4abc0e8e0e74cd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 21:33:59 +0300 Subject: [PATCH 116/230] more sample-detailed.json documentation. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- .../{default.json => default-sample.json} | 0 .../config/pools/sample-detailed.json | 143 +++++++++++------- 3 files changed, 90 insertions(+), 55 deletions(-) rename src/CoiniumServ/config/pools/{default.json => default-sample.json} (100%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 0579ae3b9..51ff867ab 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -783,7 +783,7 @@ PreserveNewest - + PreserveNewest diff --git a/src/CoiniumServ/config/pools/default.json b/src/CoiniumServ/config/pools/default-sample.json similarity index 100% rename from src/CoiniumServ/config/pools/default.json rename to src/CoiniumServ/config/pools/default-sample.json diff --git a/src/CoiniumServ/config/pools/sample-detailed.json b/src/CoiniumServ/config/pools/sample-detailed.json index fd31a1f99..eb9526abd 100644 --- a/src/CoiniumServ/config/pools/sample-detailed.json +++ b/src/CoiniumServ/config/pools/sample-detailed.json @@ -1,24 +1,8 @@ { - # detailed sample config file for pool which explicility sets all settings + # detailed sample config file for pool which explicility sets all settings. "enabled": false, - "coin": "litecoin.json", - - # ------------------------------- - # Wallet & Rewards Configuration - # ------------------------------- - - # address: generated coins will arrive here. - - "wallet" : { - "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" - }, - - # rewards: list of addresses that gets a percentage from each mined block (ie, pool fee.) - - "rewards": [ - {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} - ], + "coin": "litecoin.json", # ------------------------------- # Coin Daemon RPC Connection @@ -36,36 +20,59 @@ "password": "password" }, + # ------------------------------- + # Wallet & Rewards Configuration + # ------------------------------- + + # address: generated coins will arrive here. + + "wallet" : { + "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" + }, + + # rewards: list of addresses that gets a percentage from each mined block (ie, pool fee.) + + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + # ------------------------------- # Payment Processing Configuration # ------------------------------- - # enabled: Set this true to let CoiniumServ handle the payments, false if you would like some other software like mpos to handle them. - # interval: Interval in seconds that payment-processor will be running. - # minimum: Minimum amount of coins before a miner is eligable for getting a payment. + # enabled: set this true to let CoiniumServ handle the payments, false if you would like some other software like mpos to handle them. + # interval: interval in seconds that payment-processor will be running. + # minimum: minimum amount of coins before a miner is eligable for getting a payment. "payments": { "enabled": true, "interval": 60, - "minimum": 1 + "minimum": 0.01, }, # ------------------------------- - # Job Manager Configuration + # Miner Configuration # ------------------------------- - "jobs": { - "blockRefresh": 1000, - "rebroadcast": 55 + # validateUsername: set true to validate miner usernames as an addresses against the coin daemon. + # timeout: timeout in seconds to disconnect miners that did not submit any shares for the period. + + "miner": { + "validateUsername": "true", + "timeout": 300 }, # ------------------------------- - # Miner Manager Configuration + # Job Manager Configuration # ------------------------------- - "miners": { - "timeout": 600, - "validateUsernames": "true" + # blockRefresh: timeout in miliseconds to poll coin daemon for a new block. + # rebroadcast: if now new blocks are found in this many seconds, a new job will be created and broadcasted. + + + "jobs": { + "blockRefresh": 1000, + "rebroadcast": 55 }, # ------------------------------- @@ -73,18 +80,18 @@ # ------------------------------- # stratum: - # enabled: Set this true to enable stratum server. - # bind: Interface to bind stratum server. - # port: Port to listen for stratum connections. - # diff: Default difficulty assigned to newly connected miners. + # enabled: set this true to enable stratum server. + # bind: interface to bind stratum server. + # port: port to listen for stratum connections. + # diff: default difficulty assigned to newly connected miners. # vardiff: - # enabled: Set this true to enable variable-difficulty support. - # minDiff: Minimum difficulty that can be assigned to miners. - # maxDiff: Maximum difficulty that can be assigned to miners. - # targetTime: Try to get a single share per this many seconds from miner. - # retargetTime: Retarget a miners difficulty ever this many seconds. - # variancePercent: Allow difficulty for a miner to vary this percent without retargeting. + # enabled: set this true to enable variable-difficulty support. + # minDiff: minimum difficulty that can be assigned to miners. + # maxDiff: maximum difficulty that can be assigned to miners. + # targetTime: try to get a single share per this many seconds from miner. + # retargetTime: retarget a miners difficulty ever this many seconds. + # variancePercent: allow difficulty for a miner to vary this percent without retargeting. "stratum": { "enabled": true, @@ -100,22 +107,18 @@ "variancePercent": 30 } }, - + # ------------------------------- - # Getwork Server Configuration + # Ban Configuration # ------------------------------- - # EXPERIMENTAL!; This feature is still in development and still not complete yet. - # enabled: Set this true to enable getwork server. + # you can ban miners which submits invalid work / data to reduce system/network load. + # enabled: set this true to enable banning support. + # duration: duration of ban when a miner gets flagged for so. + # invalidPercent: percentage of invalid shares to trigger a ban. + # checkThreshold: mumber of shares required before a miner's shares are considered for a ban. + # purgeInterval: purge interval in seconds that bans are checked to see if they are expired. - # vanilla server configuration - experimental! - "vanilla": { - "enabled": false, - "bind": "localhost", - "port": 2223 - }, - - # banning support "banning": { "enabled": true, "duration": 600, @@ -124,7 +127,20 @@ "purgeInterval": 300 }, - # per-pool storage configuration + # ------------------------------- + # Per-pool Storage Configuration + # ------------------------------- + + # note that this is different then the global storage configuration in config.json as pools will be using their own storage connections. + # basically, each pool can have different set of storage configuration. + + # redis: + # enabled: is redis enabled? + # host: redis host. + # port: redis port. + # password: set the password if your redis installation requires one. + # databaseId: redis database instance id (optional) + "storage": { "redis": { "enabled": true, @@ -135,7 +151,12 @@ } }, - # mpos compat mode configuration - not implemented yet! + # ------------------------------- + # MPOS Compatibility Mode + # ------------------------------- + + # NOT-IMPLEMENTED-YET! + "mpos": { "enabled": false, "database": { @@ -146,4 +167,18 @@ "password": "password" } } + + # ------------------------------- + # Getwork Server Configuration + # ------------------------------- + + # EXPERIMENTAL!; This feature is still in development and still not complete yet. + # enabled: Set this true to enable getwork server. + # bind: interface to bind getwork server. + # port: port to listen for getwork connections. + + "vanilla": { + "enabled": false, + "bind": "localhost", + "port": 2223 } \ No newline at end of file From dd08289bb8e720661bfef0162161508f9bef36ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 21 Jul 2014 21:44:11 +0300 Subject: [PATCH 117/230] removed global redis configuration as pools will handling their own storage-connections. --- src/CoiniumServ/config/config-sample.json | 11 ----------- src/CoiniumServ/config/pools/sample-detailed.json | 5 +---- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-sample.json index be4ebebf1..a0e95172b 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-sample.json @@ -5,17 +5,6 @@ "bind": "127.0.0.1", "port": 91 }, - - # global storage configuration. - "storage": { - "redis": { - "enabled": true, - "host": "10.0.0.13", - "port": 6379, - "password": "", - "databaseId": 0 - } - }, # logging configuration "logging": { diff --git a/src/CoiniumServ/config/pools/sample-detailed.json b/src/CoiniumServ/config/pools/sample-detailed.json index eb9526abd..b66a1beb5 100644 --- a/src/CoiniumServ/config/pools/sample-detailed.json +++ b/src/CoiniumServ/config/pools/sample-detailed.json @@ -131,9 +131,6 @@ # Per-pool Storage Configuration # ------------------------------- - # note that this is different then the global storage configuration in config.json as pools will be using their own storage connections. - # basically, each pool can have different set of storage configuration. - # redis: # enabled: is redis enabled? # host: redis host. @@ -172,7 +169,7 @@ # Getwork Server Configuration # ------------------------------- - # EXPERIMENTAL!; This feature is still in development and still not complete yet. + # EXPERIMENTAL!; This feature is still in development and not complete yet. # enabled: Set this true to enable getwork server. # bind: interface to bind getwork server. # port: port to listen for getwork connections. From 12d9b173e3ae1866b8dcfb8f368192de2f865ced Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 22 Jul 2014 12:56:23 +0300 Subject: [PATCH 118/230] more config files documentation. --- src/CoiniumServ/CoiniumServ.csproj | 8 +- ...config-sample.json => config-example.json} | 12 +- .../config/pools/default-example.json | 144 ++++++++++++++++++ .../config/pools/default-sample.json | 62 -------- ...le-detailed.json => detailed-example.json} | 9 +- src/CoiniumServ/config/pools/example.json | 117 ++++++++++++++ src/CoiniumServ/config/pools/sample.json | 63 -------- 7 files changed, 284 insertions(+), 131 deletions(-) rename src/CoiniumServ/config/{config-sample.json => config-example.json} (68%) create mode 100644 src/CoiniumServ/config/pools/default-example.json delete mode 100644 src/CoiniumServ/config/pools/default-sample.json rename src/CoiniumServ/config/pools/{sample-detailed.json => detailed-example.json} (94%) create mode 100644 src/CoiniumServ/config/pools/example.json delete mode 100644 src/CoiniumServ/config/pools/sample.json diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 51ff867ab..5d49c7108 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -375,7 +375,7 @@ PreserveNewest - + PreserveNewest @@ -783,13 +783,13 @@ PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/src/CoiniumServ/config/config-sample.json b/src/CoiniumServ/config/config-example.json similarity index 68% rename from src/CoiniumServ/config/config-sample.json rename to src/CoiniumServ/config/config-example.json index a0e95172b..13d896225 100644 --- a/src/CoiniumServ/config/config-sample.json +++ b/src/CoiniumServ/config/config-example.json @@ -1,11 +1,21 @@ { - # website configuration + # ------------------------------- + # Website Configuration + # ------------------------------- + + # enabled: set this true to enable frontend. + + # website configuration "website": { "enabled": true, "bind": "127.0.0.1", "port": 91 }, + # ------------------------------- + # Logging Configuration + # ------------------------------- + # logging configuration "logging": { "root": "logs", diff --git a/src/CoiniumServ/config/pools/default-example.json b/src/CoiniumServ/config/pools/default-example.json new file mode 100644 index 000000000..8e26e87b6 --- /dev/null +++ b/src/CoiniumServ/config/pools/default-example.json @@ -0,0 +1,144 @@ +{ + # default pool configuration + # if a per-pool config file doesn't override a setting, default value from this file will be applied + + # ------------------------------- + # Coin Daemon RPC Connection + # ------------------------------- + + # host: ip/hostname of coin-daemon. + + "daemon": { + "host": "127.0.0.1" + }, + + # ------------------------------- + # Payment Processing Configuration + # ------------------------------- + + # interval: interval in seconds that payment-processor will be running. + # minimum: minimum amount of coins before a miner is eligable for getting a payment. + + "payments": { + "interval": 60, + "minimum": 1 + }, + + # ------------------------------- + # Miner Configuration + # ------------------------------- + + # validateUsername: set true to validate miner usernames as an addresses against the coin daemon. + # timeout: timeout in seconds to disconnect miners that did not submit any shares for the period. + + "miner": { + "validateUsername": "true", + "timeout": 300 + }, + + # ------------------------------- + # Job Manager Configuration + # ------------------------------- + + # blockRefresh: timeout in miliseconds to poll coin daemon for a new block. + # rebroadcast: if now new blocks are found in this many seconds, a new job will be created and broadcasted. + + + "jobs": { + "blockRefresh": 1000, + "rebroadcast": 55 + }, + + # ------------------------------- + # Stratum Server Configuration + # ------------------------------- + + # stratum: + # bind: interface to bind stratum server. + # diff: default difficulty assigned to newly connected miners. + + # vardiff: + # minDiff: minimum difficulty that can be assigned to miners. + # maxDiff: maximum difficulty that can be assigned to miners. + # targetTime: try to get a single share per this many seconds from miner. + # retargetTime: retarget a miners difficulty ever this many seconds. + # variancePercent: allow difficulty for a miner to vary this percent without retargeting. + + "stratum": { + "bind": "0.0.0.0", + "diff": 16, + "vardiff": { + "minDiff": 8, + "maxDiff": 512, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + }, + + # ------------------------------- + # Ban Configuration + # ------------------------------- + + # you can ban miners which submits invalid work / data to reduce system/network load. + # duration: duration of ban when a miner gets flagged for so. + # invalidPercent: percentage of invalid shares to trigger a ban. + # checkThreshold: mumber of shares required before a miner's shares are considered for a ban. + # purgeInterval: purge interval in seconds that bans are checked to see if they are expired. + + "banning": { + "duration": 600, + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 + }, + + # ------------------------------- + # Per-pool Storage Configuration + # ------------------------------- + + # redis: + # host: redis host. + # port: redis port. + # password: set the password if your redis installation requires one. + # databaseId: redis database instance id (optional) + + "storage": { + "redis": { + "host": "127.0.0.1", + "port": 6379, + "password": "", + "databaseId": 0 + } + }, + + # ------------------------------- + # MPOS Compatibility Mode + # ------------------------------- + + # NOT-IMPLEMENTED-YET! + # host: database host. + # port: database port. + # username: username for connecting the database. + # password: password for connecting the database. + + "mpos": { + "database": { + "host": "127.0.0.1", + "port": 3306, + "user": "username", + "password": "password" + } + }, + + # ------------------------------- + # Getwork Server Configuration + # ------------------------------- + + # EXPERIMENTAL!; This feature is still in development and not complete yet. + # bind: interface to bind getwork server. + + "vanilla": { + "bind": "localhost" + } +} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/default-sample.json b/src/CoiniumServ/config/pools/default-sample.json deleted file mode 100644 index b4705183d..000000000 --- a/src/CoiniumServ/config/pools/default-sample.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - # default pool configuration - # if a per-pool config file doesn't override a setting, default value from this file will be applied - - # payment processing configuration - "payments": { - "interval": 60, - "minimum": 1 - }, - - # coin daemon connection configuration - "daemon": { - "host": "127.0.0.1" - }, - - # stratum server configuration - "stratum": { - "bind": "0.0.0.0", - "diff": 16, - "vardiff": { - "minDiff": 8, - "maxDiff": 512, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30 - } - }, - - # vanilla server configuration - experimental! - "vanilla": { - "bind": "localhost" - }, - - # banning support - "banning": { - "enabled": true, - "duration": 600, - "invalidPercent": 50, - "checkThreshold": 500, - "purgeInterval": 300 - }, - - # per-pool storage configuration - "storage": { - "redis": { - "host": "127.0.0.1", - "port": 6379, - "password": "", - "databaseId": 0 - } - }, - - # mpos compat mode configuration - not implemented yet! - "mpos": { - "database": { - "host": "127.0.0.1", - "port": 3306, - "user": "username", - "password": "password" - } - } -} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/sample-detailed.json b/src/CoiniumServ/config/pools/detailed-example.json similarity index 94% rename from src/CoiniumServ/config/pools/sample-detailed.json rename to src/CoiniumServ/config/pools/detailed-example.json index b66a1beb5..c11c2c0ed 100644 --- a/src/CoiniumServ/config/pools/sample-detailed.json +++ b/src/CoiniumServ/config/pools/detailed-example.json @@ -153,6 +153,12 @@ # ------------------------------- # NOT-IMPLEMENTED-YET! + # enabled: set this true to enable mpos compatibility mode - make sure to internal disable payment-processor! + # host: database host. + # port: database port. + # name: database-name. + # username: username for connecting the database. + # password: password for connecting the database. "mpos": { "enabled": false, @@ -163,7 +169,7 @@ "user": "username", "password": "password" } - } + }, # ------------------------------- # Getwork Server Configuration @@ -178,4 +184,5 @@ "enabled": false, "bind": "localhost", "port": 2223 + } } \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/example.json b/src/CoiniumServ/config/pools/example.json new file mode 100644 index 000000000..0a863a6dc --- /dev/null +++ b/src/CoiniumServ/config/pools/example.json @@ -0,0 +1,117 @@ +{ + # sample pool config file that only sets specific settings for the pool and gets the others from default.json + + "enabled": false, + "coin": "litecoin.json", + + # ------------------------------- + # Coin Daemon RPC Connection + # ------------------------------- + + # port: the port coin daemon is listening on. + # username: username for rpc connection. + # password: password for rpc connection. + + "daemon": { + "port": 9333, + "username": "user", + "password": "password" + }, + + # ------------------------------- + # Wallet & Rewards Configuration + # ------------------------------- + + # address: generated coins will arrive here. + + "wallet" : { + "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" + }, + + # rewards: list of addresses that gets a percentage from each mined block (ie, pool fee.) + + "rewards": [ + {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} + ], + + # ------------------------------- + # Payment Processing Configuration + # ------------------------------- + + # enabled: set this true to let CoiniumServ handle the payments, false if you would like some other software like mpos to handle them. + + "payments": { + "enabled": true + }, + + # ------------------------------- + # Stratum Server Configuration + # ------------------------------- + + # stratum: + # enabled: set this true to enable stratum server. + # port: port to listen for stratum connections. + + # vardiff: + # enabled: set this true to enable variable-difficulty support. + + "stratum": { + "enabled": true, + "port": 3333, + "vardiff": { + "enabled": true + } + }, + + # ------------------------------- + # Ban Configuration + # ------------------------------- + + # you can ban miners which submits invalid work / data to reduce system/network load. + # enabled: set this true to enable banning support. + + "banning": { + "enabled": true + }, + + # ------------------------------- + # Per-pool Storage Configuration + # ------------------------------- + + # redis: + # enabled: is redis enabled? + + "storage": { + "redis": { + "enabled": true + } + }, + + # ------------------------------- + # MPOS Compatibility Mode + # ------------------------------- + + # NOT-IMPLEMENTED-YET! + # enabled: set this true to enable mpos compatibility mode - make sure to internal disable payment-processor! + # name: database-name. + + "mpos": { + "enabled": false, + "database": { + "name": "db-name" + } + }, + + # ------------------------------- + # Getwork Server Configuration + # ------------------------------- + + # EXPERIMENTAL!; This feature is still in development and not complete yet. + # enabled: Set this true to enable getwork server. + # port: port to listen for getwork connections. + + "vanilla": { + "enabled": false, + "port": 2223 + } +} \ No newline at end of file diff --git a/src/CoiniumServ/config/pools/sample.json b/src/CoiniumServ/config/pools/sample.json deleted file mode 100644 index 23e2ecec3..000000000 --- a/src/CoiniumServ/config/pools/sample.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - # sample pool config file that only sets specific settings for the pool and gets the others from default.json - - "enabled": false, - "coin": "litecoin.json", - - # central wallet configuration - "wallet" : { - "address": "n3Mvrshbf4fMoHzWZkDVbhhx4BLZCcU9oY" - }, - - # rewards configuration - "rewards": [ - {"myxWybbhUkGzGF7yaf2QVNx3hh3HWTya5t": 1} - ], - - # coin daemon connection configuration - "daemon": { - "port": 9333, - "username": "user", - "password": "password" - }, - - # payment processing configuration - "payments": { - "enabled": true - }, - - # stratum server configuration - "stratum": { - "enabled": true, - "port": 3333, - "vardiff": { - "enabled": true - } - }, - - # vanilla server configuration - experimental! - "vanilla": { - "enabled": false, - "port": 2223 - }, - - # banning support - "banning": { - "enabled": true - }, - - # per-pool storage config - "storage": { - "redis": { - "enabled": true - } - }, - - # mpos compat mode configuration - not implemented yet! - "mpos": { - "enabled": false, - "database": { - "name": "db-name" - } - } -} \ No newline at end of file From dc0f3e3d2190465722a03a5d0c8efdca913d8454 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 22 Jul 2014 17:32:35 +0300 Subject: [PATCH 119/230] Added default.json support for pools. Payment-processor can now use double value as minimum setting. RedisConfig is no more global and now loaded per-pool. --- src/CoiniumServ/CoiniumServ.csproj | 1 + .../Mining/Pools/Config/IPoolConfig.cs | 3 ++ .../Mining/Pools/Config/IStorageConfig.cs | 29 +++++++++++++++++++ .../Mining/Pools/Config/PoolConfig.cs | 7 +++-- src/CoiniumServ/Mining/Pools/Pool.cs | 10 ++----- src/CoiniumServ/Payments/IPaymentConfig.cs | 2 +- src/CoiniumServ/Payments/PaymentConfig.cs | 2 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 5 ++-- .../Persistance/Redis/IRedisConfig.cs | 3 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 4 +-- .../Server/Mining/Stratum/StratumServer.cs | 1 + .../Server/Mining/Vanilla/VanillaServer.cs | 2 ++ .../Utils/Configuration/ConfigManager.cs | 17 +++++++++-- .../Utils/Configuration/IConfigManager.cs | 2 -- .../config/pools/default-example.json | 3 +- .../config/pools/detailed-example.json | 2 +- 16 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 5d49c7108..01a86f6e5 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -131,6 +131,7 @@ + diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 2f5957af2..b60d11fe9 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -24,6 +24,7 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; using CoiniumServ.Payments; +using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Vanilla.Config; using CoiniumServ.Utils.Configuration; @@ -52,5 +53,7 @@ public interface IPoolConfig:IConfig IPaymentConfig Payments { get; } IBanConfig Banning { get; } + + IStorageConfig Storage { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs new file mode 100644 index 000000000..61e3461b4 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs @@ -0,0 +1,29 @@ +#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.Mining.Pools.Config +{ + public interface IStorageConfig + { + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index da433cfba..5cd72ae2e 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -21,11 +21,11 @@ // #endregion -using System.IO; using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; -using CoiniumServ.Factories; using CoiniumServ.Payments; +using CoiniumServ.Persistance; +using CoiniumServ.Persistance.Redis; using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Vanilla.Config; @@ -57,6 +57,7 @@ public class PoolConfig : IPoolConfig public IPaymentConfig Payments { get; private set; } public IBanConfig Banning { get; private set; } + public IStorageConfig Storage { get; private set; } /// /// Initializes a new instance of the class. @@ -115,6 +116,8 @@ public PoolConfig(dynamic config, ICoinConfig coinConfig) Banning = new BanConfig(config.banning); + Storage = new RedisConfig(config.storage.redis); + Valid = true; } } diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Mining/Pools/Pool.cs index f8d68521c..e283d4c51 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Mining/Pools/Pool.cs @@ -181,8 +181,7 @@ private void PrintPoolInfo() "Coin version: {2} protocol: {3} wallet: {4} " + "Daemon network: {5:l} peers: {6} blocks: {7} errors: {8:l} " + "Network difficulty: {9:0.00000000} block difficulty: {10:0.00} " + - "Network hashrate: {11:l} " + - "{12:l}", + "Network hashrate: {11:l} ", Config.Coin.Symbol, Config.Coin.Algorithm, info.Version, @@ -193,12 +192,7 @@ private void PrintPoolInfo() string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors, miningInfo.Difficulty, miningInfo.Difficulty * _hashAlgorithm.Multiplier, - miningInfo.NetworkHashps.GetReadableHashrate(), - "Services: " + _servers.Select(pair => pair.Key) - .Aggregate(string.Empty, - (current, server) => - current + - string.Format("{0} @ {1}:{2}, ", server.Config.Name.ToLower(), server.BindIP, server.Port)) + miningInfo.NetworkHashps.GetReadableHashrate() ); } diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs index b932274e8..d14770bc6 100644 --- a/src/CoiniumServ/Payments/IPaymentConfig.cs +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -32,6 +32,6 @@ public interface IPaymentConfig:IConfig Int32 Interval { get; } - Int32 Minimum { get; } + double Minimum { get; } } } diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs index 05bfd810c..7f9a7db4e 100644 --- a/src/CoiniumServ/Payments/PaymentConfig.cs +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -28,7 +28,7 @@ public class PaymentConfig:IPaymentConfig public bool Valid { get; private set; } public bool Enabled { get; private set; } public int Interval { get; private set; } - public int Minimum { get; private set; } + public double Minimum { get; private set; } public PaymentConfig(dynamic config) { diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 9eedc7161..b79d08d1e 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -26,7 +26,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Mining.Pools.Config; @@ -36,6 +35,8 @@ namespace CoiniumServ.Payments { + // TODO: needs a cleanup. + public class PaymentProcessor : IPaymentProcessor { public bool IsEnabled { get; private set; } @@ -86,7 +87,7 @@ public void Initialize(IPaymentConfig config) return; // calculate the minimum amount of payments in satoshis. - _paymentThresholdInSatoshis = _magnitude*config.Minimum; + _paymentThresholdInSatoshis = (decimal) (_magnitude*config.Minimum); // if we reached here, then we can just setup the timer to run payments. _timer = new Timer(RunPayments, null, _config.Interval * 1000, Timeout.Infinite); diff --git a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs index d7ca028f6..c0bc63fe6 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs @@ -22,10 +22,11 @@ #endregion using System; +using CoiniumServ.Mining.Pools.Config; namespace CoiniumServ.Persistance.Redis { - public interface IRedisConfig + public interface IRedisConfig : IStorageConfig { bool Enabled { get; } string Host { get; } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index f44cba1ec..c9b52feb0 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -55,12 +55,12 @@ public class Redis:IStorage, IRedis private readonly ILogger _logger; - public Redis(IConfigManager configManager, IPoolConfig poolConfig) + public Redis(PoolConfig poolConfig) { _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); _poolConfig = poolConfig; // the pool config. - _redisConfig = configManager.RedisConfig; // read the redis config. + _redisConfig = (IRedisConfig) poolConfig.Storage; IsEnabled = _redisConfig.Enabled; diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index e22841e6a..fee348b69 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -94,6 +94,7 @@ public void Initialize(IServerConfig config) public override bool Start() { var success = Listen(BindIP, Port); + _logger.Information("Stratum server listening on {0:l}:{1}", BindIP, Port); return success; } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index 7e73d9fdb..ae611ef13 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -61,6 +61,8 @@ public void Initialize(IServerConfig config) Initialize(); ProcessRequest += ProcessHttpRequest; + + _logger.Information("Vanilla server listening on {0:l}:{1}", BindIP, Port); } private void ProcessHttpRequest(HttpListenerContext context) diff --git a/src/CoiniumServ/Utils/Configuration/ConfigManager.cs b/src/CoiniumServ/Utils/Configuration/ConfigManager.cs index 83c3ced7d..0c0036bad 100644 --- a/src/CoiniumServ/Utils/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Utils/Configuration/ConfigManager.cs @@ -21,13 +21,13 @@ // #endregion +using System; using System.Collections.Generic; using System.IO; using System.Linq; using CoiniumServ.Coin.Config; using CoiniumServ.Factories; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance.Redis; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Helpers.IO; using CoiniumServ.Utils.Logging; @@ -38,7 +38,6 @@ namespace CoiniumServ.Utils.Configuration public class ConfigManager:IConfigManager { public bool ConfigExists { get { return _globalConfigData != null; } } - public IRedisConfig RedisConfig { get; private set; } public IWebServerConfig WebServerConfig { get; private set; } public ILogConfig LogConfig { get; private set; } @@ -51,7 +50,9 @@ public class ConfigManager:IConfigManager private readonly Dictionary _coinConfigs; // cache for loaded coin configs. private readonly dynamic _globalConfigData; // global config data. + private dynamic _defaultPoolConfig; private readonly IConfigFactory _configFactory; + private ILogger _logger; public ConfigManager(IConfigFactory configFactory) @@ -63,7 +64,6 @@ public ConfigManager(IConfigFactory configFactory) _coinConfigs = new Dictionary(); LogConfig = new LogConfig(_globalConfigData.logging); - RedisConfig = new RedisConfig(_globalConfigData.storage.redis); WebServerConfig = new WebServerConfig(_globalConfigData.website); } @@ -84,12 +84,23 @@ private void LoadPoolConfigs() { var data = JsonConfigReader.Read(file); + // check if we have a default.json pool config. + var filename = Path.GetFileNameWithoutExtension(file); + if (!string.IsNullOrEmpty(filename) && filename.Equals("default", StringComparison.OrdinalIgnoreCase)) + { + _defaultPoolConfig = data; + continue; // don't add the default.json to list of pools and yet again do not load the coinconfig data for it. + } + if (!data.enabled) // skip pools that are not enabled. continue; var coinName = Path.GetFileNameWithoutExtension(data.coin); var coinConfig = GetCoinConfig(coinName); + if(_defaultPoolConfig != null) + data = JsonConfig.Merger.Merge(_defaultPoolConfig, data); // if we do have a default.json config, merge with it. + PoolConfigs.Add(_configFactory.GetPoolConfig(data, coinConfig)); } diff --git a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs index a747e320c..5575c8564 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs +++ b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs @@ -33,8 +33,6 @@ public interface IConfigManager { bool ConfigExists { get; } - IRedisConfig RedisConfig { get; } - IWebServerConfig WebServerConfig { get; } ILogConfig LogConfig { get; } diff --git a/src/CoiniumServ/config/pools/default-example.json b/src/CoiniumServ/config/pools/default-example.json index 8e26e87b6..a29a7e1e5 100644 --- a/src/CoiniumServ/config/pools/default-example.json +++ b/src/CoiniumServ/config/pools/default-example.json @@ -21,7 +21,7 @@ "payments": { "interval": 60, - "minimum": 1 + "minimum": 0.01 }, # ------------------------------- @@ -43,7 +43,6 @@ # blockRefresh: timeout in miliseconds to poll coin daemon for a new block. # rebroadcast: if now new blocks are found in this many seconds, a new job will be created and broadcasted. - "jobs": { "blockRefresh": 1000, "rebroadcast": 55 diff --git a/src/CoiniumServ/config/pools/detailed-example.json b/src/CoiniumServ/config/pools/detailed-example.json index c11c2c0ed..bfbde936c 100644 --- a/src/CoiniumServ/config/pools/detailed-example.json +++ b/src/CoiniumServ/config/pools/detailed-example.json @@ -47,7 +47,7 @@ "payments": { "enabled": true, "interval": 60, - "minimum": 0.01, + "minimum": 0.01 }, # ------------------------------- From b86b12ce1de6e2401d2cc37fc5fd74699c111291 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Tue, 22 Jul 2014 18:53:24 +0300 Subject: [PATCH 120/230] Implemented a fix when banning-manager was disabled and was causing exceptions to be thrown preventing socket connections to be accepted. Fixed validateUsername config value. Implemented MinerConfig.cs. Improved SocketServer - the backlog of waiting-to-be-accepted connections set to max now. --- src/CoiniumServ/CoiniumServ.csproj | 4 +- src/CoiniumServ/Mining/Banning/BanManager.cs | 8 ++- .../Mining/Pools/Config/IMinerConfig.cs | 37 ++++++++++++ .../Mining/Pools/Config/IPoolConfig.cs | 15 +++-- .../Mining/Pools/Config/MinerConfig.cs | 56 +++++++++++++++++++ .../Mining/Pools/Config/PoolConfig.cs | 5 +- .../Net/Server/Sockets/SocketServer.cs | 32 ++++++++--- .../Config => Persistance}/IStorageConfig.cs | 2 +- .../Server/Mining/Stratum/StratumServer.cs | 9 ++- .../config/pools/default-example.json | 2 +- .../config/pools/detailed-example.json | 2 +- 11 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs rename src/CoiniumServ/{Mining/Pools/Config => Persistance}/IStorageConfig.cs (96%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 01a86f6e5..de6d57ce2 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -130,8 +130,10 @@ + - + + diff --git a/src/CoiniumServ/Mining/Banning/BanManager.cs b/src/CoiniumServ/Mining/Banning/BanManager.cs index 63da0cba3..7a1fdf41b 100644 --- a/src/CoiniumServ/Mining/Banning/BanManager.cs +++ b/src/CoiniumServ/Mining/Banning/BanManager.cs @@ -108,15 +108,17 @@ private void Ban(IMiner miner) public bool IsBanned(IPAddress ip) { + if (!Config.Enabled) // if banning is not enabled, + return false; // just skip queries. + if (!_bannedIps.ContainsKey(ip)) // check if ip exists in banlist. return false; if (!BanExpired(ip)) // if ip has still an ongoing ban. return true; - // if the code flow reaches here, it means the ban has been expired, so remove it first. - RemoveBan(ip); - return false; + RemoveBan(ip); // if the code flow reaches here, it means the ban has been expired, so remove it first. + return false; // and tell that ip has no bans. } public void CheckBans(object state) diff --git a/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs new file mode 100644 index 000000000..233b32f30 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs @@ -0,0 +1,37 @@ +#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 CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Mining.Pools.Config +{ + public interface IMinerConfig : IConfig + { + /// + /// Should worker usernames validated against coin daemon as an address? + /// + bool ValidateUsername { get; } + + int Timeout { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index b60d11fe9..ca94b04bf 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -23,6 +23,7 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; +using CoiniumServ.Mining.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum.Config; @@ -38,22 +39,24 @@ public interface IPoolConfig:IConfig /// bool Enabled { get; } - IWalletConfig Wallet { get; } + IDaemonConfig Daemon { get; } ICoinConfig Coin { get; } - IStratumServerConfig Stratum { get; } - - IVanillaServerConfig Vanilla { get; } - - IDaemonConfig Daemon { get; } + IWalletConfig Wallet { get; } IRewardsConfig Rewards { get; } IPaymentConfig Payments { get; } + IMinerConfig Miner { get; } + + IStratumServerConfig Stratum { get; } + IBanConfig Banning { get; } IStorageConfig Storage { get; } + + IVanillaServerConfig Vanilla { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs b/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs new file mode 100644 index 000000000..ad05c3326 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs @@ -0,0 +1,56 @@ +#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 Serilog; + +namespace CoiniumServ.Mining.Pools.Config +{ + public class MinerConfig:IMinerConfig + { + public bool Valid { get; private set; } + public bool ValidateUsername { get; private set; } + public int Timeout { get; private set; } + + public MinerConfig(dynamic config) + { + try + { + // set the defaults; + ValidateUsername = true; + Timeout = 300; + + // load the config data. + ValidateUsername = config.validateUsername; + Timeout = config.timeout; + + Valid = true; + } + catch (Exception e) + { + Log.Logger.ForContext().Error(e, "Error loading miner configuration"); + Valid = false; + } + } + } +} \ No newline at end of file diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 5cd72ae2e..f101adb55 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -43,6 +43,7 @@ public class PoolConfig : IPoolConfig public ICoinConfig Coin { get; private set; } + public IMinerConfig Miner { get; private set; } public IStratumServerConfig Stratum { get; private set; } public IVanillaServerConfig Vanilla { get; private set; } @@ -66,7 +67,6 @@ public class PoolConfig : IPoolConfig /// public PoolConfig(dynamic config, ICoinConfig coinConfig) { - // todo - read per pool redis config. if (config == null) { @@ -79,6 +79,9 @@ public PoolConfig(dynamic config, ICoinConfig coinConfig) if (Enabled == false) return; + Miner = new MinerConfig(config.miner); + + Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); diff --git a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs index 4d425fc8e..70c953275 100644 --- a/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Net/Server/Sockets/SocketServer.cs @@ -114,7 +114,21 @@ protected virtual bool Listen(string bindIP, int port) Port = port; // Start listening for incoming connections. - Listener.Listen(10); + Listener.Listen(int.MaxValue); // let the maximum amount of accept backlog - we are basically leaving it to OS to determine the value. + // by setting the maximum available value, we can make sure that we can handle large amounts of concurrent + // connection requests (maybe after a server restart). + + // http://blog.stephencleary.com/2009/05/using-socket-as-server-listening-socket.html + // The “backlog” parameter to Socket.Listen is how many connections the OS may accept on behalf of the application. This is not + // the total number of active connections; it is only how many connections will be established if the application “gets behind”. + // Once connections are Accepted, they move out of the backlog queue and no longer “count” against the backlog limit. + + // The .NET docs fail to mention that int.MaxValue can be used to invoke the “dynamic backlog” feature (Windows Server systems only), + // essentially leaving it up to the OS. It is tempting to set this value very high (e.g., always passing int.MaxValue), but this would + // hurt system performance (on non-server machines) by pre-allocating a large amount of scarce resources. This value should be set to a + // reasonable amount (usually between 2 and 5), based on how many connections one is realistically expecting and how quickly they can be + // Accepted. + IsListening = true; // Begin accepting any incoming connections asynchronously. @@ -160,14 +174,16 @@ private void AcceptCallback(IAsyncResult result) OnClientConnection(new ConnectionEventArgs(connection)); // Raise the ClientConnected event. connection.BeginReceive(ReceiveCallback, connection); // Begin receiving on the new connection connection. } - - Listener.BeginAccept(AcceptCallback, null); // Continue receiving other incoming connection asynchronously. } - catch (NullReferenceException) { } // we recive this after issuing server-shutdown, just ignore it. - //catch (Exception exception) - //{ - // Log.Error("Can not accept connection: {0}", exception); - //} + catch (Exception exception) + { + Log.ForContext().Error(exception, "Can not accept connection"); + } + finally + { + // no matter we were able to accept last connection request, make sure we continue to listen for new connections. + Listener.BeginAccept(AcceptCallback, null); + } } public virtual bool IsBanned(Socket socket) diff --git a/src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs b/src/CoiniumServ/Persistance/IStorageConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs rename to src/CoiniumServ/Persistance/IStorageConfig.cs index 61e3461b4..49b4abeb9 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IStorageConfig.cs +++ b/src/CoiniumServ/Persistance/IStorageConfig.cs @@ -21,7 +21,7 @@ // #endregion -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Persistance { public interface IStorageConfig { diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index fee348b69..b32e77cda 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -109,7 +109,14 @@ public override bool Stop() public override bool IsBanned(Socket socket) { - var endpoint = (IPEndPoint) socket.RemoteEndPoint; + if (socket == null) // we should have a valid socket data. + return true; // else just behave the client as banned. + + var endpoint = (IPEndPoint) socket.RemoteEndPoint; // get the remote endpoint for socket. + + if (endpoint == null || endpoint.Address == null) // if we don't have an endpoint information, basically we can't determine the ip miner + return false; // in case, we just allow him to get connected as we can ban him later based on his behaviours. + return _banManager.IsBanned(endpoint.Address); } diff --git a/src/CoiniumServ/config/pools/default-example.json b/src/CoiniumServ/config/pools/default-example.json index a29a7e1e5..ca67bd4a1 100644 --- a/src/CoiniumServ/config/pools/default-example.json +++ b/src/CoiniumServ/config/pools/default-example.json @@ -32,7 +32,7 @@ # timeout: timeout in seconds to disconnect miners that did not submit any shares for the period. "miner": { - "validateUsername": "true", + "validateUsername": true, "timeout": 300 }, diff --git a/src/CoiniumServ/config/pools/detailed-example.json b/src/CoiniumServ/config/pools/detailed-example.json index bfbde936c..6bde2f05e 100644 --- a/src/CoiniumServ/config/pools/detailed-example.json +++ b/src/CoiniumServ/config/pools/detailed-example.json @@ -58,7 +58,7 @@ # timeout: timeout in seconds to disconnect miners that did not submit any shares for the period. "miner": { - "validateUsername": "true", + "validateUsername": true, "timeout": 300 }, From a282fbfac2c5750f3766347333110ba97b41d773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 23 Jul 2014 01:21:18 +0300 Subject: [PATCH 121/230] fixed a few typos. --- src/CoiniumServ/Daemon/DaemonBase.cs | 2 +- src/CoiniumServ/Daemon/DaemonRequest.cs | 4 ++-- src/CoiniumServ/Daemon/DaemonResponse.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index e6b0f121f..d180ed99c 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -161,7 +161,7 @@ private DaemonResponse GetRpcResponse(HttpWebRequest httpWebRequest) } catch (JsonException jsonEx) { - throw new Exception("There was a problem deserializing the response from the bitcoin wallet.", jsonEx); + throw new Exception("There was a problem deserializing the response from the coin wallet.", jsonEx); } } diff --git a/src/CoiniumServ/Daemon/DaemonRequest.cs b/src/CoiniumServ/Daemon/DaemonRequest.cs index 185896fbf..f27131487 100644 --- a/src/CoiniumServ/Daemon/DaemonRequest.cs +++ b/src/CoiniumServ/Daemon/DaemonRequest.cs @@ -29,12 +29,12 @@ namespace CoiniumServ.Daemon { /// - /// Class containing data sent to the Bitcoin wallet as a JSON RPC call. + /// Class containing data sent to the coin wallet as a JSON RPC call. /// public class DaemonRequest { /// - /// The method to call on the Bitcoin wallet. + /// The method to call on the coin wallet. /// [JsonProperty(PropertyName = "method", Order = 0)] public string Method { get; set; } diff --git a/src/CoiniumServ/Daemon/DaemonResponse.cs b/src/CoiniumServ/Daemon/DaemonResponse.cs index 05078f6a6..54d670621 100644 --- a/src/CoiniumServ/Daemon/DaemonResponse.cs +++ b/src/CoiniumServ/Daemon/DaemonResponse.cs @@ -27,7 +27,7 @@ namespace CoiniumServ.Daemon { /// /// Class containing the information contained in a JSON RPC response received from - /// the Bitcoin wallet. + /// the coin wallet. /// /// /// Type of the result object. This can simply be a string like a transaction id, From 44baf4a181f1f69c6c156dd788b3c3cd17fd5ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 23 Jul 2014 02:14:35 +0300 Subject: [PATCH 122/230] Added donors section and a reddcoin donation address to readme. Tiny updates on pool configs. Implemented job-config. --- README.md | 7 +++ src/CoiniumServ/CoiniumServ.csproj | 2 + .../Mining/Pools/Config/BanConfig.cs | 31 ++++++++-- .../Mining/Pools/Config/IBanConfig.cs | 16 +++++- .../Mining/Pools/Config/IJobConfig.cs | 40 +++++++++++++ .../Mining/Pools/Config/IMinerConfig.cs | 3 + .../Mining/Pools/Config/IPoolConfig.cs | 2 + .../Mining/Pools/Config/JobConfig.cs | 56 +++++++++++++++++++ .../Mining/Pools/Config/PoolConfig.cs | 3 + .../config/pools/default-example.json | 10 ++-- .../config/pools/detailed-example.json | 10 ++-- 11 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs create mode 100644 src/CoiniumServ/Mining/Pools/Config/JobConfig.cs diff --git a/README.md b/README.md index 1ab3d2ecd..3f5f1002f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ You can contribute the development of the project by donating; * BTC: `18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D` * LTC: `LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa` * DOGE: `DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr` +* RDD: `Rb9kcLs96VDHTmiXVjcWC2RBsfCJ73UQyr` ###### Bounties @@ -130,6 +131,12 @@ Start reading by these; * [Developer's Guide](https://github.com/CoiniumServ/CoiniumServ/wiki/Developer's-Guide) * [Technical Documentation](https://github.com/CoiniumServ/CoiniumServ/wiki/Technical-Documentation) +###### Donors + +Here is a list of our generous donors that keep the project ongoing; + +* [reddapi.com](https://www.reddapi.com) + ### License Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org - diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index de6d57ce2..47e42fce5 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -130,8 +130,10 @@ + + diff --git a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs index eaf4c43b9..378521aed 100644 --- a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs @@ -21,6 +21,9 @@ // #endregion +using System; +using Serilog; + namespace CoiniumServ.Mining.Pools.Config { public class BanConfig : IBanConfig @@ -30,14 +33,32 @@ public class BanConfig : IBanConfig public int InvalidPercent { get; private set; } public int CheckThreshold { get; private set; } public int PurgeInterval { get; private set; } + public bool Valid { get; private set; } public BanConfig(dynamic config) { - Enabled = config.enabled; - Duration = config.duration; - InvalidPercent = config.invalidPercent; - CheckThreshold = config.checkThreshold; - PurgeInterval = config.purgeInterval; + try + { + // set the defaults; + Duration = 600; + InvalidPercent = 50; + CheckThreshold = 100; + PurgeInterval = 300; + + // load the config data. + Enabled = config.enabled; + Duration = config.duration; + InvalidPercent = config.invalidPercent; + CheckThreshold = config.checkThreshold; + PurgeInterval = config.purgeInterval; + + Valid = true; + } + catch (Exception e) + { + Log.Logger.ForContext().Error(e, "Error loading banning configuration"); + Valid = false; + } } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs index b232991be..33b2a3ba9 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs @@ -21,18 +21,32 @@ // #endregion +using CoiniumServ.Utils.Configuration; + namespace CoiniumServ.Mining.Pools.Config { - public interface IBanConfig + public interface IBanConfig : IConfig { bool Enabled { get; } + /// + /// duration of ban when a miner gets flagged for so. + /// int Duration { get; } + /// + /// percentage of invalid shares to trigger a ban. + /// int InvalidPercent { get; } + /// + /// number of shares required before a miner's shares are considered for a ban. + /// int CheckThreshold { get; } + /// + /// purge interval in seconds that bans are checked to see if they are expired. + /// int PurgeInterval { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs new file mode 100644 index 000000000..0b417ca46 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs @@ -0,0 +1,40 @@ +#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 CoiniumServ.Utils.Configuration; + +namespace CoiniumServ.Mining.Pools.Config +{ + public interface IJobConfig : IConfig + { + /// + /// timeout in miliseconds to poll coin daemon for a new block. + /// + int BlockRefreshInterval { get; } + + /// + /// if now new blocks are found in this many seconds, a new job will be created and broadcasted. + /// + int RebroadcastTimeout { get; } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs index 233b32f30..a182d5fcb 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs @@ -32,6 +32,9 @@ public interface IMinerConfig : IConfig /// bool ValidateUsername { get; } + /// + /// timeout in seconds to disconnect miners that did not submit any shares for the period. + /// int Timeout { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index ca94b04bf..2292ebf91 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -51,6 +51,8 @@ public interface IPoolConfig:IConfig IMinerConfig Miner { get; } + IJobConfig Job { get; } + IStratumServerConfig Stratum { get; } IBanConfig Banning { get; } diff --git a/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs b/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs new file mode 100644 index 000000000..bcc5bbe91 --- /dev/null +++ b/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs @@ -0,0 +1,56 @@ +#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 Serilog; + +namespace CoiniumServ.Mining.Pools.Config +{ + public class JobConfig : IJobConfig + { + public bool Valid { get; private set; } + public int BlockRefreshInterval { get; private set; } + public int RebroadcastTimeout { get; private set; } + + public JobConfig(dynamic config) + { + try + { + // set the defaults; + BlockRefreshInterval = 1000; + RebroadcastTimeout = 55; + + // load the config data. + BlockRefreshInterval = config.blockRefreshInterval; + RebroadcastTimeout = config.rebroadcastTimeout; + + Valid = true; + } + catch (Exception e) + { + Log.Logger.ForContext().Error(e, "Error loading job configuration"); + Valid = false; + } + } + } +} diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index f101adb55..78fa0b5e2 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -44,6 +44,7 @@ public class PoolConfig : IPoolConfig public ICoinConfig Coin { get; private set; } public IMinerConfig Miner { get; private set; } + public IJobConfig Job { get; private set; } public IStratumServerConfig Stratum { get; private set; } public IVanillaServerConfig Vanilla { get; private set; } @@ -81,6 +82,8 @@ public PoolConfig(dynamic config, ICoinConfig coinConfig) Miner = new MinerConfig(config.miner); + Job = new JobConfig(config.job); + Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); diff --git a/src/CoiniumServ/config/pools/default-example.json b/src/CoiniumServ/config/pools/default-example.json index ca67bd4a1..b680af9a0 100644 --- a/src/CoiniumServ/config/pools/default-example.json +++ b/src/CoiniumServ/config/pools/default-example.json @@ -43,9 +43,9 @@ # blockRefresh: timeout in miliseconds to poll coin daemon for a new block. # rebroadcast: if now new blocks are found in this many seconds, a new job will be created and broadcasted. - "jobs": { - "blockRefresh": 1000, - "rebroadcast": 55 + "job": { + "blockRefreshInterval": 1000, + "rebroadcastTimeout": 55 }, # ------------------------------- @@ -82,13 +82,13 @@ # you can ban miners which submits invalid work / data to reduce system/network load. # duration: duration of ban when a miner gets flagged for so. # invalidPercent: percentage of invalid shares to trigger a ban. - # checkThreshold: mumber of shares required before a miner's shares are considered for a ban. + # checkThreshold: number of shares required before a miner's shares are considered for a ban. # purgeInterval: purge interval in seconds that bans are checked to see if they are expired. "banning": { "duration": 600, "invalidPercent": 50, - "checkThreshold": 500, + "checkThreshold": 100, "purgeInterval": 300 }, diff --git a/src/CoiniumServ/config/pools/detailed-example.json b/src/CoiniumServ/config/pools/detailed-example.json index 6bde2f05e..a44a81591 100644 --- a/src/CoiniumServ/config/pools/detailed-example.json +++ b/src/CoiniumServ/config/pools/detailed-example.json @@ -70,9 +70,9 @@ # rebroadcast: if now new blocks are found in this many seconds, a new job will be created and broadcasted. - "jobs": { - "blockRefresh": 1000, - "rebroadcast": 55 + "job": { + "blockRefreshInterval": 1000, + "rebroadcastTimeout": 55 }, # ------------------------------- @@ -116,14 +116,14 @@ # enabled: set this true to enable banning support. # duration: duration of ban when a miner gets flagged for so. # invalidPercent: percentage of invalid shares to trigger a ban. - # checkThreshold: mumber of shares required before a miner's shares are considered for a ban. + # checkThreshold: number of shares required before a miner's shares are considered for a ban. # purgeInterval: purge interval in seconds that bans are checked to see if they are expired. "banning": { "enabled": true, "duration": 600, "invalidPercent": 50, - "checkThreshold": 500, + "checkThreshold": 100, "purgeInterval": 300 }, From 0d9442369fc39c6faba8bcbaf7d08c7c7ddf0054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 23 Jul 2014 02:28:33 +0300 Subject: [PATCH 123/230] Config reader improvements. --- src/CoiniumServ/Coin/Config/CoinConfig.cs | 24 ++++++++++------ src/CoiniumServ/Coin/Config/ICoinConfig.cs | 12 ++++++++ src/CoiniumServ/Daemon/Config/DaemonConfig.cs | 28 +++++++++++++------ .../Daemon/Config/IDaemonConfig.cs | 12 ++++++++ .../Mining/Pools/Config/BanConfig.cs | 2 +- .../Mining/Pools/Config/IPoolConfig.cs | 1 - .../Mining/Pools/Config/IWalletConfig.cs | 7 ++++- .../Mining/Pools/Config/JobConfig.cs | 2 +- .../Mining/Pools/Config/MinerConfig.cs | 2 +- .../Mining/Pools/Config/RewardsConfig.cs | 26 +++++++++++++---- .../Mining/Pools/Config/WalletConfig.cs | 16 ++++++++++- 11 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index 675e753cd..79bd6b962 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -20,6 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; +using Serilog; + namespace CoiniumServ.Coin.Config { public class CoinConfig : ICoinConfig @@ -32,18 +36,20 @@ public class CoinConfig : ICoinConfig public CoinConfig(dynamic config) { - if (config == null) + try + { + Name = config.name; + Symbol = config.symbol; + Algorithm = config.algorithm; + Options = config; + + Valid = true; + } + catch (Exception e) { Valid = false; - return; + Log.Logger.ForContext().Error(e, "Error loading coin configuration"); } - - Name = config.name; - Symbol = config.symbol; - Algorithm = config.algorithm; - Options = config; - - Valid = true; } } } diff --git a/src/CoiniumServ/Coin/Config/ICoinConfig.cs b/src/CoiniumServ/Coin/Config/ICoinConfig.cs index d2389f9fb..1cc5ad657 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfig.cs @@ -27,12 +27,24 @@ namespace CoiniumServ.Coin.Config { public interface ICoinConfig:IConfig { + /// + /// name of the coin + /// string Name { get; } + /// + /// 3 or 4 letter symbol for the coin + /// string Symbol { get; } + /// + /// The algorithm used by the coin. + /// string Algorithm { get; } + /// + /// Extra options provided that will be passed to coin algorithm. + /// dynamic Options { get; } } } diff --git a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs index 3d1fee000..9f9da4a4d 100644 --- a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs @@ -20,6 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; +using Serilog; + namespace CoiniumServ.Daemon.Config { public class DaemonConfig:IDaemonConfig @@ -36,18 +40,24 @@ public class DaemonConfig:IDaemonConfig public DaemonConfig(dynamic config) { - if (config == null) + try { - Valid = false; - return; - } + // set the defaults; + Host = "0.0.0.0"; - Host = !string.IsNullOrEmpty(config.host) ? config.host : "0.0.0.0"; - Port = config.port; - Username = config.username; - Password = config.password; + // load the config data. + Host = config.host; + Port = config.port; + Username = config.username; + Password = config.password; - Valid = true; + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading daemon configuration"); + } } } } diff --git a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs index 7cf6c751e..3af15555f 100644 --- a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs @@ -28,12 +28,24 @@ namespace CoiniumServ.Daemon.Config { public interface IDaemonConfig:IConfig { + /// + /// ip/hostname of coin-daemon. + /// string Host { get; } + /// + /// the port coin daemon is listening on. + /// Int32 Port { get; } + /// + /// username for rpc connection. + /// string Username { get; } + /// + /// password for rpc connection. + /// string Password { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs index 378521aed..d045279d7 100644 --- a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs @@ -56,8 +56,8 @@ public BanConfig(dynamic config) } catch (Exception e) { - Log.Logger.ForContext().Error(e, "Error loading banning configuration"); Valid = false; + Log.Logger.ForContext().Error(e, "Error loading banning configuration"); } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 2292ebf91..0fc5ed57e 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -23,7 +23,6 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; -using CoiniumServ.Mining.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum.Config; diff --git a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs index 5c3deba42..c50abf728 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs @@ -21,10 +21,15 @@ // #endregion +using CoiniumServ.Utils.Configuration; + namespace CoiniumServ.Mining.Pools.Config { - public interface IWalletConfig + public interface IWalletConfig:IConfig { + /// + /// Address that generated coins will arrive. + /// string Adress { get; } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs b/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs index bcc5bbe91..98da97f07 100644 --- a/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs @@ -48,8 +48,8 @@ public JobConfig(dynamic config) } catch (Exception e) { - Log.Logger.ForContext().Error(e, "Error loading job configuration"); Valid = false; + Log.Logger.ForContext().Error(e, "Error loading job configuration"); } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs b/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs index ad05c3326..74aa87c28 100644 --- a/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs @@ -48,8 +48,8 @@ public MinerConfig(dynamic config) } catch (Exception e) { - Log.Logger.ForContext().Error(e, "Error loading miner configuration"); Valid = false; + Log.Logger.ForContext().Error(e, "Error loading miner configuration"); } } } diff --git a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs index c9b420f69..49f4690e6 100644 --- a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs @@ -21,27 +21,41 @@ // #endregion +using System; using System.Collections; using System.Collections.Generic; using JsonConfig; +using Serilog; namespace CoiniumServ.Mining.Pools.Config { public class RewardsConfig:IRewardsConfig { public bool Valid { get; private set; } + + /// + /// list of addresses that gets a percentage from each mined block (ie, pool fee.) + /// private readonly Dictionary _rewards; public RewardsConfig(dynamic config) { - _rewards = new Dictionary(); + try + { + _rewards = new Dictionary(); - // weird stuff going below because of JsonConfig libraries handling of dictionaries. - foreach (ConfigObject kvp in config) - foreach (KeyValuePair pair in kvp) - _rewards.Add(pair.Key, float.Parse(pair.Value.ToString())); + // weird stuff going below because of JsonConfig libraries handling of dictionaries. + foreach (ConfigObject kvp in config) + foreach (KeyValuePair pair in kvp) + _rewards.Add(pair.Key, float.Parse(pair.Value.ToString())); - Valid = true; + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading rewards configuration"); + } } public IEnumerator> GetEnumerator() diff --git a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs index c5d1dbe07..514101e9b 100644 --- a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs @@ -21,15 +21,29 @@ // #endregion +using System; +using Serilog; + namespace CoiniumServ.Mining.Pools.Config { public class WalletConfig:IWalletConfig { public string Adress { get; private set; } + public bool Valid { get; private set; } public WalletConfig(dynamic config) { - Adress = config.address; + try + { + Adress = config.address; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading wallet configuration"); + } } } } From 2bf501da44c280b26ef8d9c94fa4f9a198536f0a Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 13:15:41 +0300 Subject: [PATCH 124/230] config-example.json update & documentation. Improved more config readers. HttpListener for web-server will now correctly handle httplistener and invalidoperation exceptions. --- .../Mining/Vardiff/IVardiffConfig.cs | 19 ++++- .../Mining/Vardiff/VardiffConfig.cs | 34 ++++++-- .../Net/Server/Http/Web/HttpServer.cs | 13 ++- src/CoiniumServ/Payments/IPaymentConfig.cs | 6 ++ src/CoiniumServ/Payments/PaymentConfig.cs | 26 ++++-- src/CoiniumServ/Persistance/IStorageConfig.cs | 4 +- .../Persistance/Redis/IRedisConfig.cs | 17 +++- .../Persistance/Redis/RedisConfig.cs | 26 ++++-- .../Server/Mining/IMiningServerConfig.cs | 8 +- .../Stratum/Config/IStratumServerConfig.cs | 6 ++ .../Stratum/Config/StratumServerConfig.cs | 32 ++++---- .../Vanilla/Config/VanillaServerConfig.cs | 28 ++++--- .../Server/Web/IWebServerConfig.cs | 9 ++- src/CoiniumServ/Server/Web/WebServerConfig.cs | 27 ++++++- .../Utils/Configuration/IConfigManager.cs | 1 - src/CoiniumServ/Utils/Logging/ILogConfig.cs | 9 ++- src/CoiniumServ/Utils/Logging/ILogTarget.cs | 24 +++++- src/CoiniumServ/Utils/Logging/LogConfig.cs | 22 ++++- src/CoiniumServ/Utils/Logging/LogTarget.cs | 81 +++++++++++-------- src/CoiniumServ/config/config-example.json | 14 +++- 20 files changed, 304 insertions(+), 102 deletions(-) diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs index c4f9e3509..c22a443c0 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs +++ b/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs @@ -21,20 +21,37 @@ // #endregion +using CoiniumServ.Utils.Configuration; + namespace CoiniumServ.Mining.Vardiff { - public interface IVardiffConfig + public interface IVardiffConfig : IConfig { bool Enabled { get; } + /// + /// minimum difficulty that can be assigned to miners. + /// int MinimumDifficulty { get; } + /// + /// maximum difficulty that can be assigned to miners. + /// int MaximumDifficulty { get; } + /// + /// try to get a single share per this many seconds from miner. + /// int TargetTime { get; } + /// + /// retarget a miners difficulty ever this many seconds. + /// int RetargetTime { get; } + /// + /// allow difficulty for a miner to vary this percent without retargeting. + /// int VariancePercent { get; } } } diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs index 6cca10977..3f912e0b6 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs +++ b/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs @@ -21,6 +21,9 @@ // #endregion +using System; +using Serilog; + namespace CoiniumServ.Mining.Vardiff { public class VardiffConfig:IVardiffConfig @@ -31,15 +34,34 @@ public class VardiffConfig:IVardiffConfig public int TargetTime { get; private set; } public int RetargetTime { get; private set; } public int VariancePercent { get; private set; } + public bool Valid { get; private set; } public VardiffConfig(dynamic config) { - Enabled = config.enabled; - MinimumDifficulty = config.minDiff; - MaximumDifficulty = config.maxDiff; - TargetTime = config.targetTime; - RetargetTime = config.retargetTime; - VariancePercent = config.variancePercent; + try + { + // set the defaults; + MinimumDifficulty = 8; + MaximumDifficulty = 512; + TargetTime = 15; + RetargetTime = 90; + VariancePercent = 30; + + // load the config data. + Enabled = config.enabled; + MinimumDifficulty = config.minDiff; + MaximumDifficulty = config.maxDiff; + TargetTime = config.targetTime; + RetargetTime = config.retargetTime; + VariancePercent = config.variancePercent; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading vardiff configuration"); + } } } } diff --git a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs index b5082bc71..ba8be94b9 100644 --- a/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Net/Server/Http/Web/HttpServer.cs @@ -22,6 +22,7 @@ #endregion using System; +using System.Net; using CoiniumServ.Repository.Context; using Nancy.Bootstrapper; using Nancy.Hosting.Self; @@ -59,13 +60,12 @@ public HttpServer(INancyBootstrapper webBootstrapper) public bool Start() { var uri = new Uri(string.Format("http://{0}:{1}", BindIP, Port)); - _logger.Information("Web-server listening on: {0:l}", uri); var hostConfiguration = new HostConfiguration(); hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; hostConfiguration.UrlReservations.CreateAutomatically = true; - var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); + var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); try { @@ -74,11 +74,18 @@ public bool Start() } catch (InvalidOperationException e) // nancy requires elevated privileges to run on port 80. { - _logger.Error("Need elevated privileges to listen on port {0}. [Error: {1}].", Port, e); + _logger.Error("Need elevated privileges to listen on port {0}. Try running as administrator or root.", Port); + IsListening = false; + return false; + } + catch (HttpListenerException e) + { + _logger.Error("Can not listen on requested interface: {0:l}",BindIP); IsListening = false; return false; } + _logger.Information("Web-server listening on: {0:l}", uri); return true; } diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs index d14770bc6..d449cd3d8 100644 --- a/src/CoiniumServ/Payments/IPaymentConfig.cs +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -30,8 +30,14 @@ public interface IPaymentConfig:IConfig { bool Enabled { get; } + /// + /// interval in seconds that payment-processor will be running. + /// Int32 Interval { get; } + /// + /// minimum amount of coins before a miner is eligable for getting a payment. + /// double Minimum { get; } } } diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs index 7f9a7db4e..40491bed5 100644 --- a/src/CoiniumServ/Payments/PaymentConfig.cs +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -21,6 +21,9 @@ // #endregion +using System; +using Serilog; + namespace CoiniumServ.Payments { public class PaymentConfig:IPaymentConfig @@ -32,17 +35,24 @@ public class PaymentConfig:IPaymentConfig public PaymentConfig(dynamic config) { - if (config == null) + try + { + // set the defaults; + Interval = 60; + Minimum = 0.01; + + // load the config data. + Enabled = config.enabled; + Interval = config.interval; + Minimum = config.minimum; + + Valid = true; + } + catch (Exception e) { Valid = false; - return; + Log.Logger.ForContext().Error(e, "Error loading payment configuration"); } - - Enabled = config.enabled; - Interval = config.interval; - Minimum = config.minimum; - - Valid = true; } } } diff --git a/src/CoiniumServ/Persistance/IStorageConfig.cs b/src/CoiniumServ/Persistance/IStorageConfig.cs index 49b4abeb9..5b805fb59 100644 --- a/src/CoiniumServ/Persistance/IStorageConfig.cs +++ b/src/CoiniumServ/Persistance/IStorageConfig.cs @@ -21,9 +21,11 @@ // #endregion +using CoiniumServ.Utils.Configuration; + namespace CoiniumServ.Persistance { - public interface IStorageConfig + public interface IStorageConfig:IConfig { } } diff --git a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs index c0bc63fe6..7ce27f23e 100644 --- a/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/IRedisConfig.cs @@ -22,16 +22,31 @@ #endregion using System; -using CoiniumServ.Mining.Pools.Config; namespace CoiniumServ.Persistance.Redis { public interface IRedisConfig : IStorageConfig { bool Enabled { get; } + + /// + /// redis host. + /// string Host { get; } + + /// + /// redis port. + /// Int32 Port { get; } + + /// + /// the password if redis installation requires one. + /// string Password { get; } + + /// + /// redis database instance id + /// int DatabaseId { get; } } } diff --git a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs index 3a49e1f79..46c271e56 100644 --- a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs @@ -22,6 +22,7 @@ #endregion using System; +using Serilog; namespace CoiniumServ.Persistance.Redis { @@ -32,14 +33,29 @@ public class RedisConfig:IRedisConfig public Int32 Port { get; private set; } public string Password { get; private set; } public int DatabaseId { get; private set; } + public bool Valid { get; private set; } public RedisConfig(dynamic config) { - Enabled = config.enabled; - Host = config.host; - Port = config.port; - Password = config.password; - DatabaseId = config.databaseId; + try + { + // set the defaults; + Host = "127.0.0.1"; + Port = 6379; + DatabaseId = 0; + + // load the config data. + Enabled = config.enabled; + Host = config.host; + Port = config.port; + Password = config.password; + DatabaseId = config.databaseId; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading redis configuration"); + } } } } diff --git a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs index e29caa9fd..06e85ace9 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs @@ -28,12 +28,16 @@ namespace CoiniumServ.Server.Mining { public interface IServerConfig:IConfig { - string Name { get; } - bool Enabled { get; } + /// + /// interface to bind server. + /// string BindInterface { get; } + /// + /// port to listen for connections. + /// Int32 Port { get; } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index 88c724a6c..ff00a1fdc 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -28,8 +28,14 @@ namespace CoiniumServ.Server.Mining.Stratum.Config { public interface IStratumServerConfig : IServerConfig { + /// + /// default difficulty assigned to newly connected miners. + /// Int32 Diff { get; } + /// + /// vardiff configuration. + /// IVardiffConfig Vardiff { get; } } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index 7ce850f3a..02336699a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -23,7 +23,7 @@ using System; using CoiniumServ.Mining.Vardiff; -using CoiniumServ.Server.Mining.Service; +using Serilog; namespace CoiniumServ.Server.Mining.Stratum.Config { @@ -31,8 +31,6 @@ public class StratumServerConfig:IStratumServerConfig { public bool Valid { get; private set; } - public string Name { get; private set; } - public bool Enabled { get; private set; } public string BindInterface { get; private set; } @@ -44,21 +42,25 @@ public class StratumServerConfig:IStratumServerConfig public StratumServerConfig(dynamic config) { - if (config == null) + try { - Valid = false; - return; - } - - Name = Services.Stratum; - Enabled = config.enabled; - BindInterface = !string.IsNullOrEmpty(config.bind) ? config.bind : "0.0.0.0"; - Port = config.port; - Diff = config.diff; + // set the defaults; + BindInterface = "0.0.0.0"; - Vardiff = new VardiffConfig(config.vardiff); + // load the config data. + Enabled = config.enabled; + BindInterface = config.bind; + Port = config.port; + Diff = config.diff; + Vardiff = new VardiffConfig(config.vardiff); - Valid = true; + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading stratum server configuration"); + } } } } diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs index 05ffa376d..468c47bba 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Server.Mining.Service; +using Serilog; namespace CoiniumServ.Server.Mining.Vanilla.Config { @@ -30,8 +30,6 @@ public class VanillaServerConfig : IVanillaServerConfig { public bool Valid { get; private set; } - public string Name { get; private set; } - public bool Enabled { get; private set; } public string BindInterface { get; private set; } @@ -40,18 +38,24 @@ public class VanillaServerConfig : IVanillaServerConfig public VanillaServerConfig(dynamic config) { - if (config == null) + try { - Valid = false; - return; - } + // set the defaults; + BindInterface = "0.0.0.0"; + + // load the config data. + Enabled = config.enabled; + BindInterface = config.bind; + Port = config.port; - Name = Services.Vanilla; - Enabled = config.enabled; - BindInterface = !string.IsNullOrEmpty(config.bind) ? config.bind : "localhost"; - Port = config.port; + Valid = true; + } - Valid = true; + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading vannila server configuration"); + } } } } diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index a09196924..002fabd74 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -22,15 +22,22 @@ #endregion using System; +using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Server.Web { - public interface IWebServerConfig + public interface IWebServerConfig:IConfig { bool Enabled { get; } + /// + /// interface to bind webserver. + /// string BindInterface { get; } + /// + /// port to listen for http connections. + /// Int32 Port { get; } } } diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index e175bd542..90c1f91e2 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -20,6 +20,10 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; +using Serilog; + namespace CoiniumServ.Server.Web { public class WebServerConfig : IWebServerConfig @@ -27,12 +31,27 @@ public class WebServerConfig : IWebServerConfig public bool Enabled { get; private set; } public string BindInterface { get; private set; } public int Port { get; private set; } - + public bool Valid { get; private set; } public WebServerConfig(dynamic config) { - Enabled = config.enabled; - BindInterface = config.bind; - Port = config.port; + try + { + // set the defaults; + BindInterface = "127.0.0.1"; + Port = 80; + + // load the config data. + Enabled = config.enabled; + BindInterface = config.bind; + Port = config.port; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading web-server configuration"); + } } } } diff --git a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs index 5575c8564..300f55737 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs +++ b/src/CoiniumServ/Utils/Configuration/IConfigManager.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Persistance.Redis; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Logging; diff --git a/src/CoiniumServ/Utils/Logging/ILogConfig.cs b/src/CoiniumServ/Utils/Logging/ILogConfig.cs index e72cda913..3c9b68d50 100644 --- a/src/CoiniumServ/Utils/Logging/ILogConfig.cs +++ b/src/CoiniumServ/Utils/Logging/ILogConfig.cs @@ -22,13 +22,20 @@ #endregion using System.Collections.Generic; +using CoiniumServ.Utils.Configuration; namespace CoiniumServ.Utils.Logging { - public interface ILogConfig + public interface ILogConfig : IConfig { + /// + /// relative path of logs. + /// string Root { get; } + /// + /// log targets. + /// List Targets { get; } } } diff --git a/src/CoiniumServ/Utils/Logging/ILogTarget.cs b/src/CoiniumServ/Utils/Logging/ILogTarget.cs index 5ff5f01b4..642e8f403 100644 --- a/src/CoiniumServ/Utils/Logging/ILogTarget.cs +++ b/src/CoiniumServ/Utils/Logging/ILogTarget.cs @@ -21,27 +21,49 @@ // #endregion +using CoiniumServ.Utils.Configuration; using Serilog.Events; namespace CoiniumServ.Utils.Logging { - public interface ILogTarget + public interface ILogTarget: IConfig { bool Enabled { get; } + /// + /// console, file or packet. + /// LogTargetType Type { get; } + /// + /// filename of the log file. + /// string Filename { get; } + /// + /// set this true to get a seperate log file for every day. + /// bool Rolling { get; } + /// + /// minimum log level. + /// LogEventLevel Level { get; } } public enum LogTargetType { + /// + /// Logs to console. + /// Console, + /// + /// Logs to a file. + /// File, + /// + /// Logs network packets to a file. + /// Packet } } diff --git a/src/CoiniumServ/Utils/Logging/LogConfig.cs b/src/CoiniumServ/Utils/Logging/LogConfig.cs index b92bbe144..d582e2ca8 100644 --- a/src/CoiniumServ/Utils/Logging/LogConfig.cs +++ b/src/CoiniumServ/Utils/Logging/LogConfig.cs @@ -21,7 +21,10 @@ // #endregion +using System; using System.Collections.Generic; +using CoiniumServ.Mining.Pools.Config; +using Serilog; namespace CoiniumServ.Utils.Logging { @@ -29,15 +32,26 @@ public class LogConfig : ILogConfig { public string Root { get; private set; } public List Targets { get; private set; } + public bool Valid { get; private set; } public LogConfig(dynamic config) { - Root = config.root; + try + { + Root = config.root; + + Targets = new List(); + foreach (var target in config.targets) + { + Targets.Add(new LogTarget(target)); + } - Targets = new List(); - foreach (var target in config.targets) + Valid = true; + } + catch (Exception e) { - Targets.Add(new LogTarget(target)); + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading logging configuration"); } } } diff --git a/src/CoiniumServ/Utils/Logging/LogTarget.cs b/src/CoiniumServ/Utils/Logging/LogTarget.cs index f7cdc2e82..182d94075 100644 --- a/src/CoiniumServ/Utils/Logging/LogTarget.cs +++ b/src/CoiniumServ/Utils/Logging/LogTarget.cs @@ -34,47 +34,58 @@ public class LogTarget:ILogTarget public string Filename { get; private set; } public bool Rolling { get; private set; } public LogEventLevel Level { get; private set; } + public bool Valid { get; private set; } public LogTarget(dynamic config) { - Enabled = config.enabled; - Filename = config.filename; - Rolling = config.rolling; - - switch ((string) config.type) + try { - case "console": - Type = LogTargetType.Console; - break; - case "file": - Type = LogTargetType.File; - break; - case "packet": - Type = LogTargetType.Packet; - break; - } + Enabled = config.enabled; + Filename = config.filename; + Rolling = config.rolling; + + switch ((string) config.type) + { + case "console": + Type = LogTargetType.Console; + break; + case "file": + Type = LogTargetType.File; + break; + case "packet": + Type = LogTargetType.Packet; + break; + } - switch ((string) config.level) + switch ((string) config.level) + { + case "verbose": + Level = LogEventLevel.Verbose; + break; + case "debug": + Level = LogEventLevel.Debug; + break; + case "information": + Level = LogEventLevel.Information; + break; + case "warning": + Level = LogEventLevel.Warning; + break; + case "error": + Level = LogEventLevel.Error; + break; + case "fatal": + Level = LogEventLevel.Fatal; + break; + } + + Valid = true; + } + catch (Exception e) { - case "verbose": - Level = LogEventLevel.Verbose; - break; - case "debug": - Level = LogEventLevel.Debug; - break; - case "information": - Level = LogEventLevel.Information; - break; - case "warning": - Level = LogEventLevel.Warning; - break; - case "error": - Level = LogEventLevel.Error; - break; - case "fatal": - Level = LogEventLevel.Fatal; - break; + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading log target configuration"); } - } + } } } diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index 13d896225..daf92bac9 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -4,18 +4,30 @@ # ------------------------------- # enabled: set this true to enable frontend. + # bind: interface to bind webserver. + # port: port to listen for http connections. # website configuration "website": { "enabled": true, "bind": "127.0.0.1", - "port": 91 + "port": 80 }, # ------------------------------- # Logging Configuration # ------------------------------- + # root: relative path of logs. + # targets: log targets. + + # target: + # enabled: is the log target enabled? + # type: console, file or packet. + # filename: filename of the log file. + # rolling: set this true to get a seperate log file for every day. + # level: minimum log level. + # logging configuration "logging": { "root": "logs", From 7f823d6f74fe6c914383f8ad802fc8a0d22a0f73 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 13:24:34 +0300 Subject: [PATCH 125/230] Improved pool config reader. --- .../Mining/Pools/Config/IPoolConfig.cs | 4 +- .../Mining/Pools/Config/PoolConfig.cs | 96 ++++++------------- 2 files changed, 30 insertions(+), 70 deletions(-) diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 0fc5ed57e..57b59e233 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -38,10 +38,10 @@ public interface IPoolConfig:IConfig /// bool Enabled { get; } - IDaemonConfig Daemon { get; } - ICoinConfig Coin { get; } + IDaemonConfig Daemon { get; } + IWalletConfig Wallet { get; } IRewardsConfig Rewards { get; } diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index 78fa0b5e2..c5076687c 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -21,6 +21,7 @@ // #endregion +using System; using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; using CoiniumServ.Payments; @@ -28,6 +29,7 @@ using CoiniumServ.Persistance.Redis; using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Vanilla.Config; +using Serilog; namespace CoiniumServ.Mining.Pools.Config { @@ -37,29 +39,18 @@ namespace CoiniumServ.Mining.Pools.Config public class PoolConfig : IPoolConfig { public bool Valid { get; private set; } - public bool Enabled { get; private set; } - public IWalletConfig Wallet { get; private set; } - public ICoinConfig Coin { get; private set; } - - public IMinerConfig Miner { get; private set; } - public IJobConfig Job { get; private set; } - public IStratumServerConfig Stratum { get; private set; } - - public IVanillaServerConfig Vanilla { get; private set; } - - /// - /// Gets the daemon configuration. - /// public IDaemonConfig Daemon { get; private set; } - + public IWalletConfig Wallet { get; private set; } public IRewardsConfig Rewards { get; private set; } - public IPaymentConfig Payments { get; private set; } - + public IMinerConfig Miner { get; private set; } + public IJobConfig Job { get; private set; } + public IStratumServerConfig Stratum { get; private set; } public IBanConfig Banning { get; private set; } public IStorageConfig Storage { get; private set; } + public IVanillaServerConfig Vanilla { get; private set; } /// /// Initializes a new instance of the class. @@ -68,63 +59,32 @@ public class PoolConfig : IPoolConfig /// public PoolConfig(dynamic config, ICoinConfig coinConfig) { - - if (config == null) + try { - Valid = false; - return; + Enabled = config.enabled ? config.enabled : false; + + if (Enabled == false) // if the configuration is not enabled + return; // just skip reading rest of the parameters. + + Coin = coinConfig; + Daemon = new DaemonConfig(config.daemon); + Wallet = new WalletConfig(config.wallet); + Rewards = new RewardsConfig(config.rewards); + Payments = new PaymentConfig(config.payments); + Miner = new MinerConfig(config.miner); + Job = new JobConfig(config.job); + Stratum = new StratumServerConfig(config.stratum); + Banning = new BanConfig(config.banning); + Storage = new RedisConfig(config.storage.redis); + Vanilla = new VanillaServerConfig(config.vanilla); + + Valid = true; } - - Enabled = config.enabled ? config.enabled : false; - - if (Enabled == false) - return; - - Miner = new MinerConfig(config.miner); - - Job = new JobConfig(config.job); - - - Wallet = new WalletConfig(config.wallet); - Rewards = new RewardsConfig(config.rewards); - - Coin = coinConfig; - - if (Coin == null) + catch (Exception e) { Valid = false; - return; + Log.Logger.ForContext().Error(e, "Error loading pool configuration"); } - - Stratum = new StratumServerConfig(config.stratum); - Vanilla = new VanillaServerConfig(config.vanilla); - - if (Stratum == null && Vanilla == null) - { - Valid = false; - return; - } - - Daemon = new DaemonConfig(config.daemon); - - if (Daemon == null) - { - Valid = false; - return; - } - - Payments = new PaymentConfig(config.payments); - if (Payments == null) - { - Valid = false; - return; - } - - Banning = new BanConfig(config.banning); - - Storage = new RedisConfig(config.storage.redis); - - Valid = true; } } } From 52b2c8721bac2af05e48bd3e153165e252048d26 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 13:27:30 +0300 Subject: [PATCH 126/230] Moved config readers to respective folders. --- src/CoiniumServ/CoiniumServ.csproj | 20 +++++++++---------- .../{Pools/Config => Banning}/BanConfig.cs | 2 +- .../{Pools/Config => Banning}/IBanConfig.cs | 2 +- .../Config => Jobs/Manager}/IJobConfig.cs | 2 +- .../Config => Jobs/Manager}/JobConfig.cs | 2 +- .../Mining/Jobs/Manager/JobManager.cs | 2 +- .../Mining/Pools/Config/IPoolConfig.cs | 2 ++ .../Mining/Pools/Config/PoolConfig.cs | 2 ++ .../Config => Payments}/IRewardsConfig.cs | 2 +- .../Config => Payments}/IWalletConfig.cs | 2 +- .../Config => Payments}/RewardsConfig.cs | 2 +- .../Pools/Config => Payments}/WalletConfig.cs | 2 +- .../Mining/Stratum}/Config/IMinerConfig.cs | 2 +- .../Mining/Stratum}/Config/MinerConfig.cs | 2 +- .../Transactions/GenerationTransaction.cs | 1 + src/Tests/Coin/Coinbase/SerializersTests.cs | 1 + src/Tests/Mining/Shares/ShareTests.cs | 2 +- .../Server/Stratum/Notifications/JobTests.cs | 1 + .../GenerationTransactionTests.cs | 1 + 19 files changed, 30 insertions(+), 22 deletions(-) rename src/CoiniumServ/Mining/{Pools/Config => Banning}/BanConfig.cs (98%) rename src/CoiniumServ/Mining/{Pools/Config => Banning}/IBanConfig.cs (97%) rename src/CoiniumServ/Mining/{Pools/Config => Jobs/Manager}/IJobConfig.cs (97%) rename src/CoiniumServ/Mining/{Pools/Config => Jobs/Manager}/JobConfig.cs (97%) rename src/CoiniumServ/{Mining/Pools/Config => Payments}/IRewardsConfig.cs (96%) rename src/CoiniumServ/{Mining/Pools/Config => Payments}/IWalletConfig.cs (96%) rename src/CoiniumServ/{Mining/Pools/Config => Payments}/RewardsConfig.cs (98%) rename src/CoiniumServ/{Mining/Pools/Config => Payments}/WalletConfig.cs (97%) rename src/CoiniumServ/{Mining/Pools => Server/Mining/Stratum}/Config/IMinerConfig.cs (96%) rename src/CoiniumServ/{Mining/Pools => Server/Mining/Stratum}/Config/MinerConfig.cs (97%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 47e42fce5..44435e7d6 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -128,17 +128,17 @@ - - - - - - - + + + + + + + - - - + + + diff --git a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs b/src/CoiniumServ/Mining/Banning/BanConfig.cs similarity index 98% rename from src/CoiniumServ/Mining/Pools/Config/BanConfig.cs rename to src/CoiniumServ/Mining/Banning/BanConfig.cs index d045279d7..83b0dd495 100644 --- a/src/CoiniumServ/Mining/Pools/Config/BanConfig.cs +++ b/src/CoiniumServ/Mining/Banning/BanConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Mining.Banning { public class BanConfig : IBanConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs b/src/CoiniumServ/Mining/Banning/IBanConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs rename to src/CoiniumServ/Mining/Banning/IBanConfig.cs index 33b2a3ba9..83c160105 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IBanConfig.cs +++ b/src/CoiniumServ/Mining/Banning/IBanConfig.cs @@ -23,7 +23,7 @@ using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Mining.Banning { public interface IBanConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs b/src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs rename to src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs index 0b417ca46..233eb7e99 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IJobConfig.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs @@ -23,7 +23,7 @@ using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Mining.Jobs.Manager { public interface IJobConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/JobConfig.cs rename to src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs index 98da97f07..f56fcfa1d 100644 --- a/src/CoiniumServ/Mining/Pools/Config/JobConfig.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Mining.Jobs.Manager { public class JobConfig : IJobConfig { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs index 6b2c1787f..43aebac78 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs @@ -23,7 +23,6 @@ using System; using System.Threading; -using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; @@ -31,6 +30,7 @@ using CoiniumServ.Mining.Miners; using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Mining.Shares; +using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Vanilla; diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs index 57b59e233..f02cdb42b 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs @@ -23,6 +23,8 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; +using CoiniumServ.Mining.Banning; +using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum.Config; diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs index c5076687c..ac91a76e3 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs @@ -24,6 +24,8 @@ using System; using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; +using CoiniumServ.Mining.Banning; +using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Redis; diff --git a/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs b/src/CoiniumServ/Payments/IRewardsConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs rename to src/CoiniumServ/Payments/IRewardsConfig.cs index 7bdc89d01..4daebdf14 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IRewardsConfig.cs +++ b/src/CoiniumServ/Payments/IRewardsConfig.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Payments { public interface IRewardsConfig :IEnumerable>, IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs b/src/CoiniumServ/Payments/IWalletConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs rename to src/CoiniumServ/Payments/IWalletConfig.cs index c50abf728..834b8947a 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IWalletConfig.cs +++ b/src/CoiniumServ/Payments/IWalletConfig.cs @@ -23,7 +23,7 @@ using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Payments { public interface IWalletConfig:IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs b/src/CoiniumServ/Payments/RewardsConfig.cs similarity index 98% rename from src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs rename to src/CoiniumServ/Payments/RewardsConfig.cs index 49f4690e6..783ae30a2 100644 --- a/src/CoiniumServ/Mining/Pools/Config/RewardsConfig.cs +++ b/src/CoiniumServ/Payments/RewardsConfig.cs @@ -27,7 +27,7 @@ using JsonConfig; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Payments { public class RewardsConfig:IRewardsConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs b/src/CoiniumServ/Payments/WalletConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs rename to src/CoiniumServ/Payments/WalletConfig.cs index 514101e9b..fc03bae11 100644 --- a/src/CoiniumServ/Mining/Pools/Config/WalletConfig.cs +++ b/src/CoiniumServ/Payments/WalletConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Payments { public class WalletConfig:IWalletConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs rename to src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs index a182d5fcb..ba13251a8 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IMinerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs @@ -23,7 +23,7 @@ using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Server.Mining.Stratum.Config { public interface IMinerConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs rename to src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs index 74aa87c28..33abd4314 100644 --- a/src/CoiniumServ/Mining/Pools/Config/MinerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Server.Mining.Stratum.Config { public class MinerConfig:IMinerConfig { diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index eb9a0e331..6c1a8ea84 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -31,6 +31,7 @@ using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Payments; using CoiniumServ.Transactions.Script; using CoiniumServ.Utils.Helpers.Time; using Gibbed.IO; diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index e0f8bbcac..c6013b953 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -30,6 +30,7 @@ using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Script; diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Mining/Shares/ShareTests.cs index 1701778a6..e7c189a8c 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Mining/Shares/ShareTests.cs @@ -30,8 +30,8 @@ using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Jobs.Manager; using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Mining.Shares; +using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Transactions; diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index 09f9feb6a..cdcc395b2 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -29,6 +29,7 @@ using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Script; diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index 15cadd299..b3a84959e 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -28,6 +28,7 @@ using CoiniumServ.Daemon.Responses; using CoiniumServ.Mining.Jobs; using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Payments; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Script; using CoiniumServ.Utils.Extensions; From fe5aaf8deda7375742b7730283126becd1acc39e Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 13:38:38 +0300 Subject: [PATCH 127/230] Re-factored namespaces. --- .../{Mining => }/Banning/BanConfig.cs | 2 +- .../{Mining => }/Banning/BanManager.cs | 10 +- .../{Mining => }/Banning/IBanConfig.cs | 4 +- .../{Mining => }/Banning/IBanManager.cs | 3 +- src/CoiniumServ/Coin/Config/ICoinConfig.cs | 2 +- src/CoiniumServ/CoiniumServ.csproj | 158 +++--- .../Configuration/ConfigManager.cs | 6 +- .../{Utils => }/Configuration/IConfig.cs | 2 +- .../Configuration/IConfigManager.cs | 6 +- .../Configuration/JsonConfigReader.cs | 2 +- .../Daemon/Config/IDaemonConfig.cs | 2 +- src/CoiniumServ/Daemon/DaemonBase.cs | 2 +- src/CoiniumServ/Factories/ConfigFactory.cs | 4 +- src/CoiniumServ/Factories/IConfigFactory.cs | 4 +- src/CoiniumServ/Factories/IObjectFactory.cs | 20 +- src/CoiniumServ/Factories/ObjectFactory.cs | 20 +- .../{Mining => }/Jobs/ExtraNonce.cs | 2 +- .../{Mining => }/Jobs/IExtraNonce.cs | 2 +- .../{Mining => }/Jobs/IJobCounter.cs | 2 +- .../{Mining => }/Jobs/JobCounter.cs | 2 +- .../{Mining => }/Jobs/Manager/IJobConfig.cs | 4 +- .../{Mining => }/Jobs/Manager/IJobManager.cs | 2 +- .../{Mining => }/Jobs/Manager/JobConfig.cs | 2 +- .../{Mining => }/Jobs/Manager/JobManager.cs | 9 +- .../{Mining => }/Jobs/Tracker/IJobTracker.cs | 2 +- .../{Mining => }/Jobs/Tracker/JobTracker.cs | 2 +- .../{Utils => }/Logging/ILogConfig.cs | 4 +- .../{Utils => }/Logging/ILogManager.cs | 2 +- .../{Utils => }/Logging/ILogTarget.cs | 4 +- .../{Utils => }/Logging/LogConfig.cs | 3 +- .../{Utils => }/Logging/LogManager.cs | 5 +- .../{Utils => }/Logging/LogTarget.cs | 2 +- src/CoiniumServ/{Mining => }/Miners/IMiner.cs | 4 +- .../Stratum/Config => Miners}/IMinerConfig.cs | 4 +- .../{Mining => }/Miners/IMinerManager.cs | 6 +- .../Stratum/Config => Miners}/MinerConfig.cs | 2 +- .../{Mining => }/Miners/MinerEventArgs.cs | 2 +- .../{Mining => }/Miners/MinerManager.cs | 7 +- .../Server/Http/Basic/HttpServer.cs | 166 +++++++ .../Server/Http/Web/ErrorConfiguration.cs | 39 ++ .../Networking/Server/Http/Web/HttpServer.cs | 110 +++++ .../Server/Http/Web/RootPathProvider.cs | 39 ++ .../Server/Http/Web/WebBootstrapper.cs | 86 ++++ src/CoiniumServ/Networking/Server/IServer.cs | 58 +++ .../Sockets/BannedConnectionEventArgs.cs | 38 ++ .../Networking/Server/Sockets/Connection.cs | 246 ++++++++++ .../Server/Sockets/ConnectionDataEventArgs.cs | 46 ++ .../Server/Sockets/ConnectionEventArgs.cs | 47 ++ .../Networking/Server/Sockets/IClient.cs | 35 ++ .../Networking/Server/Sockets/IConnection.cs | 118 +++++ .../Server/Sockets/ISocketServer.cs | 38 ++ .../Networking/Server/Sockets/SocketServer.cs | 454 ++++++++++++++++++ src/CoiniumServ/Payments/IPaymentConfig.cs | 2 +- src/CoiniumServ/Payments/IRewardsConfig.cs | 2 +- src/CoiniumServ/Payments/IWalletConfig.cs | 2 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 1 - src/CoiniumServ/Persistance/IStorage.cs | 2 +- src/CoiniumServ/Persistance/IStorageConfig.cs | 2 +- src/CoiniumServ/Persistance/Redis/Redis.cs | 5 +- .../{Mining => }/Pools/Config/IPoolConfig.cs | 9 +- .../{Mining => }/Pools/Config/PoolConfig.cs | 7 +- src/CoiniumServ/{Mining => }/Pools/IPool.cs | 6 +- .../{Mining => }/Pools/IPoolManager.cs | 2 +- src/CoiniumServ/{Mining => }/Pools/Pool.cs | 19 +- .../{Mining => }/Pools/PoolManager.cs | 4 +- src/CoiniumServ/Program.cs | 1 - .../Repository/Registries/ClassRegistry.cs | 17 +- .../Repository/Registries/ManagerRegistry.cs | 14 +- .../Server/Mining/IMiningServer.cs | 2 +- .../Server/Mining/IMiningServerConfig.cs | 2 +- .../Stratum/Config/IStratumServerConfig.cs | 2 +- .../Stratum/Config/StratumServerConfig.cs | 2 +- .../Server/Mining/Stratum/IStratumMiner.cs | 4 +- .../Stratum/Service/SocketServiceContext.cs | 2 +- .../Mining/Stratum/Service/StratumService.cs | 4 +- .../Server/Mining/Stratum/StratumMiner.cs | 8 +- .../Server/Mining/Stratum/StratumServer.cs | 10 +- .../Server/Mining/Vanilla/IVanillaMiner.cs | 2 +- .../Vanilla/Service/HttpServiceContext.cs | 2 +- .../Mining/Vanilla/Service/VanillaService.cs | 2 +- .../Server/Mining/Vanilla/VanillaMiner.cs | 6 +- .../Server/Mining/Vanilla/VanillaServer.cs | 8 +- src/CoiniumServ/Server/Web/IWebServer.cs | 2 +- .../Server/Web/IWebServerConfig.cs | 2 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 4 +- src/CoiniumServ/Server/Web/Modules/Index.cs | 4 +- src/CoiniumServ/Server/Web/Modules/Pool.cs | 2 +- src/CoiniumServ/Server/Web/WebServer.cs | 4 +- src/CoiniumServ/{Mining => }/Shares/IShare.cs | 4 +- .../{Mining => }/Shares/IShareManager.cs | 2 +- src/CoiniumServ/{Mining => }/Shares/Share.cs | 4 +- .../{Mining => }/Shares/ShareError.cs | 2 +- .../{Mining => }/Shares/ShareEventArgs.cs | 2 +- .../{Mining => }/Shares/ShareManager.cs | 5 +- .../Pools => }/Statistics/Algorithms.cs | 3 +- .../{Mining/Pools => }/Statistics/Blocks.cs | 2 +- .../{Mining/Pools => }/Statistics/Global.cs | 2 +- .../Pools => }/Statistics/IAlgorithms.cs | 2 +- .../{Mining/Pools => }/Statistics/IBlocks.cs | 2 +- .../{Mining/Pools => }/Statistics/IGlobal.cs | 2 +- .../Pools => }/Statistics/IJsonResponse.cs | 2 +- .../Pools => }/Statistics/ILatestBlocks.cs | 2 +- .../Pools => }/Statistics/IPerAlgorithm.cs | 2 +- .../{Mining/Pools => }/Statistics/IPerPool.cs | 4 +- .../{Mining/Pools => }/Statistics/IPools.cs | 2 +- .../Pools => }/Statistics/IStatistics.cs | 2 +- .../Statistics/IStatisticsProvider.cs | 2 +- .../Pools => }/Statistics/LatestBlocks.cs | 2 +- .../Pools => }/Statistics/PerAlgorithm.cs | 2 +- .../{Mining/Pools => }/Statistics/PerPool.cs | 6 +- .../{Mining/Pools => }/Statistics/Pools.cs | 3 +- .../Pools => }/Statistics/Statistics.cs | 2 +- .../Transactions/GenerationTransaction.cs | 3 +- .../{Mining => }/Vardiff/IVardiffConfig.cs | 4 +- .../{Mining => }/Vardiff/IVardiffManager.cs | 2 +- .../{Mining => }/Vardiff/IVardiffMiner.cs | 2 +- .../{Mining => }/Vardiff/VardiffConfig.cs | 2 +- .../{Mining => }/Vardiff/VardiffManager.cs | 4 +- src/CoiniumServ/web/default/pool.cshtml | 6 +- src/Tests/Coin/Coinbase/SerializersTests.cs | 3 +- src/Tests/{Mining => }/Pools/PoolTests.cs | 6 +- .../Server/Stratum/Notifications/JobTests.cs | 3 +- src/Tests/{Mining => }/Shares/ShareTests.cs | 10 +- src/Tests/Tests.csproj | 4 +- .../GenerationTransactionTests.cs | 3 +- .../Script/SignatureScriptTests.cs | 2 +- 126 files changed, 1816 insertions(+), 311 deletions(-) rename src/CoiniumServ/{Mining => }/Banning/BanConfig.cs (98%) rename src/CoiniumServ/{Mining => }/Banning/BanManager.cs (96%) rename src/CoiniumServ/{Mining => }/Banning/IBanConfig.cs (95%) rename src/CoiniumServ/{Mining => }/Banning/IBanManager.cs (93%) rename src/CoiniumServ/{Utils => }/Configuration/ConfigManager.cs (97%) rename src/CoiniumServ/{Utils => }/Configuration/IConfig.cs (96%) rename src/CoiniumServ/{Utils => }/Configuration/IConfigManager.cs (92%) rename src/CoiniumServ/{Utils => }/Configuration/JsonConfigReader.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/ExtraNonce.cs (98%) rename src/CoiniumServ/{Mining => }/Jobs/IExtraNonce.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/IJobCounter.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/JobCounter.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/Manager/IJobConfig.cs (94%) rename src/CoiniumServ/{Mining => }/Jobs/Manager/IJobManager.cs (96%) rename src/CoiniumServ/{Mining => }/Jobs/Manager/JobConfig.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/Manager/JobManager.cs (97%) rename src/CoiniumServ/{Mining => }/Jobs/Tracker/IJobTracker.cs (96%) rename src/CoiniumServ/{Mining => }/Jobs/Tracker/JobTracker.cs (97%) rename src/CoiniumServ/{Utils => }/Logging/ILogConfig.cs (94%) rename src/CoiniumServ/{Utils => }/Logging/ILogManager.cs (96%) rename src/CoiniumServ/{Utils => }/Logging/ILogTarget.cs (96%) rename src/CoiniumServ/{Utils => }/Logging/LogConfig.cs (96%) rename src/CoiniumServ/{Utils => }/Logging/LogManager.cs (98%) rename src/CoiniumServ/{Utils => }/Logging/LogTarget.cs (98%) rename src/CoiniumServ/{Mining => }/Miners/IMiner.cs (96%) rename src/CoiniumServ/{Server/Mining/Stratum/Config => Miners}/IMinerConfig.cs (94%) rename src/CoiniumServ/{Mining => }/Miners/IMinerManager.cs (93%) rename src/CoiniumServ/{Server/Mining/Stratum/Config => Miners}/MinerConfig.cs (97%) rename src/CoiniumServ/{Mining => }/Miners/MinerEventArgs.cs (97%) rename src/CoiniumServ/{Mining => }/Miners/MinerManager.cs (97%) create mode 100644 src/CoiniumServ/Networking/Server/Http/Basic/HttpServer.cs create mode 100644 src/CoiniumServ/Networking/Server/Http/Web/ErrorConfiguration.cs create mode 100644 src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs create mode 100644 src/CoiniumServ/Networking/Server/Http/Web/RootPathProvider.cs create mode 100644 src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs create mode 100644 src/CoiniumServ/Networking/Server/IServer.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/BannedConnectionEventArgs.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/Connection.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/ConnectionDataEventArgs.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/ConnectionEventArgs.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/IClient.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/IConnection.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/ISocketServer.cs create mode 100644 src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs rename src/CoiniumServ/{Mining => }/Pools/Config/IPoolConfig.cs (92%) rename src/CoiniumServ/{Mining => }/Pools/Config/PoolConfig.cs (96%) rename src/CoiniumServ/{Mining => }/Pools/IPool.cs (90%) rename src/CoiniumServ/{Mining => }/Pools/IPoolManager.cs (97%) rename src/CoiniumServ/{Mining => }/Pools/Pool.cs (96%) rename src/CoiniumServ/{Mining => }/Pools/PoolManager.cs (96%) rename src/CoiniumServ/{Mining => }/Shares/IShare.cs (97%) rename src/CoiniumServ/{Mining => }/Shares/IShareManager.cs (97%) rename src/CoiniumServ/{Mining => }/Shares/Share.cs (98%) rename src/CoiniumServ/{Mining => }/Shares/ShareError.cs (97%) rename src/CoiniumServ/{Mining => }/Shares/ShareEventArgs.cs (97%) rename src/CoiniumServ/{Mining => }/Shares/ShareManager.cs (98%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/Algorithms.cs (98%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/Blocks.cs (97%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/Global.cs (98%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IAlgorithms.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IBlocks.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IGlobal.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IJsonResponse.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/ILatestBlocks.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IPerAlgorithm.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IPerPool.cs (94%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IPools.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IStatistics.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/IStatisticsProvider.cs (96%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/LatestBlocks.cs (97%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/PerAlgorithm.cs (97%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/PerPool.cs (97%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/Pools.cs (98%) rename src/CoiniumServ/{Mining/Pools => }/Statistics/Statistics.cs (97%) rename src/CoiniumServ/{Mining => }/Vardiff/IVardiffConfig.cs (96%) rename src/CoiniumServ/{Mining => }/Vardiff/IVardiffManager.cs (96%) rename src/CoiniumServ/{Mining => }/Vardiff/IVardiffMiner.cs (97%) rename src/CoiniumServ/{Mining => }/Vardiff/VardiffConfig.cs (98%) rename src/CoiniumServ/{Mining => }/Vardiff/VardiffManager.cs (98%) rename src/Tests/{Mining => }/Pools/PoolTests.cs (96%) rename src/Tests/{Mining => }/Shares/ShareTests.cs (99%) diff --git a/src/CoiniumServ/Mining/Banning/BanConfig.cs b/src/CoiniumServ/Banning/BanConfig.cs similarity index 98% rename from src/CoiniumServ/Mining/Banning/BanConfig.cs rename to src/CoiniumServ/Banning/BanConfig.cs index 83b0dd495..a9bbc93d7 100644 --- a/src/CoiniumServ/Mining/Banning/BanConfig.cs +++ b/src/CoiniumServ/Banning/BanConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Banning +namespace CoiniumServ.Banning { public class BanConfig : IBanConfig { diff --git a/src/CoiniumServ/Mining/Banning/BanManager.cs b/src/CoiniumServ/Banning/BanManager.cs similarity index 96% rename from src/CoiniumServ/Mining/Banning/BanManager.cs rename to src/CoiniumServ/Banning/BanManager.cs index 7a1fdf41b..f44a821bb 100644 --- a/src/CoiniumServ/Mining/Banning/BanManager.cs +++ b/src/CoiniumServ/Banning/BanManager.cs @@ -26,16 +26,14 @@ using System.Linq; using System.Net; using System.Threading; -using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Miners; +using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Shares; using CoiniumServ.Utils.Helpers.Time; using Serilog; -namespace CoiniumServ.Mining.Banning +namespace CoiniumServ.Banning { public class BanManager:IBanManager { diff --git a/src/CoiniumServ/Mining/Banning/IBanConfig.cs b/src/CoiniumServ/Banning/IBanConfig.cs similarity index 95% rename from src/CoiniumServ/Mining/Banning/IBanConfig.cs rename to src/CoiniumServ/Banning/IBanConfig.cs index 83c160105..2f1807f6f 100644 --- a/src/CoiniumServ/Mining/Banning/IBanConfig.cs +++ b/src/CoiniumServ/Banning/IBanConfig.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; -namespace CoiniumServ.Mining.Banning +namespace CoiniumServ.Banning { public interface IBanConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Banning/IBanManager.cs b/src/CoiniumServ/Banning/IBanManager.cs similarity index 93% rename from src/CoiniumServ/Mining/Banning/IBanManager.cs rename to src/CoiniumServ/Banning/IBanManager.cs index 4d3ed304a..ce70f7736 100644 --- a/src/CoiniumServ/Mining/Banning/IBanManager.cs +++ b/src/CoiniumServ/Banning/IBanManager.cs @@ -22,9 +22,8 @@ #endregion using System.Net; -using CoiniumServ.Mining.Pools.Config; -namespace CoiniumServ.Mining.Banning +namespace CoiniumServ.Banning { public interface IBanManager { diff --git a/src/CoiniumServ/Coin/Config/ICoinConfig.cs b/src/CoiniumServ/Coin/Config/ICoinConfig.cs index 1cc5ad657..1a615c281 100644 --- a/src/CoiniumServ/Coin/Config/ICoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/ICoinConfig.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Coin.Config { diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 44435e7d6..31367494a 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -126,55 +126,55 @@ - - - - - - + + + + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -209,14 +209,14 @@ - - + + - - - - + + + + @@ -238,7 +238,7 @@ - + @@ -248,12 +248,12 @@ - - - - - - + + + + + + @@ -274,7 +274,7 @@ - + @@ -286,21 +286,21 @@ - - - - + + + + - - - - - - - - - + + + + + + + + + @@ -308,14 +308,14 @@ - - + + - + @@ -326,13 +326,13 @@ - - - - - - - + + + + + + + @@ -365,9 +365,9 @@ - + - + diff --git a/src/CoiniumServ/Utils/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs similarity index 97% rename from src/CoiniumServ/Utils/Configuration/ConfigManager.cs rename to src/CoiniumServ/Configuration/ConfigManager.cs index 0c0036bad..066e2ac59 100644 --- a/src/CoiniumServ/Utils/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -27,13 +27,13 @@ using System.Linq; using CoiniumServ.Coin.Config; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Logging; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Web; using CoiniumServ.Utils.Helpers.IO; -using CoiniumServ.Utils.Logging; using Serilog; -namespace CoiniumServ.Utils.Configuration +namespace CoiniumServ.Configuration { public class ConfigManager:IConfigManager { diff --git a/src/CoiniumServ/Utils/Configuration/IConfig.cs b/src/CoiniumServ/Configuration/IConfig.cs similarity index 96% rename from src/CoiniumServ/Utils/Configuration/IConfig.cs rename to src/CoiniumServ/Configuration/IConfig.cs index cf7655acb..c8471f88a 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfig.cs +++ b/src/CoiniumServ/Configuration/IConfig.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Utils.Configuration +namespace CoiniumServ.Configuration { public interface IConfig { diff --git a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs b/src/CoiniumServ/Configuration/IConfigManager.cs similarity index 92% rename from src/CoiniumServ/Utils/Configuration/IConfigManager.cs rename to src/CoiniumServ/Configuration/IConfigManager.cs index 300f55737..a9391826c 100644 --- a/src/CoiniumServ/Utils/Configuration/IConfigManager.cs +++ b/src/CoiniumServ/Configuration/IConfigManager.cs @@ -22,11 +22,11 @@ #endregion using System.Collections.Generic; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Logging; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Web; -using CoiniumServ.Utils.Logging; -namespace CoiniumServ.Utils.Configuration +namespace CoiniumServ.Configuration { public interface IConfigManager { diff --git a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs b/src/CoiniumServ/Configuration/JsonConfigReader.cs similarity index 97% rename from src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs rename to src/CoiniumServ/Configuration/JsonConfigReader.cs index 3363f28f3..72b2064bf 100644 --- a/src/CoiniumServ/Utils/Configuration/JsonConfigReader.cs +++ b/src/CoiniumServ/Configuration/JsonConfigReader.cs @@ -25,7 +25,7 @@ using JsonConfig; using Serilog; -namespace CoiniumServ.Utils.Configuration +namespace CoiniumServ.Configuration { public static class JsonConfigReader { diff --git a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs index 3af15555f..a6cbd053f 100644 --- a/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/IDaemonConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Daemon.Config { diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index d180ed99c..f0f333820 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -28,8 +28,8 @@ using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Factories; +using CoiniumServ.Logging; using CoiniumServ.Utils.Extensions; -using CoiniumServ.Utils.Logging; using Newtonsoft.Json; using Serilog; diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs index fb06dde07..65902fcaa 100644 --- a/src/CoiniumServ/Factories/ConfigFactory.cs +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -22,9 +22,9 @@ #endregion using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Configuration; +using CoiniumServ.Pools.Config; using CoiniumServ.Repository.Context; -using CoiniumServ.Utils.Configuration; using Nancy.TinyIoc; namespace CoiniumServ.Factories diff --git a/src/CoiniumServ/Factories/IConfigFactory.cs b/src/CoiniumServ/Factories/IConfigFactory.cs index 5fec6f1f2..5c8b1cac2 100644 --- a/src/CoiniumServ/Factories/IConfigFactory.cs +++ b/src/CoiniumServ/Factories/IConfigFactory.cs @@ -22,8 +22,8 @@ #endregion using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; +using CoiniumServ.Pools.Config; namespace CoiniumServ.Factories { diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index 0c1f9d22f..cce97f862 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -21,25 +21,25 @@ // #endregion +using CoiniumServ.Banning; using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Jobs.Tracker; +using CoiniumServ.Logging; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; -using CoiniumServ.Utils.Logging; +using CoiniumServ.Shares; +using CoiniumServ.Statistics; +using CoiniumServ.Vardiff; using Nancy.Bootstrapper; namespace CoiniumServ.Factories diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index 45949b832..48d37b0df 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -21,26 +21,26 @@ // #endregion +using CoiniumServ.Banning; using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Jobs.Tracker; +using CoiniumServ.Logging; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Repository.Context; using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Web; -using CoiniumServ.Utils.Logging; +using CoiniumServ.Shares; +using CoiniumServ.Statistics; +using CoiniumServ.Vardiff; using Nancy.Bootstrapper; using Nancy.TinyIoc; diff --git a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs b/src/CoiniumServ/Jobs/ExtraNonce.cs similarity index 98% rename from src/CoiniumServ/Mining/Jobs/ExtraNonce.cs rename to src/CoiniumServ/Jobs/ExtraNonce.cs index a5a0745f6..7b2a03de0 100644 --- a/src/CoiniumServ/Mining/Jobs/ExtraNonce.cs +++ b/src/CoiniumServ/Jobs/ExtraNonce.cs @@ -24,7 +24,7 @@ using System; using CoiniumServ.Utils.Extensions; -namespace CoiniumServ.Mining.Jobs +namespace CoiniumServ.Jobs { /// /// Counter for extra nonce. diff --git a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs b/src/CoiniumServ/Jobs/IExtraNonce.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/IExtraNonce.cs rename to src/CoiniumServ/Jobs/IExtraNonce.cs index f5161cd14..16efa0e1c 100644 --- a/src/CoiniumServ/Mining/Jobs/IExtraNonce.cs +++ b/src/CoiniumServ/Jobs/IExtraNonce.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Jobs +namespace CoiniumServ.Jobs { // Hex-encoded, per-connection unique string which will be used for coinbase serialization later. (http://mining.bitcoin.cz/stratum-mining) public interface IExtraNonce diff --git a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs b/src/CoiniumServ/Jobs/IJobCounter.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/IJobCounter.cs rename to src/CoiniumServ/Jobs/IJobCounter.cs index 61c979ac0..37a0a3ea7 100644 --- a/src/CoiniumServ/Mining/Jobs/IJobCounter.cs +++ b/src/CoiniumServ/Jobs/IJobCounter.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Jobs +namespace CoiniumServ.Jobs { public interface IJobCounter { diff --git a/src/CoiniumServ/Mining/Jobs/JobCounter.cs b/src/CoiniumServ/Jobs/JobCounter.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/JobCounter.cs rename to src/CoiniumServ/Jobs/JobCounter.cs index cd82f884c..7e2c1dfa3 100644 --- a/src/CoiniumServ/Mining/Jobs/JobCounter.cs +++ b/src/CoiniumServ/Jobs/JobCounter.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Jobs +namespace CoiniumServ.Jobs { /// /// Counter for job id's. diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs b/src/CoiniumServ/Jobs/Manager/IJobConfig.cs similarity index 94% rename from src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs rename to src/CoiniumServ/Jobs/Manager/IJobConfig.cs index 233eb7e99..91d32742d 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobConfig.cs +++ b/src/CoiniumServ/Jobs/Manager/IJobConfig.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; -namespace CoiniumServ.Mining.Jobs.Manager +namespace CoiniumServ.Jobs.Manager { public interface IJobConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs b/src/CoiniumServ/Jobs/Manager/IJobManager.cs similarity index 96% rename from src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs rename to src/CoiniumServ/Jobs/Manager/IJobManager.cs index 2b19cf716..ffe1b0cb4 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/IJobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/IJobManager.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Jobs.Manager +namespace CoiniumServ.Jobs.Manager { public interface IJobManager { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs b/src/CoiniumServ/Jobs/Manager/JobConfig.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs rename to src/CoiniumServ/Jobs/Manager/JobConfig.cs index f56fcfa1d..dcf15acaf 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobConfig.cs +++ b/src/CoiniumServ/Jobs/Manager/JobConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Jobs.Manager +namespace CoiniumServ.Jobs.Manager { public class JobConfig : IJobConfig { diff --git a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Jobs/Manager/JobManager.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs rename to src/CoiniumServ/Jobs/Manager/JobManager.cs index 43aebac78..0cf7a5847 100644 --- a/src/CoiniumServ/Mining/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/JobManager.cs @@ -26,18 +26,17 @@ using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; +using CoiniumServ.Jobs.Tracker; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Vanilla; +using CoiniumServ.Shares; using CoiniumServ.Transactions; using Serilog; -namespace CoiniumServ.Mining.Jobs.Manager +namespace CoiniumServ.Jobs.Manager { public class JobManager : IJobManager { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs b/src/CoiniumServ/Jobs/Tracker/IJobTracker.cs similarity index 96% rename from src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs rename to src/CoiniumServ/Jobs/Tracker/IJobTracker.cs index acaee2530..55c18884f 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/IJobTracker.cs +++ b/src/CoiniumServ/Jobs/Tracker/IJobTracker.cs @@ -24,7 +24,7 @@ using System; using CoiniumServ.Server.Mining.Stratum.Notifications; -namespace CoiniumServ.Mining.Jobs.Tracker +namespace CoiniumServ.Jobs.Tracker { public interface IJobTracker { diff --git a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs b/src/CoiniumServ/Jobs/Tracker/JobTracker.cs similarity index 97% rename from src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs rename to src/CoiniumServ/Jobs/Tracker/JobTracker.cs index 8f92be3d3..940193414 100644 --- a/src/CoiniumServ/Mining/Jobs/Tracker/JobTracker.cs +++ b/src/CoiniumServ/Jobs/Tracker/JobTracker.cs @@ -25,7 +25,7 @@ using System.Collections.Generic; using CoiniumServ.Server.Mining.Stratum.Notifications; -namespace CoiniumServ.Mining.Jobs.Tracker +namespace CoiniumServ.Jobs.Tracker { public class JobTracker:IJobTracker { diff --git a/src/CoiniumServ/Utils/Logging/ILogConfig.cs b/src/CoiniumServ/Logging/ILogConfig.cs similarity index 94% rename from src/CoiniumServ/Utils/Logging/ILogConfig.cs rename to src/CoiniumServ/Logging/ILogConfig.cs index 3c9b68d50..2655630c5 100644 --- a/src/CoiniumServ/Utils/Logging/ILogConfig.cs +++ b/src/CoiniumServ/Logging/ILogConfig.cs @@ -22,9 +22,9 @@ #endregion using System.Collections.Generic; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public interface ILogConfig : IConfig { diff --git a/src/CoiniumServ/Utils/Logging/ILogManager.cs b/src/CoiniumServ/Logging/ILogManager.cs similarity index 96% rename from src/CoiniumServ/Utils/Logging/ILogManager.cs rename to src/CoiniumServ/Logging/ILogManager.cs index 746259797..e76ade3b8 100644 --- a/src/CoiniumServ/Utils/Logging/ILogManager.cs +++ b/src/CoiniumServ/Logging/ILogManager.cs @@ -21,7 +21,7 @@ // #endregion -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public interface ILogManager { diff --git a/src/CoiniumServ/Utils/Logging/ILogTarget.cs b/src/CoiniumServ/Logging/ILogTarget.cs similarity index 96% rename from src/CoiniumServ/Utils/Logging/ILogTarget.cs rename to src/CoiniumServ/Logging/ILogTarget.cs index 642e8f403..1bc1a4ca4 100644 --- a/src/CoiniumServ/Utils/Logging/ILogTarget.cs +++ b/src/CoiniumServ/Logging/ILogTarget.cs @@ -21,10 +21,10 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; using Serilog.Events; -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public interface ILogTarget: IConfig { diff --git a/src/CoiniumServ/Utils/Logging/LogConfig.cs b/src/CoiniumServ/Logging/LogConfig.cs similarity index 96% rename from src/CoiniumServ/Utils/Logging/LogConfig.cs rename to src/CoiniumServ/Logging/LogConfig.cs index d582e2ca8..6dbd5ff73 100644 --- a/src/CoiniumServ/Utils/Logging/LogConfig.cs +++ b/src/CoiniumServ/Logging/LogConfig.cs @@ -23,10 +23,9 @@ using System; using System.Collections.Generic; -using CoiniumServ.Mining.Pools.Config; using Serilog; -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public class LogConfig : ILogConfig { diff --git a/src/CoiniumServ/Utils/Logging/LogManager.cs b/src/CoiniumServ/Logging/LogManager.cs similarity index 98% rename from src/CoiniumServ/Utils/Logging/LogManager.cs rename to src/CoiniumServ/Logging/LogManager.cs index 0d58b7f83..25adbf06b 100644 --- a/src/CoiniumServ/Utils/Logging/LogManager.cs +++ b/src/CoiniumServ/Logging/LogManager.cs @@ -23,13 +23,12 @@ using System.IO; using System.Linq; -using CoiniumServ.Factories; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; using Serilog; using Serilog.Core; using Serilog.Events; -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public class LogManager:ILogManager { diff --git a/src/CoiniumServ/Utils/Logging/LogTarget.cs b/src/CoiniumServ/Logging/LogTarget.cs similarity index 98% rename from src/CoiniumServ/Utils/Logging/LogTarget.cs rename to src/CoiniumServ/Logging/LogTarget.cs index 182d94075..1983316da 100644 --- a/src/CoiniumServ/Utils/Logging/LogTarget.cs +++ b/src/CoiniumServ/Logging/LogTarget.cs @@ -25,7 +25,7 @@ using Serilog; using Serilog.Events; -namespace CoiniumServ.Utils.Logging +namespace CoiniumServ.Logging { public class LogTarget:ILogTarget { diff --git a/src/CoiniumServ/Mining/Miners/IMiner.cs b/src/CoiniumServ/Miners/IMiner.cs similarity index 96% rename from src/CoiniumServ/Mining/Miners/IMiner.cs rename to src/CoiniumServ/Miners/IMiner.cs index 65923a2a4..2a17f7527 100644 --- a/src/CoiniumServ/Mining/Miners/IMiner.cs +++ b/src/CoiniumServ/Miners/IMiner.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Mining.Pools; +using CoiniumServ.Pools; -namespace CoiniumServ.Mining.Miners +namespace CoiniumServ.Miners { /// /// Miner interface that any implementations should extend. diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs b/src/CoiniumServ/Miners/IMinerConfig.cs similarity index 94% rename from src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs rename to src/CoiniumServ/Miners/IMinerConfig.cs index ba13251a8..d9dbe7a92 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IMinerConfig.cs +++ b/src/CoiniumServ/Miners/IMinerConfig.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; -namespace CoiniumServ.Server.Mining.Stratum.Config +namespace CoiniumServ.Miners { public interface IMinerConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Miners/IMinerManager.cs b/src/CoiniumServ/Miners/IMinerManager.cs similarity index 93% rename from src/CoiniumServ/Mining/Miners/IMinerManager.cs rename to src/CoiniumServ/Miners/IMinerManager.cs index d7a98b810..81e2e62ca 100644 --- a/src/CoiniumServ/Mining/Miners/IMinerManager.cs +++ b/src/CoiniumServ/Miners/IMinerManager.cs @@ -23,10 +23,10 @@ using System; using System.Collections.Generic; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Networking.Server.Sockets; +using CoiniumServ.Pools; -namespace CoiniumServ.Mining.Miners +namespace CoiniumServ.Miners { public interface IMinerManager { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs b/src/CoiniumServ/Miners/MinerConfig.cs similarity index 97% rename from src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs rename to src/CoiniumServ/Miners/MinerConfig.cs index 33abd4314..93d3f23fd 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/MinerConfig.cs +++ b/src/CoiniumServ/Miners/MinerConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Server.Mining.Stratum.Config +namespace CoiniumServ.Miners { public class MinerConfig:IMinerConfig { diff --git a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs b/src/CoiniumServ/Miners/MinerEventArgs.cs similarity index 97% rename from src/CoiniumServ/Mining/Miners/MinerEventArgs.cs rename to src/CoiniumServ/Miners/MinerEventArgs.cs index 153038b02..585be502c 100644 --- a/src/CoiniumServ/Mining/Miners/MinerEventArgs.cs +++ b/src/CoiniumServ/Miners/MinerEventArgs.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Miners +namespace CoiniumServ.Miners { public class MinerEventArgs:EventArgs { diff --git a/src/CoiniumServ/Mining/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs similarity index 97% rename from src/CoiniumServ/Mining/Miners/MinerManager.cs rename to src/CoiniumServ/Miners/MinerManager.cs index 1a440b0c8..2a1c4673e 100644 --- a/src/CoiniumServ/Mining/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -24,14 +24,13 @@ using System; using System.Collections.Generic; using System.Linq; -using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Networking.Server.Sockets; +using CoiniumServ.Pools; using CoiniumServ.Server.Mining.Stratum; using Serilog; -namespace CoiniumServ.Mining.Miners +namespace CoiniumServ.Miners { public class MinerManager : IMinerManager { diff --git a/src/CoiniumServ/Networking/Server/Http/Basic/HttpServer.cs b/src/CoiniumServ/Networking/Server/Http/Basic/HttpServer.cs new file mode 100644 index 000000000..1390923d4 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Http/Basic/HttpServer.cs @@ -0,0 +1,166 @@ +#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.Collections.Generic; +using System.Net; +using System.Threading; + +// source from: http://stackoverflow.com/a/4673210/170181 + +namespace CoiniumServ.Networking.Server.Http.Basic +{ + public class HttpServer : IServer, IDisposable + { + /// + /// The IP address of the interface the server binded. + /// + public string BindIP { get; protected set; } + + /// + /// The listening port for the server. + /// + public int Port { get; protected set; } + + /// + /// Is server currently listening for connections? + /// + public bool IsListening { get; private set; } + + public event Action ProcessRequest; + + private HttpListener _listener; + private Thread _listenerThread; + private Thread[] _workers; + private ManualResetEvent _stop, _ready; + private Queue _queue; + + /// + /// Initializes the specified port. + /// + /// The port. + /// The maximum threads. + /// HttpListener not supported. Switch to mono provided one. + public void Initialize(int maxThreads = 5) + { + if (!HttpListener.IsSupported) + throw new NotSupportedException("HttpListener not supported."); + + _workers = new Thread[maxThreads]; + _queue = new Queue(); + _stop = new ManualResetEvent(false); + _ready = new ManualResetEvent(false); + _listener = new HttpListener(); + _listenerThread = new Thread(HandleRequests); + } + + public bool Start() + { + _listener.Prefixes.Add(String.Format(@"http://{0}:{1}/", BindIP, Port)); + _listener.Start(); + _listenerThread.Start(); + + for (int i = 0; i < _workers.Length; i++) + { + _workers[i] = new Thread(Worker); + _workers[i].Start(); + } + + IsListening = true; + + return true; + } + + public bool Stop() + { + _stop.Set(); + _listenerThread.Join(); + foreach (Thread worker in _workers) + worker.Join(); + + _listener.Stop(); + + return true; + } + + private void HandleRequests() + { + while (_listener.IsListening) + { + var context = _listener.BeginGetContext(ContextReady, null); + + if (0 == WaitHandle.WaitAny(new[] {_stop, context.AsyncWaitHandle})) + return; + } + } + + private void ContextReady(IAsyncResult ar) + { + try + { + lock (_queue) + { + _queue.Enqueue(_listener.EndGetContext(ar)); + _ready.Set(); + } + } + catch + { + return; + } + } + + private void Worker() + { + WaitHandle[] wait = {_ready, _stop}; + while (0 == WaitHandle.WaitAny(wait)) + { + HttpListenerContext context; + lock (_queue) + { + if (_queue.Count > 0) + context = _queue.Dequeue(); + else + { + _ready.Reset(); + continue; + } + } + + try + { + ProcessRequest(context); + } + catch (Exception e) + { + Console.Error.WriteLine(e); + } + } + } + + public void Dispose() + { + Stop(); + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Http/Web/ErrorConfiguration.cs b/src/CoiniumServ/Networking/Server/Http/Web/ErrorConfiguration.cs new file mode 100644 index 000000000..4055593f6 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Http/Web/ErrorConfiguration.cs @@ -0,0 +1,39 @@ +#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 Nancy; +using Nancy.CustomErrors; + +namespace CoiniumServ.Networking.Server.Http.Web +{ + public class ErrorConfiguration : CustomErrorsConfiguration + { + public ErrorConfiguration() + { + // Map error status codes to custom view names + ErrorViews[HttpStatusCode.NotFound] = "error"; + ErrorViews[HttpStatusCode.InternalServerError] = "error"; + ErrorViews[HttpStatusCode.Forbidden] = "error"; + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs new file mode 100644 index 000000000..43ed5ef4d --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs @@ -0,0 +1,110 @@ +#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.Net; +using Nancy.Bootstrapper; +using Nancy.Hosting.Self; +using Serilog; + +namespace CoiniumServ.Networking.Server.Http.Web +{ + public class HttpServer : IServer, IDisposable + { + /// + /// The IP address of the interface the server binded. + /// + public string BindIP { get; protected set; } + + /// + /// The listening port for the server. + /// + public int Port { get; protected set; } + + /// + /// Is server currently listening for connections? + /// + public bool IsListening { get; protected set; } + + private readonly INancyBootstrapper _webBootstrapper; + + private readonly ILogger _logger; + + public HttpServer(INancyBootstrapper webBootstrapper) + { + _webBootstrapper = webBootstrapper; + _logger = Log.ForContext(); + } + + public bool Start() + { + var uri = new Uri(string.Format("http://{0}:{1}", BindIP, Port)); + + var hostConfiguration = new HostConfiguration(); + hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; + hostConfiguration.UrlReservations.CreateAutomatically = true; + + var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); + + try + { + host.Start(); + IsListening = true; + } + catch (InvalidOperationException e) // nancy requires elevated privileges to run on port 80. + { + _logger.Error("Need elevated privileges to listen on port {0}. Try running as administrator or root.", Port); + IsListening = false; + return false; + } + catch (HttpListenerException e) + { + _logger.Error("Can not listen on requested interface: {0:l}",BindIP); + IsListening = false; + return false; + } + + _logger.Information("Web-server listening on: {0:l}", uri); + return true; + } + + public bool Stop() + { + throw new NotImplementedException(); + } + + /// + /// Unhandled exception callback for nancy based web-server. + /// + /// + private void UnhandledExceptionHandler(Exception exception) + { + _logger.Error("Web-server: {0}", exception); + } + + public void Dispose() + { + Stop(); + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Http/Web/RootPathProvider.cs b/src/CoiniumServ/Networking/Server/Http/Web/RootPathProvider.cs new file mode 100644 index 000000000..eb5bc1690 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Http/Web/RootPathProvider.cs @@ -0,0 +1,39 @@ +#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.IO; +using System.Reflection; +using CoiniumServ.Utils.Platform; +using Nancy; + +namespace CoiniumServ.Networking.Server.Http.Web +{ + public class CustomRootPathProvider : IRootPathProvider + { + public string GetRootPath() + { + return string.Format(PlatformManager.Framework == Frameworks.Mono ? "{0}/web/default" : "{0}\\web\\default", + Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs new file mode 100644 index 000000000..7f4ae429a --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs @@ -0,0 +1,86 @@ +#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 CoiniumServ.Repository.Context; +using Nancy; +using Nancy.Bootstrapper; +using Nancy.Conventions; +using Nancy.CustomErrors; +using Nancy.Diagnostics; +using Nancy.TinyIoc; + +namespace CoiniumServ.Networking.Server.Http.Web +{ + public class WebBootstrapper : DefaultNancyBootstrapper + { + /// + /// The _application context + /// + private readonly IApplicationContext _applicationContext; + + public WebBootstrapper(IApplicationContext applicationContext) + { + _applicationContext = applicationContext; + } + + protected override DiagnosticsConfiguration DiagnosticsConfiguration + { + get { return new DiagnosticsConfiguration { Password = @"coinium" }; } + } + + protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) + { + StaticConfiguration.EnableRequestTracing = true; + CustomErrors.Enable(pipelines, new ErrorConfiguration()); + } + + protected override IRootPathProvider RootPathProvider + { + get { return new CustomRootPathProvider(); } + } + + protected override void ConfigureConventions(NancyConventions nancyConventions) + { + // static content + nancyConventions.StaticContentsConventions.Clear(); + nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("css", "/css")); + nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("js", "/js")); + nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("font-awesome", "/font-awesome")); + + // view location + nancyConventions.ViewLocationConventions.Clear(); + nancyConventions.ViewLocationConventions.Add((viewName, model, context) => string.Concat("/", viewName)); + nancyConventions.ViewLocationConventions.Add((viewName, model, context) => string.Concat("/", context.ModuleName, "/", viewName)); + } + + protected override TinyIoCContainer GetApplicationContainer() + { + return _applicationContext.Container; + } + + protected override void ConfigureApplicationContainer(TinyIoCContainer container) + { + // prevents nancy from autoregistering it's own set of resolvers. + } + } +} diff --git a/src/CoiniumServ/Networking/Server/IServer.cs b/src/CoiniumServ/Networking/Server/IServer.cs new file mode 100644 index 000000000..89b9e8c38 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/IServer.cs @@ -0,0 +1,58 @@ +#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.Networking.Server +{ + /// + /// Server interface that any implementations should extend. + /// + public interface IServer + { + /// + /// The IP address of the interface the server binded. + /// + string BindIP { get; } + + /// + /// The listening port for the server. + /// + int Port { get; } + + /// + /// Is server currently listening for connections? + /// + bool IsListening { get; } + + /// + /// Starts a server instance. + /// + /// + bool Start(); + + /// + /// Stops the server instance. + /// + /// + bool Stop(); + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/BannedConnectionEventArgs.cs b/src/CoiniumServ/Networking/Server/Sockets/BannedConnectionEventArgs.cs new file mode 100644 index 000000000..f67d4c001 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/BannedConnectionEventArgs.cs @@ -0,0 +1,38 @@ +#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.Net; + +namespace CoiniumServ.Networking.Server.Sockets +{ + public class BannedConnectionEventArgs:EventArgs + { + public IPEndPoint Endpoint { get; private set; } + + public BannedConnectionEventArgs(EndPoint endpoint) + { + Endpoint = (IPEndPoint)endpoint; + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/Connection.cs b/src/CoiniumServ/Networking/Server/Sockets/Connection.cs new file mode 100644 index 000000000..b40414fbe --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/Connection.cs @@ -0,0 +1,246 @@ +#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.Collections.Generic; +using System.Net; +using System.Net.Sockets; + +namespace CoiniumServ.Networking.Server.Sockets +{ + public class Connection : IConnection + { + /// + /// Gets or sets bound client. + /// + public IClient Client { get; set; } + + /// + /// Gets underlying socket. + /// + public Socket Socket { get; private set; } + + /// + /// Returns true if there exists an active connection. + /// + public bool IsConnected + { + get { return (Socket != null) && Socket.Connected; } + } + + /// + /// Returns remote endpoint. + /// + public IPEndPoint RemoteEndPoint + { + get { return (Socket == null) ? null : Socket.RemoteEndPoint as IPEndPoint; } + } + + /// + /// Returns local endpoint. + /// + public IPEndPoint LocalEndPoint + { + get { return Socket.LocalEndPoint as IPEndPoint; } + } + + /// + /// The server instance that connection is bound to. + /// + private readonly SocketServer _server; + + /// + /// Default buffer size. + /// + public static readonly int BufferSize = 16 * 1024; // 16 KB + + /// + /// The recieve buffer. + /// + private readonly byte[] _recvBuffer = new byte[BufferSize]; + + /// + /// Returns the recieve-buffer. + /// + public byte[] RecvBuffer + { + get { return _recvBuffer; } + } + + public Connection(SocketServer server, Socket socket) + { + if (server == null) + throw new ArgumentNullException("server"); + + if (socket == null) + throw new ArgumentNullException("socket"); + + _server = server; + Socket = socket; + } + + #region recieve methods + + // Read bytes from the Socket into the buffer in a non-blocking call. + // This allows us to read no more than the specified count number of bytes.\ + // Note that this method should only be called prior to encryption! + public int Receive(int start, int count) + { + return Socket.Receive(_recvBuffer, start, count, SocketFlags.None); + } + + /// + /// Begins recieving data async. + /// + /// Callback function be called when recv() is complete. + /// State manager object. + /// Returns + public IAsyncResult BeginReceive(AsyncCallback callback, object state) + { + return Socket.BeginReceive(_recvBuffer, 0, BufferSize, SocketFlags.None, callback, state); + } + + public int EndReceive(IAsyncResult result) + { + return Socket.EndReceive(result); + } + + #endregion + + #region send methods + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Returns count of sent bytes. + public int Send(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + return Send(buffer, 0, buffer.Length, SocketFlags.None); + } + + /// + /// Sends an enumarable byte buffer to remote endpoint. + /// + /// Enumrable byte buffer to send. + /// Returns count of sent bytes. + public int Send(IEnumerable data) + { + if (data == null) + throw new ArgumentNullException("data"); + + return Send(data, SocketFlags.None); + } + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Sockets flags to use. + /// Returns count of sent bytes. + public int Send(byte[] buffer, SocketFlags flags) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + return Send(buffer, 0, buffer.Length, flags); + } + + /// + /// Sends an enumarable byte buffer to remote endpoint. + /// + /// Enumrable byte buffer to send. + /// Sockets flags to use. + /// Returns count of sent bytes. + public int Send(IEnumerable data, SocketFlags flags) + { + if (data == null) + throw new ArgumentNullException("data"); + + if (_server == null) + throw new Exception("[Connection] _server is null in Send"); + + return _server.Send(this, data, flags); + } + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Start index to read from buffer. + /// Count of bytes to send. + /// Returns count of sent bytes. + public int Send(byte[] buffer, int start, int count) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + return Send(buffer, start, count, SocketFlags.None); + } + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Start index to read from buffer. + /// Count of bytes to send. + /// Sockets flags to use. + /// + public int Send(byte[] buffer, int start, int count, SocketFlags flags) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + if (_server == null) + throw new Exception("Connection is not bound to a server instance."); + + return _server.Send(this, buffer, start, count, flags); + } + + #endregion + + #region disconnect methods + + public void Disconnect() + { + _server.RemoveConnection(this); + } + + #endregion + + /// + /// Returns a connection state string. + /// + /// Connection state string. + public override string ToString() + { + if (Socket == null) + return "No Socket!"; + + return Socket.RemoteEndPoint != null ? Socket.RemoteEndPoint.ToString() : "Not Connected!"; + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/ConnectionDataEventArgs.cs b/src/CoiniumServ/Networking/Server/Sockets/ConnectionDataEventArgs.cs new file mode 100644 index 000000000..95b1b7d1e --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/ConnectionDataEventArgs.cs @@ -0,0 +1,46 @@ +#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.Networking.Server.Sockets +{ + public sealed class ConnectionDataEventArgs : ConnectionEventArgs + { + public IEnumerable Data { get; private set; } + + public ConnectionDataEventArgs(IConnection connection, IEnumerable data) + : base(connection) + { + Data = data ?? new byte[0]; + } + + public override string ToString() + { + return Connection.RemoteEndPoint != null + ? string.Format("{0}: {1} bytes", Connection.RemoteEndPoint, Data.Count()) + : string.Format("Not Connected: {0} bytes", Data.Count()); + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/ConnectionEventArgs.cs b/src/CoiniumServ/Networking/Server/Sockets/ConnectionEventArgs.cs new file mode 100644 index 000000000..9434da529 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/ConnectionEventArgs.cs @@ -0,0 +1,47 @@ +#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; + +namespace CoiniumServ.Networking.Server.Sockets +{ + public class ConnectionEventArgs : EventArgs + { + public IConnection Connection { get; private set; } + + public ConnectionEventArgs(IConnection connection) + { + if (connection == null) + throw new ArgumentNullException("connection"); + + Connection = connection; + } + + public override string ToString() + { + return Connection.RemoteEndPoint != null + ? Connection.RemoteEndPoint.ToString() + : "Not Connected"; + } + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/IClient.cs b/src/CoiniumServ/Networking/Server/Sockets/IClient.cs new file mode 100644 index 000000000..672dce03a --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/IClient.cs @@ -0,0 +1,35 @@ +#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.Networking.Server.Sockets +{ + /// + /// Client interface. + /// + public interface IClient + { + /// + /// Gets or sets the TCP connection bound to client. + /// + IConnection Connection { get; } + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/IConnection.cs b/src/CoiniumServ/Networking/Server/Sockets/IConnection.cs new file mode 100644 index 000000000..9ff03a4b3 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/IConnection.cs @@ -0,0 +1,118 @@ +#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.Net; +using System.Net.Sockets; + +namespace CoiniumServ.Networking.Server.Sockets +{ + /// + /// Connection interface. + /// + public interface IConnection + { + /// + /// Returns true if there exists an active connection. + /// + bool IsConnected { get; } + + /// + /// Returns remote endpoint. + /// + IPEndPoint RemoteEndPoint { get; } + + /// + /// Returns local endpoint. + /// + IPEndPoint LocalEndPoint { get; } + + /// + /// Gets or sets bound client. + /// + IClient Client { get; set; } + + /// + /// Gets underlying socket. + /// + Socket Socket { get; } + + /// + /// Kills the connection to remote endpoint. + /// + void Disconnect(); + + // Read bytes from the Sokcet into the buffer in a non-blocking call. + // This allows us to read no more than the specified count number of bytes. + int Receive(int start, int count); + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Returns count of sent bytes. + int Send(byte[] buffer); + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Sockets flags to use. + /// Returns count of sent bytes. + int Send(byte[] buffer, SocketFlags flags); + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Start index to read from buffer. + /// Count of bytes to send. + /// Returns count of sent bytes. + int Send(byte[] buffer, int start, int count); + + /// + /// Sends byte buffer to remote endpoint. + /// + /// Byte buffer to send. + /// Start index to read from buffer. + /// Count of bytes to send. + /// Sockets flags to use. + /// Returns count of sent bytes. + int Send(byte[] buffer, int start, int count, SocketFlags flags); + + /// + /// Sends an enumarable byte buffer to remote endpoint. + /// + /// Enumrable byte buffer to send. + /// Returns count of sent bytes. + int Send(IEnumerable data); + + /// + /// Sends an enumarable byte buffer to remote endpoint. + /// + /// Enumrable byte buffer to send. + /// Sockets flags to use. + /// Returns count of sent bytes. + int Send(IEnumerable data, SocketFlags flags); + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/ISocketServer.cs b/src/CoiniumServ/Networking/Server/Sockets/ISocketServer.cs new file mode 100644 index 000000000..5f62a9042 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/ISocketServer.cs @@ -0,0 +1,38 @@ +#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; + +namespace CoiniumServ.Networking.Server.Sockets +{ + public interface ISocketServer:IServer + { + void RemoveConnection(IConnection connection); + + void Shutdown(); + + void DisconnectAll(); + + IEnumerable GetConnections(); + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs new file mode 100644 index 000000000..b3d993325 --- /dev/null +++ b/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs @@ -0,0 +1,454 @@ +#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.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using CoiniumServ.Utils.Extensions; +using Serilog; + +namespace CoiniumServ.Networking.Server.Sockets +{ + public class SocketServer : ISocketServer, IDisposable + { + /// + /// The IP address of the interface the server binded. + /// + public string BindIP { get; protected set; } + + /// + /// The listening port for the server. + /// + public int Port { get; protected set; } + + /// + /// Is server currently listening for connections? + /// + public bool IsListening { get; private set; } + + /// + /// Listener socket. + /// + protected Socket Listener; + + /// + /// List of connections. + /// + protected List Connections = new List(); + + /// + /// Used for locking connections list. + /// + protected object ConnectionLock = new object(); + + // connection event handlers. + public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e); + public delegate void BannedConnectionEventHandler(object sender, BannedConnectionEventArgs e); + public delegate void ConnectionDataEventHandler(object sender, ConnectionDataEventArgs e); + + // connection events. + public event ConnectionEventHandler ClientConnected; + public event ConnectionEventHandler ClientDisconnected; + public event BannedConnectionEventHandler BannedConnection; + public event ConnectionDataEventHandler DataReceived; + public event ConnectionDataEventHandler DataSent; + + /// + /// Is the instance disposed? + /// + private bool _disposed; + + #region listener & accept callbacks. + + /// + /// Start listening on given interface and port. + /// + /// The interface IP to listen for connections. + /// The port to listen for connections. + /// + protected virtual bool Listen(string bindIP, int port) + { + // Check if the server instance has been already disposed. + if (_disposed) + throw new ObjectDisposedException(GetType().Name, "Server instance has been already disposed."); + + // Check if the server is already listening. + if (IsListening) + throw new InvalidOperationException(string.Format("Server is already listening on {0}:{1}", bindIP, port)); + + try + { + // Create new TCP socket and set socket options. + Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + // Setup our options: + // * NoDelay - true - don't use packet coalescing + // * DontLinger - true - don't keep sockets around once they've been disconnected + Listener.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + + // try the actual bind. + Listener.Bind(new IPEndPoint(IPAddress.Parse(bindIP), port)); + Port = port; + + // Start listening for incoming connections. + Listener.Listen(int.MaxValue); // let the maximum amount of accept backlog - we are basically leaving it to OS to determine the value. + // by setting the maximum available value, we can make sure that we can handle large amounts of concurrent + // connection requests (maybe after a server restart). + + // http://blog.stephencleary.com/2009/05/using-socket-as-server-listening-socket.html + // The “backlog” parameter to Socket.Listen is how many connections the OS may accept on behalf of the application. This is not + // the total number of active connections; it is only how many connections will be established if the application “gets behind”. + // Once connections are Accepted, they move out of the backlog queue and no longer “count” against the backlog limit. + + // The .NET docs fail to mention that int.MaxValue can be used to invoke the “dynamic backlog” feature (Windows Server systems only), + // essentially leaving it up to the OS. It is tempting to set this value very high (e.g., always passing int.MaxValue), but this would + // hurt system performance (on non-server machines) by pre-allocating a large amount of scarce resources. This value should be set to a + // reasonable amount (usually between 2 and 5), based on how many connections one is realistically expecting and how quickly they can be + // Accepted. + + IsListening = true; + + // Begin accepting any incoming connections asynchronously. + Listener.BeginAccept(AcceptCallback, null); + + return true; + } + catch (SocketException exception) + { + Log.ForContext().Fatal("{0} can not bind on {1}, server shutting down.. Reason: {2}", GetType().Name, bindIP, exception); + Shutdown(); + return false; + } + } + + /// + /// Accept callbacks from listener socket. + /// + /// + private void AcceptCallback(IAsyncResult result) + { + if (Listener == null) + return; + + try + { + var socket = Listener.EndAccept(result); // Finish accepting the incoming connection. + var banned = IsBanned(socket); + + if (banned) + { + var endpoint = socket.RemoteEndPoint; + socket.Disconnect(true); + OnBannedConnection(new BannedConnectionEventArgs(endpoint)); + } + else + { + var connection = new Connection(this, socket); // Track the connection. + + lock (ConnectionLock) + Connections.Add(connection); // Add the new connection to the active connections list. + + OnClientConnection(new ConnectionEventArgs(connection)); // Raise the ClientConnected event. + connection.BeginReceive(ReceiveCallback, connection); // Begin receiving on the new connection connection. + } + } + catch (Exception exception) + { + Log.ForContext().Error(exception, "Can not accept connection"); + } + finally + { + // no matter we were able to accept last connection request, make sure we continue to listen for new connections. + Listener.BeginAccept(AcceptCallback, null); + } + } + + public virtual bool IsBanned(Socket socket) + { + return false; + } + + #endregion + + #region recieve callback + + private void ReceiveCallback(IAsyncResult result) + { + var connection = result.AsyncState as Connection; // Get the connection connection passed to the callback. + + if (connection == null) + return; + + try + { + var bytesRecv = connection.EndReceive(result); // Finish receiving data from the socket. + + if (bytesRecv > 0) + { + OnDataReceived(new ConnectionDataEventArgs(connection, connection.RecvBuffer.Enumerate(0, bytesRecv))); // Raise the DataReceived event. + + // Begin receiving again on the socket, if it is connected. + if (connection.IsConnected) + connection.BeginReceive(ReceiveCallback, connection); + else + Log.ForContext().Debug("Connection closed:" + connection.Client); + } + else + RemoveConnection(connection); // Connection was lost. + } + catch (SocketException e) + { + Log.ForContext().Debug(e, "ReceiveCallback"); + RemoveConnection(connection); // An error occured while receiving, connection has disconnected. + } + catch (Exception e) + { + Log.ForContext().Debug(e, "ReceiveCallback"); + RemoveConnection(connection); // An error occured while receiving, the connection may have been disconnected. + } + } + + #endregion + + #region send methods + + public virtual int Send(Connection connection, byte[] buffer, int start, int count, SocketFlags flags) + { + if (connection == null) + throw new ArgumentNullException("connection"); + + if (buffer == null) + throw new ArgumentNullException("buffer"); + + if (!connection.IsConnected) + return 0; + + var totalBytesSent = 0; + var bytesRemaining = buffer.Length; + + try + { + while (bytesRemaining > 0) // Ensure we send every byte. + { + int bytesSent = connection.Socket.Send(buffer, start, count, flags); + + if (bytesSent > 0) + OnDataSent(new ConnectionDataEventArgs(connection, buffer.Enumerate(totalBytesSent, bytesSent))); // Raise the Data Sent event. + + // Decrement bytes remaining and increment bytes sent. + bytesRemaining -= bytesSent; + totalBytesSent += bytesSent; + } + } + catch (SocketException socketException) + { + RemoveConnection(connection); // An error occured while sending, connection has disconnected. + Log.ForContext().Error(socketException, "Send"); + } + catch (Exception e) + { + RemoveConnection(connection); // An error occured while sending, it is possible that the connection has a problem. + Log.ForContext().Error(e, "Send"); + } + + return totalBytesSent; + } + public virtual int Send(Connection connection, IEnumerable data, SocketFlags flags) + { + if (connection == null) + throw new ArgumentNullException("connection"); + + if (data == null) + throw new ArgumentNullException("data"); + + var buffer = data.ToArray(); + return Send(connection, buffer, 0, buffer.Length, SocketFlags.None); + } + + #endregion + + #region disconnect & shutdown handlers + + public void RemoveConnection(IConnection connection) + { + if (connection == null) + return; + + lock (connection) + { + if (connection.IsConnected) // disconnect the client + connection.Socket.Disconnect(true); + } + + connection.Client = null; + + // Remove the connection from the dictionary and raise the OnDisconnection event. + lock (ConnectionLock) + { + if (Connections.Contains(connection)) + Connections.Remove(connection); + } + + OnClientDisconnect(new ConnectionEventArgs(connection)); // raise the ClientDisconnected event. + } + + /// + /// Shuts down the server instance. + /// + public virtual void Shutdown() + { + // Check if the server has been disposed. + if (_disposed) + throw new ObjectDisposedException(GetType().Name, "Server has been already disposed."); + + // Check if the server is actually listening. + if (!IsListening) + return; + + // Close the listener socket. + if (Listener != null) + { + Listener.Close(); + Listener = null; + } + + // Disconnect the clients. + DisconnectAll(); + + Listener = null; + IsListening = false; + } + + public virtual void DisconnectAll() + { + lock (ConnectionLock) + { + foreach (var connection in Connections.ToList()) // using ToList() to get a copy in order to prevent any modified collection exceptions. + { + RemoveConnection(connection); + } + + Connections.Clear(); + } + } + + + #endregion + + #region service methods + + public IEnumerable GetConnections() + { + lock (ConnectionLock) + foreach (IConnection connection in Connections) + yield return connection; + } + + #endregion + + #region server control + public virtual bool Start() + { + throw new NotImplementedException(); + } + + public virtual bool Stop() + { + throw new NotImplementedException(); + } + + #endregion + + #region events + + private void OnClientConnection(ConnectionEventArgs e) + { + var handler = ClientConnected; + + if (handler != null) + handler(this, e); + } + + private void OnClientDisconnect(ConnectionEventArgs e) + { + var handler = ClientDisconnected; + + if (handler != null) + handler(this, e); + } + + private void OnBannedConnection(BannedConnectionEventArgs e) + { + var handler = BannedConnection; + + if (handler != null) + handler(this, e); + } + + private void OnDataReceived(ConnectionDataEventArgs e) + { + var handler = DataReceived; + + if (handler != null) + handler(this, e); + } + + private void OnDataSent(ConnectionDataEventArgs e) + { + var handler = DataSent; + + if (handler != null) + handler(this, e); + } + + #endregion + + #region de-ctor + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + Shutdown(); // Close the listener socket. + DisconnectAll(); // Disconnect all users. + } + + // Dispose of unmanaged resources here. + + _disposed = true; + } + + #endregion + } +} diff --git a/src/CoiniumServ/Payments/IPaymentConfig.cs b/src/CoiniumServ/Payments/IPaymentConfig.cs index d449cd3d8..2871ae52c 100644 --- a/src/CoiniumServ/Payments/IPaymentConfig.cs +++ b/src/CoiniumServ/Payments/IPaymentConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Payments { diff --git a/src/CoiniumServ/Payments/IRewardsConfig.cs b/src/CoiniumServ/Payments/IRewardsConfig.cs index 4daebdf14..af17fff63 100644 --- a/src/CoiniumServ/Payments/IRewardsConfig.cs +++ b/src/CoiniumServ/Payments/IRewardsConfig.cs @@ -22,7 +22,7 @@ #endregion using System.Collections.Generic; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Payments { diff --git a/src/CoiniumServ/Payments/IWalletConfig.cs b/src/CoiniumServ/Payments/IWalletConfig.cs index 834b8947a..4bce0abd8 100644 --- a/src/CoiniumServ/Payments/IWalletConfig.cs +++ b/src/CoiniumServ/Payments/IWalletConfig.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Payments { diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index b79d08d1e..dcb83d212 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -28,7 +28,6 @@ using System.Threading; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Exceptions; -using CoiniumServ.Mining.Pools.Config; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Blocks; using Serilog; diff --git a/src/CoiniumServ/Persistance/IStorage.cs b/src/CoiniumServ/Persistance/IStorage.cs index 06eb89ce8..e577a8c6e 100644 --- a/src/CoiniumServ/Persistance/IStorage.cs +++ b/src/CoiniumServ/Persistance/IStorage.cs @@ -23,9 +23,9 @@ using System; using System.Collections.Generic; -using CoiniumServ.Mining.Shares; using CoiniumServ.Payments; using CoiniumServ.Persistance.Blocks; +using CoiniumServ.Shares; namespace CoiniumServ.Persistance { diff --git a/src/CoiniumServ/Persistance/IStorageConfig.cs b/src/CoiniumServ/Persistance/IStorageConfig.cs index 5b805fb59..6b0610b92 100644 --- a/src/CoiniumServ/Persistance/IStorageConfig.cs +++ b/src/CoiniumServ/Persistance/IStorageConfig.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Persistance { diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index c9b52feb0..b014050a0 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -28,11 +28,10 @@ using System.Net; using System.Net.Sockets; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Shares; using CoiniumServ.Payments; using CoiniumServ.Persistance.Blocks; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Pools.Config; +using CoiniumServ.Shares; using CoiniumServ.Utils.Extensions; using CoiniumServ.Utils.Helpers.Time; using Serilog; diff --git a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Pools/Config/IPoolConfig.cs similarity index 92% rename from src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs rename to src/CoiniumServ/Pools/Config/IPoolConfig.cs index f02cdb42b..fc84a403c 100644 --- a/src/CoiniumServ/Mining/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Pools/Config/IPoolConfig.cs @@ -21,17 +21,18 @@ // #endregion +using CoiniumServ.Banning; using CoiniumServ.Coin.Config; +using CoiniumServ.Configuration; using CoiniumServ.Daemon.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Vanilla.Config; -using CoiniumServ.Utils.Configuration; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Pools.Config { public interface IPoolConfig:IConfig { diff --git a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Pools/Config/PoolConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs rename to src/CoiniumServ/Pools/Config/PoolConfig.cs index ac91a76e3..c128a4da0 100644 --- a/src/CoiniumServ/Mining/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Pools/Config/PoolConfig.cs @@ -22,10 +22,11 @@ #endregion using System; +using CoiniumServ.Banning; using CoiniumServ.Coin.Config; using CoiniumServ.Daemon.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Redis; @@ -33,7 +34,7 @@ using CoiniumServ.Server.Mining.Vanilla.Config; using Serilog; -namespace CoiniumServ.Mining.Pools.Config +namespace CoiniumServ.Pools.Config { /// /// Reads and serves the configuration for a pool. diff --git a/src/CoiniumServ/Mining/Pools/IPool.cs b/src/CoiniumServ/Pools/IPool.cs similarity index 90% rename from src/CoiniumServ/Mining/Pools/IPool.cs rename to src/CoiniumServ/Pools/IPool.cs index 312b6764a..47263621a 100644 --- a/src/CoiniumServ/Mining/Pools/IPool.cs +++ b/src/CoiniumServ/Pools/IPool.cs @@ -21,10 +21,10 @@ // #endregion -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Pools.Config; +using CoiniumServ.Statistics; -namespace CoiniumServ.Mining.Pools +namespace CoiniumServ.Pools { public interface IPool { diff --git a/src/CoiniumServ/Mining/Pools/IPoolManager.cs b/src/CoiniumServ/Pools/IPoolManager.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/IPoolManager.cs rename to src/CoiniumServ/Pools/IPoolManager.cs index 041de1b3e..8e73811e9 100644 --- a/src/CoiniumServ/Mining/Pools/IPoolManager.cs +++ b/src/CoiniumServ/Pools/IPoolManager.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; -namespace CoiniumServ.Mining.Pools +namespace CoiniumServ.Pools { public interface IPoolManager { diff --git a/src/CoiniumServ/Mining/Pools/Pool.cs b/src/CoiniumServ/Pools/Pool.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Pool.cs rename to src/CoiniumServ/Pools/Pool.cs index e283d4c51..079eaa878 100644 --- a/src/CoiniumServ/Mining/Pools/Pool.cs +++ b/src/CoiniumServ/Pools/Pool.cs @@ -23,28 +23,27 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography; +using CoiniumServ.Banning; using CoiniumServ.Coin.Helpers; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Factories; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Jobs.Tracker; +using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining; using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Shares; +using CoiniumServ.Statistics; using CoiniumServ.Utils.Helpers.Validation; +using CoiniumServ.Vardiff; using Serilog; -namespace CoiniumServ.Mining.Pools +namespace CoiniumServ.Pools { /// /// Contains pool services and server. diff --git a/src/CoiniumServ/Mining/Pools/PoolManager.cs b/src/CoiniumServ/Pools/PoolManager.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/PoolManager.cs rename to src/CoiniumServ/Pools/PoolManager.cs index 990791f52..4ee833f0f 100644 --- a/src/CoiniumServ/Mining/Pools/PoolManager.cs +++ b/src/CoiniumServ/Pools/PoolManager.cs @@ -24,11 +24,11 @@ using System; using System.Collections.Generic; using System.Linq; +using CoiniumServ.Configuration; using CoiniumServ.Factories; -using CoiniumServ.Utils.Configuration; using Serilog; -namespace CoiniumServ.Mining.Pools +namespace CoiniumServ.Pools { public class PoolManager : IPoolManager { diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 6970ae1da..478fc6f64 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -29,7 +29,6 @@ using CoiniumServ.Repository; using CoiniumServ.Utils; using CoiniumServ.Utils.Commands; -using CoiniumServ.Utils.Logging; using CoiniumServ.Utils.Platform; using Nancy.TinyIoc; using Serilog; diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index d89f5e29d..a803d673d 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -23,17 +23,16 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Config; -using CoiniumServ.Mining.Pools.Statistics; -using CoiniumServ.Net.Server.Http.Web; +using CoiniumServ.Jobs.Tracker; +using CoiniumServ.Logging; +using CoiniumServ.Networking.Server.Http.Web; using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Redis; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Repository.Context; -using CoiniumServ.Server.Web; -using CoiniumServ.Utils.Logging; +using CoiniumServ.Statistics; using Nancy.Bootstrapper; namespace CoiniumServ.Repository.Registries @@ -56,8 +55,8 @@ public void RegisterInstances() _applicationContext.Container.Register(Storages.Redis).AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); - _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 8aa0b8cfa..629e64be2 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -21,14 +21,14 @@ // #endregion -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Shares; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Banning; +using CoiniumServ.Configuration; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Miners; +using CoiniumServ.Pools; using CoiniumServ.Repository.Context; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Shares; +using CoiniumServ.Vardiff; namespace CoiniumServ.Repository.Registries { diff --git a/src/CoiniumServ/Server/Mining/IMiningServer.cs b/src/CoiniumServ/Server/Mining/IMiningServer.cs index 1333af916..fec82048d 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServer.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServer.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Net.Server; +using CoiniumServ.Networking.Server; namespace CoiniumServ.Server.Mining { diff --git a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs index 06e85ace9..ed26f09fb 100644 --- a/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/IMiningServerConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Server.Mining { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index ff00a1fdc..3620b32c8 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Vardiff; namespace CoiniumServ.Server.Mining.Stratum.Config { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index 02336699a..80e9f1b68 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Vardiff; using Serilog; namespace CoiniumServ.Server.Mining.Stratum.Config diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index 9d82baea1..ba4facbea 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -22,9 +22,9 @@ #endregion using System; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Vardiff; +using CoiniumServ.Miners; using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Vardiff; namespace CoiniumServ.Server.Mining.Stratum { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs index b20601691..da6c4f1eb 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/SocketServiceContext.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Mining.Miners; +using CoiniumServ.Miners; namespace CoiniumServ.Server.Mining.Stratum.Service { diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index c2ba66e26..cb3c8eb5a 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -23,10 +23,10 @@ using AustinHarris.JsonRpc; using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Shares; +using CoiniumServ.Jobs; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Mining.Stratum.Responses; +using CoiniumServ.Shares; namespace CoiniumServ.Server.Mining.Stratum.Service { diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 60e021356..634504386 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -24,15 +24,15 @@ using System; using System.Text; using AustinHarris.JsonRpc; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Logging; +using CoiniumServ.Miners; +using CoiniumServ.Networking.Server.Sockets; +using CoiniumServ.Pools; using CoiniumServ.Server.Mining.Stratum.Errors; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Stratum.Service; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Extensions; -using CoiniumServ.Utils.Logging; using Newtonsoft.Json; using Serilog; diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index b32e77cda..977f3f39d 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -24,12 +24,12 @@ using System; using System.Net; using System.Net.Sockets; +using CoiniumServ.Banning; using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Banning; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Net.Server.Sockets; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Miners; +using CoiniumServ.Networking.Server.Sockets; +using CoiniumServ.Pools; using Serilog; // stratum server uses json-rpc 2.0 (over raw sockets) & json-rpc.net (http://jsonrpc2.codeplex.com/) diff --git a/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs index 1b0f7e223..b496a06bc 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/IVanillaMiner.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Mining.Miners; +using CoiniumServ.Miners; namespace CoiniumServ.Server.Mining.Vanilla { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs index 29a8b3ec7..9ee129b05 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/HttpServiceContext.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Mining.Miners; +using CoiniumServ.Miners; namespace CoiniumServ.Server.Mining.Vanilla.Service { diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index f6ca4fb1f..5bfa6f36f 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -25,8 +25,8 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Shares; using CoiniumServ.Server.Mining.Service; +using CoiniumServ.Shares; using Serilog; namespace CoiniumServ.Server.Mining.Vanilla.Service diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 981412f80..91c05ee5c 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -27,11 +27,11 @@ using System.Text; using AustinHarris.JsonRpc; using CoiniumServ.Factories; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; +using CoiniumServ.Logging; +using CoiniumServ.Miners; +using CoiniumServ.Pools; using CoiniumServ.Server.Mining.Vanilla.Service; using CoiniumServ.Utils.Extensions; -using CoiniumServ.Utils.Logging; using Serilog; namespace CoiniumServ.Server.Mining.Vanilla diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index ae611ef13..9c371d048 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -25,10 +25,10 @@ // classic server uses json-rpc 1.0 (over http) & json-rpc.net (http://jsonrpc2.codeplex.com/) using CoiniumServ.Coin.Config; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Net.Server.Http.Basic; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Miners; +using CoiniumServ.Networking.Server.Http.Basic; +using CoiniumServ.Pools; using Serilog; namespace CoiniumServ.Server.Mining.Vanilla diff --git a/src/CoiniumServ/Server/Web/IWebServer.cs b/src/CoiniumServ/Server/Web/IWebServer.cs index d8650e24d..2dbc65e0a 100644 --- a/src/CoiniumServ/Server/Web/IWebServer.cs +++ b/src/CoiniumServ/Server/Web/IWebServer.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Net.Server; +using CoiniumServ.Networking.Server; namespace CoiniumServ.Server.Web { diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index 002fabd74..c4734b146 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -22,7 +22,7 @@ #endregion using System; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; namespace CoiniumServ.Server.Web { diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index 1573ee38a..f3af67576 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Pools; using CoiniumServ.Server.Web.Modules.Models; +using CoiniumServ.Statistics; using Nancy; using Newtonsoft.Json; diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index 4feced4d7..465c861ed 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -22,8 +22,8 @@ #endregion using System.Collections.Generic; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Statistics; +using CoiniumServ.Pools; +using CoiniumServ.Statistics; using Nancy; namespace CoiniumServ.Server.Web.Modules diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index afc63aa17..8e9e9f9e2 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -21,7 +21,7 @@ // #endregion -using CoiniumServ.Mining.Pools; +using CoiniumServ.Pools; using CoiniumServ.Server.Web.Modules.Models; using Nancy; diff --git a/src/CoiniumServ/Server/Web/WebServer.cs b/src/CoiniumServ/Server/Web/WebServer.cs index 69b25fd88..ddaab55e1 100644 --- a/src/CoiniumServ/Server/Web/WebServer.cs +++ b/src/CoiniumServ/Server/Web/WebServer.cs @@ -21,8 +21,8 @@ // #endregion -using CoiniumServ.Net.Server.Http.Web; -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; +using CoiniumServ.Networking.Server.Http.Web; using Nancy.Bootstrapper; using Serilog; diff --git a/src/CoiniumServ/Mining/Shares/IShare.cs b/src/CoiniumServ/Shares/IShare.cs similarity index 97% rename from src/CoiniumServ/Mining/Shares/IShare.cs rename to src/CoiniumServ/Shares/IShare.cs index b48997e80..167f2ce2e 100644 --- a/src/CoiniumServ/Mining/Shares/IShare.cs +++ b/src/CoiniumServ/Shares/IShare.cs @@ -24,11 +24,11 @@ using System; using CoiniumServ.Cryptology; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Miners; +using CoiniumServ.Miners; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Utils.Numerics; -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public interface IShare { diff --git a/src/CoiniumServ/Mining/Shares/IShareManager.cs b/src/CoiniumServ/Shares/IShareManager.cs similarity index 97% rename from src/CoiniumServ/Mining/Shares/IShareManager.cs rename to src/CoiniumServ/Shares/IShareManager.cs index e7950e3f2..6f5d29bde 100644 --- a/src/CoiniumServ/Mining/Shares/IShareManager.cs +++ b/src/CoiniumServ/Shares/IShareManager.cs @@ -25,7 +25,7 @@ using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Vanilla; -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public interface IShareManager { diff --git a/src/CoiniumServ/Mining/Shares/Share.cs b/src/CoiniumServ/Shares/Share.cs similarity index 98% rename from src/CoiniumServ/Mining/Shares/Share.cs rename to src/CoiniumServ/Shares/Share.cs index 86b2db77b..fa2684b89 100644 --- a/src/CoiniumServ/Mining/Shares/Share.cs +++ b/src/CoiniumServ/Shares/Share.cs @@ -26,14 +26,14 @@ using CoiniumServ.Cryptology; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Miners; +using CoiniumServ.Miners; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Utils.Extensions; using CoiniumServ.Utils.Numerics; using Serilog; -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public class Share : IShare { diff --git a/src/CoiniumServ/Mining/Shares/ShareError.cs b/src/CoiniumServ/Shares/ShareError.cs similarity index 97% rename from src/CoiniumServ/Mining/Shares/ShareError.cs rename to src/CoiniumServ/Shares/ShareError.cs index 8e6a7e69a..10ae8e073 100644 --- a/src/CoiniumServ/Mining/Shares/ShareError.cs +++ b/src/CoiniumServ/Shares/ShareError.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public enum ShareError { diff --git a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs b/src/CoiniumServ/Shares/ShareEventArgs.cs similarity index 97% rename from src/CoiniumServ/Mining/Shares/ShareEventArgs.cs rename to src/CoiniumServ/Shares/ShareEventArgs.cs index 2a9b4fb70..4c70dd77a 100644 --- a/src/CoiniumServ/Mining/Shares/ShareEventArgs.cs +++ b/src/CoiniumServ/Shares/ShareEventArgs.cs @@ -24,7 +24,7 @@ using System; using CoiniumServ.Server.Mining.Stratum; -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public class ShareEventArgs:EventArgs { diff --git a/src/CoiniumServ/Mining/Shares/ShareManager.cs b/src/CoiniumServ/Shares/ShareManager.cs similarity index 98% rename from src/CoiniumServ/Mining/Shares/ShareManager.cs rename to src/CoiniumServ/Shares/ShareManager.cs index f56292815..c52d4bb41 100644 --- a/src/CoiniumServ/Mining/Shares/ShareManager.cs +++ b/src/CoiniumServ/Shares/ShareManager.cs @@ -23,9 +23,8 @@ using System; using AustinHarris.JsonRpc; -using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; -using CoiniumServ.Mining.Jobs.Tracker; +using CoiniumServ.Jobs.Tracker; using CoiniumServ.Persistance; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Errors; @@ -33,7 +32,7 @@ using CoiniumServ.Utils.Extensions; using Serilog; -namespace CoiniumServ.Mining.Shares +namespace CoiniumServ.Shares { public class ShareManager : IShareManager { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs b/src/CoiniumServ/Statistics/Algorithms.cs similarity index 98% rename from src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs rename to src/CoiniumServ/Statistics/Algorithms.cs index 6ce2978dc..2201a2388 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Algorithms.cs +++ b/src/CoiniumServ/Statistics/Algorithms.cs @@ -25,9 +25,10 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using CoiniumServ.Pools; using Newtonsoft.Json; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class Algorithms : IAlgorithms { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs b/src/CoiniumServ/Statistics/Blocks.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs rename to src/CoiniumServ/Statistics/Blocks.cs index 797897354..ad2795798 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Blocks.cs +++ b/src/CoiniumServ/Statistics/Blocks.cs @@ -23,7 +23,7 @@ using CoiniumServ.Persistance; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class Blocks:IBlocks { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs b/src/CoiniumServ/Statistics/Global.cs similarity index 98% rename from src/CoiniumServ/Mining/Pools/Statistics/Global.cs rename to src/CoiniumServ/Statistics/Global.cs index 65cdd2daa..d83337418 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Global.cs +++ b/src/CoiniumServ/Statistics/Global.cs @@ -25,7 +25,7 @@ using System.Dynamic; using Newtonsoft.Json; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class Global : IGlobal { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs b/src/CoiniumServ/Statistics/IAlgorithms.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs rename to src/CoiniumServ/Statistics/IAlgorithms.cs index 6d777f362..bbb3f5a70 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IAlgorithms.cs +++ b/src/CoiniumServ/Statistics/IAlgorithms.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IAlgorithms: IEnumerable>, IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs b/src/CoiniumServ/Statistics/IBlocks.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs rename to src/CoiniumServ/Statistics/IBlocks.cs index 0088be6c8..762d64ec0 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IBlocks.cs +++ b/src/CoiniumServ/Statistics/IBlocks.cs @@ -21,7 +21,7 @@ // #endregion -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IBlocks : IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs b/src/CoiniumServ/Statistics/IGlobal.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs rename to src/CoiniumServ/Statistics/IGlobal.cs index 07b7edc36..4f13f5369 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IGlobal.cs +++ b/src/CoiniumServ/Statistics/IGlobal.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IGlobal: IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs b/src/CoiniumServ/Statistics/IJsonResponse.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs rename to src/CoiniumServ/Statistics/IJsonResponse.cs index 1af108a76..eafe9296a 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IJsonResponse.cs +++ b/src/CoiniumServ/Statistics/IJsonResponse.cs @@ -21,7 +21,7 @@ // #endregion -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IJsonResponse { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs b/src/CoiniumServ/Statistics/ILatestBlocks.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs rename to src/CoiniumServ/Statistics/ILatestBlocks.cs index b31e17d20..7aef93770 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/ILatestBlocks.cs +++ b/src/CoiniumServ/Statistics/ILatestBlocks.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; using CoiniumServ.Persistance.Blocks; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface ILatestBlocks: IEnumerable, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs b/src/CoiniumServ/Statistics/IPerAlgorithm.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs rename to src/CoiniumServ/Statistics/IPerAlgorithm.cs index 4dbf027ec..8c9a371d4 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerAlgorithm.cs +++ b/src/CoiniumServ/Statistics/IPerAlgorithm.cs @@ -23,7 +23,7 @@ using System; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IPerAlgorithm:IJsonResponse { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs b/src/CoiniumServ/Statistics/IPerPool.cs similarity index 94% rename from src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs rename to src/CoiniumServ/Statistics/IPerPool.cs index b83b42058..66387dce3 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPerPool.cs +++ b/src/CoiniumServ/Statistics/IPerPool.cs @@ -22,9 +22,9 @@ #endregion using System; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Pools.Config; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IPerPool:IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs b/src/CoiniumServ/Statistics/IPools.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IPools.cs rename to src/CoiniumServ/Statistics/IPools.cs index 1db85a011..0554c6b34 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IPools.cs +++ b/src/CoiniumServ/Statistics/IPools.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IPools : IEnumerable>,IJsonResponse, IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs b/src/CoiniumServ/Statistics/IStatistics.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs rename to src/CoiniumServ/Statistics/IStatistics.cs index dfad1f911..febf8ac63 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatistics.cs +++ b/src/CoiniumServ/Statistics/IStatistics.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IStatistics { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs b/src/CoiniumServ/Statistics/IStatisticsProvider.cs similarity index 96% rename from src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs rename to src/CoiniumServ/Statistics/IStatisticsProvider.cs index 5cf1596ef..3574c405d 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/IStatisticsProvider.cs +++ b/src/CoiniumServ/Statistics/IStatisticsProvider.cs @@ -20,7 +20,7 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public interface IStatisticsProvider { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs b/src/CoiniumServ/Statistics/LatestBlocks.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs rename to src/CoiniumServ/Statistics/LatestBlocks.cs index 6768ae523..1741b12cf 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/LatestBlocks.cs +++ b/src/CoiniumServ/Statistics/LatestBlocks.cs @@ -27,7 +27,7 @@ using CoiniumServ.Persistance; using CoiniumServ.Persistance.Blocks; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class LatestBlocks:ILatestBlocks { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs b/src/CoiniumServ/Statistics/PerAlgorithm.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs rename to src/CoiniumServ/Statistics/PerAlgorithm.cs index c5fbdbb29..0c0616a10 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerAlgorithm.cs +++ b/src/CoiniumServ/Statistics/PerAlgorithm.cs @@ -25,7 +25,7 @@ using System.Dynamic; using Newtonsoft.Json; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class PerAlgorithm:IPerAlgorithm { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs b/src/CoiniumServ/Statistics/PerPool.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs rename to src/CoiniumServ/Statistics/PerPool.cs index b218cf6d7..be7e45189 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/PerPool.cs +++ b/src/CoiniumServ/Statistics/PerPool.cs @@ -26,13 +26,13 @@ using System.Linq; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; -using CoiniumServ.Mining.Miners; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Miners; using CoiniumServ.Persistance; +using CoiniumServ.Pools.Config; using CoiniumServ.Utils.Helpers.Time; using Newtonsoft.Json; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class PerPool:IPerPool { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs b/src/CoiniumServ/Statistics/Pools.cs similarity index 98% rename from src/CoiniumServ/Mining/Pools/Statistics/Pools.cs rename to src/CoiniumServ/Statistics/Pools.cs index fa9b2ce05..615958717 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Pools.cs +++ b/src/CoiniumServ/Statistics/Pools.cs @@ -26,9 +26,10 @@ using System.Collections.Generic; using System.Dynamic; using System.Linq; +using CoiniumServ.Pools; using Newtonsoft.Json; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class Pools:IPools { diff --git a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs b/src/CoiniumServ/Statistics/Statistics.cs similarity index 97% rename from src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs rename to src/CoiniumServ/Statistics/Statistics.cs index 8b5275808..646d02d49 100644 --- a/src/CoiniumServ/Mining/Pools/Statistics/Statistics.cs +++ b/src/CoiniumServ/Statistics/Statistics.cs @@ -24,7 +24,7 @@ using System.Threading; using CoiniumServ.Factories; -namespace CoiniumServ.Mining.Pools.Statistics +namespace CoiniumServ.Statistics { public class Statistics:IStatistics, IStatisticsProvider { diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 6c1a8ea84..37b4fcb1d 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -29,8 +29,7 @@ using CoiniumServ.Cryptology; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Jobs; using CoiniumServ.Payments; using CoiniumServ.Transactions.Script; using CoiniumServ.Utils.Helpers.Time; diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs b/src/CoiniumServ/Vardiff/IVardiffConfig.cs similarity index 96% rename from src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs rename to src/CoiniumServ/Vardiff/IVardiffConfig.cs index c22a443c0..65cdef2a8 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffConfig.cs +++ b/src/CoiniumServ/Vardiff/IVardiffConfig.cs @@ -21,9 +21,9 @@ // #endregion -using CoiniumServ.Utils.Configuration; +using CoiniumServ.Configuration; -namespace CoiniumServ.Mining.Vardiff +namespace CoiniumServ.Vardiff { public interface IVardiffConfig : IConfig { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs b/src/CoiniumServ/Vardiff/IVardiffManager.cs similarity index 96% rename from src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs rename to src/CoiniumServ/Vardiff/IVardiffManager.cs index 3d6125b4d..38f59065b 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffManager.cs +++ b/src/CoiniumServ/Vardiff/IVardiffManager.cs @@ -21,7 +21,7 @@ // #endregion -namespace CoiniumServ.Mining.Vardiff +namespace CoiniumServ.Vardiff { public interface IVardiffManager { diff --git a/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs b/src/CoiniumServ/Vardiff/IVardiffMiner.cs similarity index 97% rename from src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs rename to src/CoiniumServ/Vardiff/IVardiffMiner.cs index e74b54f2f..efaf55598 100644 --- a/src/CoiniumServ/Mining/Vardiff/IVardiffMiner.cs +++ b/src/CoiniumServ/Vardiff/IVardiffMiner.cs @@ -23,7 +23,7 @@ using CoiniumServ.Utils.Buffers; -namespace CoiniumServ.Mining.Vardiff +namespace CoiniumServ.Vardiff { public interface IVardiffMiner { diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Vardiff/VardiffConfig.cs similarity index 98% rename from src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs rename to src/CoiniumServ/Vardiff/VardiffConfig.cs index 3f912e0b6..80306fb68 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffConfig.cs +++ b/src/CoiniumServ/Vardiff/VardiffConfig.cs @@ -24,7 +24,7 @@ using System; using Serilog; -namespace CoiniumServ.Mining.Vardiff +namespace CoiniumServ.Vardiff { public class VardiffConfig:IVardiffConfig { diff --git a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs b/src/CoiniumServ/Vardiff/VardiffManager.cs similarity index 98% rename from src/CoiniumServ/Mining/Vardiff/VardiffManager.cs rename to src/CoiniumServ/Vardiff/VardiffManager.cs index 37e5477c8..049f14ed1 100644 --- a/src/CoiniumServ/Mining/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Vardiff/VardiffManager.cs @@ -22,12 +22,12 @@ #endregion using System; -using CoiniumServ.Mining.Shares; +using CoiniumServ.Shares; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Helpers.Time; using Serilog; -namespace CoiniumServ.Mining.Vardiff +namespace CoiniumServ.Vardiff { public class VardiffManager:IVardiffManager { diff --git a/src/CoiniumServ/web/default/pool.cshtml b/src/CoiniumServ/web/default/pool.cshtml index 91adcca5d..97a445991 100644 --- a/src/CoiniumServ/web/default/pool.cshtml +++ b/src/CoiniumServ/web/default/pool.cshtml @@ -1,8 +1,6 @@ -@using System -@using System.Linq -@using CoiniumServ.Coin.Helpers +@using CoiniumServ.Coin.Helpers @using CoiniumServ.Persistance.Blocks -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } diff --git a/src/Tests/Coin/Coinbase/SerializersTests.cs b/src/Tests/Coin/Coinbase/SerializersTests.cs index c6013b953..6c09931e7 100644 --- a/src/Tests/Coin/Coinbase/SerializersTests.cs +++ b/src/Tests/Coin/Coinbase/SerializersTests.cs @@ -28,8 +28,7 @@ using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Jobs; using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Transactions; diff --git a/src/Tests/Mining/Pools/PoolTests.cs b/src/Tests/Pools/PoolTests.cs similarity index 96% rename from src/Tests/Mining/Pools/PoolTests.cs rename to src/Tests/Pools/PoolTests.cs index 0c456e3b4..bdfe7ad58 100644 --- a/src/Tests/Mining/Pools/PoolTests.cs +++ b/src/Tests/Pools/PoolTests.cs @@ -25,13 +25,13 @@ using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; using CoiniumServ.Factories; -using CoiniumServ.Mining.Pools; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using NSubstitute; using Should.Fluent; using Xunit; -namespace CoiniumServ.Tests.Mining.Pools +namespace CoiniumServ.Tests.Pools { public class PoolTests { diff --git a/src/Tests/Server/Stratum/Notifications/JobTests.cs b/src/Tests/Server/Stratum/Notifications/JobTests.cs index cdcc395b2..27c8dd2bd 100644 --- a/src/Tests/Server/Stratum/Notifications/JobTests.cs +++ b/src/Tests/Server/Stratum/Notifications/JobTests.cs @@ -27,8 +27,7 @@ using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Jobs; using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Transactions; diff --git a/src/Tests/Mining/Shares/ShareTests.cs b/src/Tests/Shares/ShareTests.cs similarity index 99% rename from src/Tests/Mining/Shares/ShareTests.cs rename to src/Tests/Shares/ShareTests.cs index e7c189a8c..6306b9aff 100644 --- a/src/Tests/Mining/Shares/ShareTests.cs +++ b/src/Tests/Shares/ShareTests.cs @@ -27,13 +27,13 @@ using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Jobs.Manager; -using CoiniumServ.Mining.Jobs.Tracker; -using CoiniumServ.Mining.Shares; +using CoiniumServ.Jobs; +using CoiniumServ.Jobs.Manager; +using CoiniumServ.Jobs.Tracker; using CoiniumServ.Payments; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; +using CoiniumServ.Shares; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Script; using CoiniumServ.Utils.Extensions; @@ -43,7 +43,7 @@ using Should.Fluent; using Xunit; -namespace CoiniumServ.Tests.Mining.Shares +namespace CoiniumServ.Tests.Shares { public class ShareTests { diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 7b5a84515..80b4c9f38 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -69,13 +69,13 @@ - + - + diff --git a/src/Tests/Transactions/GenerationTransactionTests.cs b/src/Tests/Transactions/GenerationTransactionTests.cs index b3a84959e..9fe69a8ba 100644 --- a/src/Tests/Transactions/GenerationTransactionTests.cs +++ b/src/Tests/Transactions/GenerationTransactionTests.cs @@ -26,8 +26,7 @@ using System.Linq; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; -using CoiniumServ.Mining.Pools.Config; +using CoiniumServ.Jobs; using CoiniumServ.Payments; using CoiniumServ.Transactions; using CoiniumServ.Transactions.Script; diff --git a/src/Tests/Transactions/Script/SignatureScriptTests.cs b/src/Tests/Transactions/Script/SignatureScriptTests.cs index 5267397bc..bba1b68bb 100644 --- a/src/Tests/Transactions/Script/SignatureScriptTests.cs +++ b/src/Tests/Transactions/Script/SignatureScriptTests.cs @@ -23,7 +23,7 @@ using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; -using CoiniumServ.Mining.Jobs; +using CoiniumServ.Jobs; using CoiniumServ.Transactions.Script; using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; From 8d93c9df7983e845c30694644706fff0b6a38331 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 15:06:38 +0300 Subject: [PATCH 128/230] Implemented /api/ documentation page. Removed unused bootstrap html files. Added /donate/ page. Fixed web layout. Removed nancydiagnostics configuration. Set version to 0.1.0.* --- src/CoiniumServ/CoiniumServ.csproj | 37 +- .../Server/Http/Web/WebBootstrapper.cs | 7 +- src/CoiniumServ/Server/Web/Modules/Api.cs | 17 +- src/CoiniumServ/Server/Web/Modules/Donate.cs | 35 + src/CoiniumServ/Server/Web/Modules/Pool.cs | 2 +- src/CoiniumServ/Utils/Versions/VersionInfo.cs | 2 +- src/CoiniumServ/web/default/api.cshtml | 86 +- src/CoiniumServ/web/default/blank-page.html | 141 ---- .../web/default/bootstrap-elements.html | 745 ------------------ .../web/default/bootstrap-grid.html | 400 ---------- src/CoiniumServ/web/default/charts.html | 314 -------- src/CoiniumServ/web/default/donate.cshtml | 38 + src/CoiniumServ/web/default/forms.html | 365 --------- .../web/default/images/coiniumserv.png | Bin 0 -> 1795 bytes src/CoiniumServ/web/default/index.cshtml | 2 +- src/CoiniumServ/web/default/index.html | 421 ---------- src/CoiniumServ/web/default/layout.cshtml | 95 +-- src/CoiniumServ/web/default/tables.html | 457 ----------- src/CoiniumServ/web/default/typography.html | 269 ------- 19 files changed, 194 insertions(+), 3239 deletions(-) create mode 100644 src/CoiniumServ/Server/Web/Modules/Donate.cs delete mode 100644 src/CoiniumServ/web/default/blank-page.html delete mode 100644 src/CoiniumServ/web/default/bootstrap-elements.html delete mode 100644 src/CoiniumServ/web/default/bootstrap-grid.html delete mode 100644 src/CoiniumServ/web/default/charts.html create mode 100644 src/CoiniumServ/web/default/donate.cshtml delete mode 100644 src/CoiniumServ/web/default/forms.html create mode 100644 src/CoiniumServ/web/default/images/coiniumserv.png delete mode 100644 src/CoiniumServ/web/default/index.html delete mode 100644 src/CoiniumServ/web/default/tables.html delete mode 100644 src/CoiniumServ/web/default/typography.html diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 31367494a..c6d5248bd 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -139,6 +139,7 @@ + @@ -802,6 +803,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -898,9 +905,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -920,22 +924,12 @@ - - PreserveNewest - - + PreserveNewest - - - PreserveNewest - - - PreserveNewest - + PreserveNewest - PreserveNewest @@ -954,9 +948,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -993,16 +984,8 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - - + diff --git a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs index 7f4ae429a..1121ddbcd 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs @@ -26,7 +26,6 @@ using Nancy.Bootstrapper; using Nancy.Conventions; using Nancy.CustomErrors; -using Nancy.Diagnostics; using Nancy.TinyIoc; namespace CoiniumServ.Networking.Server.Http.Web @@ -43,11 +42,6 @@ public WebBootstrapper(IApplicationContext applicationContext) _applicationContext = applicationContext; } - protected override DiagnosticsConfiguration DiagnosticsConfiguration - { - get { return new DiagnosticsConfiguration { Password = @"coinium" }; } - } - protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { StaticConfiguration.EnableRequestTracing = true; @@ -65,6 +59,7 @@ protected override void ConfigureConventions(NancyConventions nancyConventions) nancyConventions.StaticContentsConventions.Clear(); nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("css", "/css")); nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("js", "/js")); + nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("images", "/images")); nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("font-awesome", "/font-awesome")); // view location diff --git a/src/CoiniumServ/Server/Web/Modules/Api.cs b/src/CoiniumServ/Server/Web/Modules/Api.cs index f3af67576..40d3ed860 100644 --- a/src/CoiniumServ/Server/Web/Modules/Api.cs +++ b/src/CoiniumServ/Server/Web/Modules/Api.cs @@ -21,7 +21,8 @@ // #endregion -using CoiniumServ.Pools; +using System.Linq; +using CoiniumServ.Coin.Config; using CoiniumServ.Server.Web.Modules.Models; using CoiniumServ.Statistics; using Nancy; @@ -31,9 +32,13 @@ namespace CoiniumServ.Server.Web.Modules { public class ApiModule: NancyModule { - public ApiModule(IPoolManager poolManager, IStatistics statistics) + public ApiModule(IStatistics statistics) { - Get["/api"] = _ => View["api"]; + Get["/api/"] = _ => View["api", new ApiModel + { + BaseUrl = Request.Url.SiteBase, + Coin = statistics.Pools.First().Value.Config.Coin + }]; Get["/api/global"] = _ => Response.AsJson(statistics.Global.GetResponseObject()); @@ -72,4 +77,10 @@ public ApiModule(IPoolManager poolManager, IStatistics statistics) }; } } + + public class ApiModel + { + public string BaseUrl { get; set; } + public ICoinConfig Coin { get; set; } + } } diff --git a/src/CoiniumServ/Server/Web/Modules/Donate.cs b/src/CoiniumServ/Server/Web/Modules/Donate.cs new file mode 100644 index 000000000..65b8926d7 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Donate.cs @@ -0,0 +1,35 @@ +#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 Nancy; + +namespace CoiniumServ.Server.Web.Modules +{ + public class DonateModule : NancyModule + { + public DonateModule() + { + Get["/donate/"] = _ => View["donate"]; + } + } +} diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index 8e9e9f9e2..3d1bd5423 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -31,7 +31,7 @@ public class PoolModule : NancyModule { public PoolModule(IPoolManager poolManager) { - Get["/pool/{slug}"] = _ => + Get["/pool/{slug}/"] = _ => { var pool = poolManager.GetBySymbol(_.slug); diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index 84eb42df9..a0de731ba 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -36,7 +36,7 @@ public static class Assembly /// /// Main assemblies version. /// - public const string Version = "0.1.*"; + public const string Version = "0.1.0.*"; } } } diff --git a/src/CoiniumServ/web/default/api.cshtml b/src/CoiniumServ/web/default/api.cshtml index 48ed858b1..7a38a26c7 100644 --- a/src/CoiniumServ/web/default/api.cshtml +++ b/src/CoiniumServ/web/default/api.cshtml @@ -1,7 +1,89 @@ -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@using System.Linq +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; }
    - test +
    +
    +
    +

    API

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ActionArgumentsDescriptionDemo
    globalnoneGlobal Information
    Returns general statistics & information about the pool network.
    +
    + + +
    +
    poolsnonePools List & Statistics
    Returns list of pools and detailed statistics for them.
    +
    + + +
    +
    poolcoin symbolPool Statistics
    Returns detailed statistics for a given pool.
    + @if (@Model.Coin != null) + { +
    + + +
    + } +
    algorithmsnoneAlgorithms List & Statistics
    Returns list of algorithms and detailed statistics for them.
    +
    + + +
    +
    algorithmalgorithm nameAlgorithm Statistics
    Returns detailed statistics for a given algorithm.
    + @if (@Model.Coin != null) + { +
    + + +
    + } +
    +
    +
    +
    diff --git a/src/CoiniumServ/web/default/blank-page.html b/src/CoiniumServ/web/default/blank-page.html deleted file mode 100644 index cba3c1bdd..000000000 --- a/src/CoiniumServ/web/default/blank-page.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - Blank Page - SB Admin - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/CoiniumServ/web/default/bootstrap-elements.html b/src/CoiniumServ/web/default/bootstrap-elements.html deleted file mode 100644 index da685d581..000000000 --- a/src/CoiniumServ/web/default/bootstrap-elements.html +++ /dev/null @@ -1,745 +0,0 @@ - - - - - - - - - Bootstrap Elements - SB Admin - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Bootstrap Elements Built-In Bootstrap Elements

    - -
    - - Start Bootstrap recommends that you have an in-depth understanding of the Bootstrap framework before working with this template. Visit http://getbootstrap.com/ for complete documentation. -
    -
    -
    - -
    -
    -

    Buttons

    -
    -
    - -
    -
    - -

    - - - - - - - -

    - -

    - - - - - - - -

    - -

    -

    - - - - -

    - -

    - - - - -

    - -
    - -
    - -

    - -

    - -

    -

    - Left - Right - Middle -
    -

    - -

    -

    -
    - - - - -
    -
    - - - -
    -
    - - -
    - - -
    -
    -
    -

    - -

    -

    - - - - -
    -

    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    - -
    -
    -

    Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.

    -
    -
    -

    Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit.

    -
    - - -
    -
    -
    - -
    - -
    - - - -
    - -
    -
    - -
    -
    -

    Pagination

    -
    - - - -
    -
    -
    -

    Pager

    -
    - -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    -

    Alerts

    -
    -
    - -

    Warning!

    -

    Best check yo self, you're not looking too good. Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

    -
    -
    -
    -
    - -
    -
    -
    - - Oh snap! Change a few things up and try submitting again. -
    -
    -
    -
    - - Well done! You successfully read this important alert message. -
    -
    -
    -
    - - Heads up! This alert needs your attention, but it's not super important. -
    -
    -
    - -
    -
    -

    Labels

    -
    - Default - Primary - Success - Warning - Danger - Info -
    -
    -
    -

    Badges

    - -
    -
    - -
    -
    - - -

    Basic

    -
    -
    -
    -
    -
    - -

    Contextual alternatives

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    Striped

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    Animated

    -
    -
    -
    -
    -
    - -

    Stacked

    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    - -
    -
    -

    Jumbotron

    -

    This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.

    -

    Learn more

    -
    -
    -
    -
    - -
    -
    -

    List groups

    -
    -
    - - - -
    -
    -

    Panels

    -
    -
    - -
    -
    -
    -
    - Basic panel -
    -
    -
    -
    Panel heading
    -
    - Panel content -
    -
    -
    -
    - Panel content -
    - -
    -
    -
    -
    -
    -

    Panel primary

    -
    -
    - Panel content -
    -
    -
    -
    -

    Panel success

    -
    -
    - Panel content -
    -
    -
    -
    -

    Panel warning

    -
    -
    - Panel content -
    -
    -
    -
    -
    -
    -

    Panel danger

    -
    -
    - Panel content -
    -
    -
    -
    -

    Panel info

    -
    -
    - Panel content -
    -
    -
    -
    - -
    -
    -

    Wells

    -
    -
    - -
    -
    -
    - Look, I'm in a well! -
    -
    -
    -
    - Look, I'm in a small well! -
    -
    -
    -
    - Look, I'm in a large well! -
    -
    -
    - -
    - -
    - - - - - - - \ No newline at end of file diff --git a/src/CoiniumServ/web/default/bootstrap-grid.html b/src/CoiniumServ/web/default/bootstrap-grid.html deleted file mode 100644 index 9709db82a..000000000 --- a/src/CoiniumServ/web/default/bootstrap-grid.html +++ /dev/null @@ -1,400 +0,0 @@ - - - - - - - - - Bootstrap Grid - SB Admin - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Bootstrap Grid Built-In Bootstrap Grid

    - -
    - - Be sure to visit Bootstrap's grid documentation for more information. -
    -
    -
    - -
    -
    -
    -
    - .col-lg-12 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-6 -
    -
    -
    -
    -
    -
    - .col-lg-6 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-4 -
    -
    -
    -
    -
    -
    - .col-lg-4 -
    -
    -
    -
    -
    -
    - .col-lg-4 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    -
    -
    - .col-lg-2 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    -
    -
    - .col-lg-1 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-8 -
    -
    -
    -
    -
    -
    - .col-lg-4 -
    -
    -
    -
    - -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    -
    -
    - .col-lg-6 -
    -
    -
    -
    -
    -
    - .col-lg-3 -
    -
    -
    -
    - -
    - -
    - - - - - - - \ No newline at end of file diff --git a/src/CoiniumServ/web/default/charts.html b/src/CoiniumServ/web/default/charts.html deleted file mode 100644 index 4199f012b..000000000 --- a/src/CoiniumServ/web/default/charts.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - Charts - SB Admin - - - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Charts Display Your Data

    - -
    - - There are two options for charts: Flot charts and morris.js. Choose which one best suits your needs, and make sure to master the documentation to get the most out of these charts! -
    -
    -
    - -
    -
    -

    Flot Charts

    -
    -
    -

    Line Graph Example with Tooltips

    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -

    Pie Chart Example with Tooltips

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Multiple Axes Line Graph Example with Tooltips and Raw Data

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -

    Moving Line Chart

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Bar Graph with Tooltips

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -

    Additional Flot Chart Information

    -

    Full documentation for Flot can be found at http://www.flotcharts.org/. Flot has a lot of different options available, and they have a bunch of plugins as well that allow you to do neat things. Here we are using the tooltip plugin, the resize plugin, and the pie chart plugin, but there are many more to choose from. The documentation is a bit more advanced and requires a good deal of JavaScript knowledge in order to make the charts work for you.

    -

    NOTE: The charts are responsive, and the Flot charts are redrawn when the window resizes. The only one that needs a page refresh on a window resize is the pie chart. If you find a way to fix this, please let me know.

    -
    -
    - -
    -
    -

    morris.js Charts

    -
    -
    -

    Area Line Graph Example with Tooltips

    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -

    Donut Chart Example

    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Line Graph Example with Tooltips

    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Bar Graph Example

    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -

    Additional morris.js Information

    -

    Full documentation for morris.js charts can be found at http://www.oesmith.co.uk/morris.js/. The chart options for morris.js are line & area charts, bar charts, and donut charts. The documentation is pretty straight forward, and you will want to look at it in order to get the most out of the charts.

    -

    NOTE: The charts are responsive, but they are drawn when the window loads. If you change the window size, for instance resizing your brownser window, you will need to refresh the page to redraw the chart responsively. According to morris.js, automatically redrawing charts on window resizing is being worked into their next big update. -

    -
    - -
    - -
    - - - - - - - - - - - - - - - - - - - - diff --git a/src/CoiniumServ/web/default/donate.cshtml b/src/CoiniumServ/web/default/donate.cshtml new file mode 100644 index 000000000..6d179eb31 --- /dev/null +++ b/src/CoiniumServ/web/default/donate.cshtml @@ -0,0 +1,38 @@ +@{ Layout = "layout.cshtml"; } + + + diff --git a/src/CoiniumServ/web/default/forms.html b/src/CoiniumServ/web/default/forms.html deleted file mode 100644 index 2b1807b3b..000000000 --- a/src/CoiniumServ/web/default/forms.html +++ /dev/null @@ -1,365 +0,0 @@ - - - - - - - - - Forms - SB Admin - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Forms Enter Your Data

    - -
    - - Visit Bootstrap's Form Documentation for more information. -
    -
    -
    - -
    -
    - -
    - -
    - - -

    Example block-level help text here.

    -
    - -
    - - -
    - -
    - -

    email@example.com

    -
    - -
    - - -
    - -
    - - -
    - -
    - -
    - -
    -
    - -
    -
    - -
    -
    - -
    - - - - -
    - -
    - -
    - -
    -
    - -
    -
    - -
    -
    - -
    - - - - -
    - -
    - - -
    - -
    - - -
    - - - - -
    - -
    -
    -

    Disabled Form States

    - -
    - -
    - -
    - - -
    - -
    - - -
    - -
    - -
    - - - -
    - -
    - -

    Form Validation

    - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - -

    Input Groups

    - -
    - -
    - @ - -
    - -
    - - .00 -
    - -
    - - -
    - -
    - $ - - .00 -
    - -
    - - - - -
    - -
    - -

    For complete documentation, please visit Bootstrap's Form Documentation.

    - -
    -
    - -
    - -
    - - - - - - - \ No newline at end of file diff --git a/src/CoiniumServ/web/default/images/coiniumserv.png b/src/CoiniumServ/web/default/images/coiniumserv.png new file mode 100644 index 0000000000000000000000000000000000000000..0059557b0fdf4772228f551902f708786eb76e6f GIT binary patch literal 1795 zcmV+e2mJVnP)^6$%~zi9mqP}l>nv1ncpDf;AmIqIg0vF#`8$Raeo8__-B8c@@Y%qzEo6d z$h=?srmRNe-mOx*ql}lETd;&-N~IjvDq%T`kAz1dK||3rWfb~+-EvftzXP2(n2pL! znv#Tsgg$o3dyZk=k+5uQlsp_Mqa#qzP=5sXh@%-a#BVTq<)x`;$=h>wv)?jC4YMhw6#EJ1yF#F)9ftY}vyfNwco zqQ$~kN)5X#V@8Hrq%3=faCLot0GN&4fCq=}3Q`Aj}0C0NDf10M_JEfSrI|mfI4)0wRi^blL z8+aeu!(%i@(@E{TH$wz&f!|BO9Z?qsz6=WpapLR8hT6l!!XaYnrv-P8ybNY z=Yji`Akd~RmiC4Bb3uUHgr}$c@uUe}UcLbQ1U5pfNeR!JS(04g;^N}h9*p|I?A6&? zFlrJ6I1B5lNRssIah~%eITL`Nvl=POmQZjC@Z9BLKR}2?BS82DSbqyBv<{sAfS&U% z6g3xn4w%hwz4;OSws!tVlZu^zP41O^)>I5i2v3r@EVW-}`mPqu~OzGc-AP3L#z8oQmj5=1=qYT%Vj zLeaBhIDwZa!$HT}+k2!9eMDb4;To7%;S_v?ON&X817Cjyj<>c4%1^C~=b9xX87&-r zNHP?(ax)-&!X>{w6%Pcf;B5xC=)8)ce?FJz)VWQ_Ir)GleUo#Yq6@00b+(sZn0%)c zXQu?QP`JFFVdPStZyFvq#}ZR?E@?_`)!o1~M0={QQdhlJrK{a3HyHZeU8F_5WAdx# zDD^dlz>Ht+?Y228bd@iv^mXP)-5J^6kC7w3ANB5SIQWIx zD7N@F1e@Dt7MfAmvh_#?1wO=@6@m!>(J>gj(2b$;Xf*Ao%Qh8Y#QdcQY@n4Qh`GYG zMxa^(BfjW6WEfJzCU_&82w=L10w=}d9#JDh5aWgPZoMQBz@#jLA`;VWrhTj&pTX9y z-6bCC1z{sGNyg&BC1BJzq{=&E6Cp+|UWMs{Alhqe678i>eM!MXL~P6u9Q+jRVI-5t zu=a0?M4|wjL`j~aUdKI7|B+*na{p;T1qhk>hE@CEEVkM*(htBL2RI2!pdt>ba)0eU z?{&2(?4v|0cw7^-cc^VQJe{3M+-bwj*x~VW5d@`2_e#a*QTWPDNG5Hg4kU_^4m~kg zmK_HhR!bS$GAv4sCT-KV31S6iekjc=vX7$BdGB>}rLO}$7xir8*3FFvzMjMYWKt;# zne`@6sshCt&i*TSNG(wK@e;C;qtQz~ zL*qB>K#^bNSZ731CK|IM2@G{18Wj9o2j6c)>bx5&u@Uyr5A}kIEe#C(2Ck^!*CGLW zNofkFsWcCd5~4=fF|jX(XN63 l6-SCh{9_y@002ovPDHLkV1jhnR;K^} literal 0 HcmV?d00001 diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index 54c82ef12..f484f94a4 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -92,7 +92,7 @@ @foreach (var pool in Model.Pools) { - @pool.Config.Coin.Name + @pool.Config.Coin.Name @pool.Statistics.Hashrate.GetReadableHashrate() @pool.Statistics.NetworkHashrate.GetReadableHashrate() @pool.Statistics.Difficulty diff --git a/src/CoiniumServ/web/default/index.html b/src/CoiniumServ/web/default/index.html deleted file mode 100644 index 9da9cd4bc..000000000 --- a/src/CoiniumServ/web/default/index.html +++ /dev/null @@ -1,421 +0,0 @@ - - - - - - - - - Dashboard - SB Admin - - - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Dashboard Statistics Overview

    - -
    - - Welcome to SB Admin by Start Bootstrap! Feel free to use this template for your admin needs! We are using a few different plugins to handle the dynamic tables and charts, so make sure you check out the necessary documentation links provided. -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    -

    456

    -

    New Mentions!

    -
    -
    -
    - - - -
    -
    -
    -
    -
    -
    -
    - -
    -
    -

    12

    -

    To-Do Items

    -
    -
    -
    - - - -
    -
    -
    -
    -
    -
    -
    - -
    -
    -

    18

    -

    Crawl Errors

    -
    -
    -
    - - - -
    -
    -
    -
    -
    -
    -
    - -
    -
    -

    56

    -

    New Orders!

    -
    -
    -
    - - - -
    -
    -
    - -
    -
    -
    -
    -

    Traffic Statistics: October 1, 2013 - October 31, 2013

    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -

    Traffic Sources: October 1, 2013 - October 31, 2013

    -
    -
    -
    - -
    -
    -
    - -
    -
    -
    -

    Recent Transactions

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Order # Order Date Order Time Amount (USD)
    332610/21/20133:29 PM$321.33
    332510/21/20133:20 PM$234.34
    332410/21/20133:03 PM$724.17
    332310/21/20133:00 PM$23.71
    332210/21/20132:49 PM$8345.23
    332110/21/20132:23 PM$245.12
    332010/21/20132:15 PM$5663.54
    331910/21/20132:13 PM$943.45
    -
    - -
    -
    -
    -
    - -
    - - - -
    - - - - - - - - - - - - - - diff --git a/src/CoiniumServ/web/default/layout.cshtml b/src/CoiniumServ/web/default/layout.cshtml index 342ea769d..4d43f85ea 100644 --- a/src/CoiniumServ/web/default/layout.cshtml +++ b/src/CoiniumServ/web/default/layout.cshtml @@ -35,89 +35,15 @@ - CoiniumServ + CoiniumServ @@ -134,14 +60,11 @@ Pool-name is powered by open source CoiniumServ project created by coinium.org
    -   Support by donating : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D -
    -
    - : #coinium-serv - | Forums - | API - | Donate - + #coiniumserv + | Forums + | API + | Donate + |
    diff --git a/src/CoiniumServ/web/default/tables.html b/src/CoiniumServ/web/default/tables.html deleted file mode 100644 index c6c362c11..000000000 --- a/src/CoiniumServ/web/default/tables.html +++ /dev/null @@ -1,457 +0,0 @@ - - - - - - - - - Tables - SB Admin - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Tables Sort Your Data

    - -
    - - We're using Tablesorter 2.0 for the sort function on the tables. Read the documentation for more customization options or feel free to use something else! -
    -
    -
    - -
    -
    -

    Bordered Table

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Page Visits % New Visits Revenue
    /index.html126532.3%$321.33
    /about.html26133.3%$234.12
    /sales.html66521.3%$16.34
    /blog.html951689.3%$1644.43
    /404.html2334.3%$23.52
    /services.html42160.3%$724.32
    /blog/post.html123393.2%$126.34
    -
    -
    -
    -

    Bordered with Striped Rows

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Page Visits % New Visits Revenue
    /index.html126532.3%$321.33
    /about.html26133.3%$234.12
    /sales.html66521.3%$16.34
    /blog.html951689.3%$1644.43
    /404.html2334.3%$23.52
    /services.html42160.3%$724.32
    /blog/post.html123393.2%$126.34
    -
    -
    -
    - -
    -
    -

    Basic Table

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Page Visits % New Visits Revenue
    /index.html126532.3%$321.33
    /about.html26133.3%$234.12
    /sales.html66521.3%$16.34
    /blog.html951689.3%$1644.43
    /404.html2334.3%$23.52
    /services.html42160.3%$724.32
    /blog/post.html123393.2%$126.34
    -
    -
    -
    -

    Striped Rows

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Page Visits % New Visits Revenue
    /index.html126532.3%$321.33
    /about.html26133.3%$234.12
    /sales.html66521.3%$16.34
    /blog.html951689.3%$1644.43
    /404.html2334.3%$23.52
    /services.html42160.3%$724.32
    /blog/post.html123393.2%$126.34
    -
    -
    -
    - -
    -
    -

    Contextual Classes

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Page Visits % New Visits Revenue
    /index.html126532.3%$321.33
    /about.html26133.3%$234.12
    /sales.html66521.3%$16.34
    /blog.html951689.3%$1644.43
    /404.html2334.3%$23.52
    /services.html42160.3%$724.32
    /blog/post.html123393.2%$126.34
    -
    -
    -
    -

    Bootstrap Docs

    -

    For complete documentation, please visit Bootstrap's Tables Documentation.

    -
    -
    - -
    - -
    - - - - - - - - - - - \ No newline at end of file diff --git a/src/CoiniumServ/web/default/typography.html b/src/CoiniumServ/web/default/typography.html deleted file mode 100644 index 9e80d89de..000000000 --- a/src/CoiniumServ/web/default/typography.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - Typography - SB Admin - - - - - - - - - - - -
    - - - - -
    - -
    -
    -

    Typograhy Text and Headers

    - -
    - - Visit Bootstrap's Typography Documentation for more information. -
    -
    -
    -

    Heading 1 Sub-heading

    -

    Heading 2 Sub-heading

    -

    Heading 3 Sub-heading

    -

    Heading 4 Sub-heading

    -
    Heading 5 Sub-heading
    -
    Heading 6 Sub-heading
    -
    -
    -

    Example Body Copy Text

    -

    This is an example of lead body copy.

    -

    This is an example of standard paragraph text. This is an example of link anchor text within body copy.

    -

    This is an example of small, fine print text.

    -

    This is an example of strong, bold text.

    -

    This is an example of emphasized, italic text.

    -

    Alignment Classes

    -

    Left aligned text.

    -

    Center aligned text.

    -

    Right aligned text.

    -
    -
    -

    Emphasis Classes

    -

    This is an example of muted text.

    -

    This is an example of primary text.

    -

    This is an example of success text.

    -

    This is an example of info text.

    -

    This is an example of warning text.

    -

    This is an example of danger text.

    -
    -
    - -
    -
    -

    Abbreviations

    -

    The abbreviation of the word attribute is attr.

    -

    HTML is an abbreviation for a programming language.

    -

    Addresses

    -
    - Twitter, Inc.
    - 795 Folsom Ave, Suite 600
    - San Francisco, CA 94107
    - P: (123) 456-7890 -
    - -
    - Full Name
    - first.last@example.com -
    -
    -
    -

    Blockquotes

    -

    Default Blockquote

    -
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

    -
    -

    Blockquote with Citation

    -
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

    - Someone famous in Source Title -
    -

    Right Aligned Blockquote

    -
    -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

    -
    -
    -
    -

    Lists

    -

    Unordered List

    -
      -
    • List Item
    • -
    • List Item
    • -
        -
      • List Item
      • -
      • List Item
      • -
      • List Item
      • -
      -
    • List Item
    • -
    -

    Ordered List

    -
      -
    1. List Item
    2. -
    3. List Item
    4. -
    5. List Item
    6. -
    -

    Unstyled List

    -
      -
    • List Item
    • -
    • List Item
    • -
    • List Item
    • -
    -

    Inline List

    -
      -
    • List Item
    • -
    • List Item
    • -
    • List Item
    • -
    -
    -
    - -
    -
    -

    Descriptions

    -
    -
    Standard Description List
    -
    Description Text
    -
    Description List Title
    -
    Description List Text
    -
    -
    -
    Horizontal Description List
    -
    Description Text
    -
    Description List Title
    -
    Description List Text
    -
    -
    -
    -

    Code

    -

    This is an example of an inline code element within body copy. Wrap inline code within a <code>...</code> tag.

    -
    This is an example of preformatted text.
    -
    -
    -

    Bootstrap Docs

    -

    For complete documentation, please visit Bootstrap's Typograhpy Documentation.

    -
    -
    - -
    - -
    - - - - - - - \ No newline at end of file From ef8a927eee9d6602066ded2aa9f448574102a545 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 15:26:06 +0300 Subject: [PATCH 129/230] Added version codenames :) --- src/CoiniumServ/Program.cs | 3 ++- src/CoiniumServ/Properties/AssemblyInfo.cs | 10 ++++++---- src/CoiniumServ/Utils/Versions/VersionInfo.cs | 7 ++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 478fc6f64..a8462bba3 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -30,6 +30,7 @@ using CoiniumServ.Utils; using CoiniumServ.Utils.Commands; using CoiniumServ.Utils.Platform; +using CoiniumServ.Utils.Versions; using Nancy.TinyIoc; using Serilog; @@ -80,7 +81,7 @@ static void Main(string[] args) // print a version banner. _logger = Log.ForContext(); - _logger.Information("CoiniumServ {0:l} warming-up..", Assembly.GetAssembly(typeof(Program)).GetName().Version); + _logger.Information("CoiniumServ {0} {1:l} warming-up..", VersionInfo.CodeName, Assembly.GetAssembly(typeof(Program)).GetName().Version); PlatformManager.PrintPlatformBanner(); // initialize config manager. diff --git a/src/CoiniumServ/Properties/AssemblyInfo.cs b/src/CoiniumServ/Properties/AssemblyInfo.cs index e3b2200f8..0b86197fe 100644 --- a/src/CoiniumServ/Properties/AssemblyInfo.cs +++ b/src/CoiniumServ/Properties/AssemblyInfo.cs @@ -29,15 +29,17 @@ using CoiniumServ.Utils.Versions; [assembly: AssemblyTitle("CoiniumServ")] -[assembly: AssemblyDescription("Crypto currency pool software")] +[assembly: AssemblyDescription("Next-gen crypto currency mining pool software")] + #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else [assembly: AssemblyConfiguration("Release")] #endif - [assembly: AssemblyCompany("Coinium.org")] - [assembly: AssemblyProduct("CoiniumServ")] -[assembly: AssemblyCopyright("Copyright (C) 2013 - 2014, coinium project, http://www.coinium.org")] + +[assembly: AssemblyCompany("Coinium.org")] +[assembly: AssemblyProduct("CoiniumServ")] +[assembly: AssemblyCopyright("Copyright (C) 2013 - 2014, Coinium project, http://www.coinium.org - http://www.coiniumserv.com")] [assembly: AssemblyTrademark("CoiniumServ")] [assembly: AssemblyCulture("")] diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index a0de731ba..e8a8c90bd 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -28,13 +28,18 @@ namespace CoiniumServ.Utils.Versions /// Put anything related to versions here. public static class VersionInfo { + /// + /// Codename. + /// + public const string CodeName = "Medivh"; + /// /// Main assembly versions info. /// public static class Assembly { /// - /// Main assemblies version. + /// Main assemby version. /// public const string Version = "0.1.0.*"; } From d141b05653e9288a35faf5555ac3a05f301e9b6d Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 15:40:21 +0300 Subject: [PATCH 130/230] okay got a better codename :) --- src/CoiniumServ/Properties/AssemblyInfo.cs | 11 +++++------ src/CoiniumServ/Utils/Versions/VersionInfo.cs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/CoiniumServ/Properties/AssemblyInfo.cs b/src/CoiniumServ/Properties/AssemblyInfo.cs index 0b86197fe..e00cc1e27 100644 --- a/src/CoiniumServ/Properties/AssemblyInfo.cs +++ b/src/CoiniumServ/Properties/AssemblyInfo.cs @@ -30,6 +30,11 @@ [assembly: AssemblyTitle("CoiniumServ")] [assembly: AssemblyDescription("Next-gen crypto currency mining pool software")] +[assembly: AssemblyCompany("Coinium.org")] +[assembly: AssemblyProduct("CoiniumServ - " + VersionInfo.CodeName)] +[assembly: AssemblyCopyright("Copyright (C) 2013 - 2014, CoiniumServ project, http://www.coinium.org - http://www.coiniumserv.com")] +[assembly: AssemblyTrademark("CoiniumServ")] +[assembly: AssemblyCulture("")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] @@ -37,12 +42,6 @@ [assembly: AssemblyConfiguration("Release")] #endif -[assembly: AssemblyCompany("Coinium.org")] -[assembly: AssemblyProduct("CoiniumServ")] -[assembly: AssemblyCopyright("Copyright (C) 2013 - 2014, Coinium project, http://www.coinium.org - http://www.coiniumserv.com")] -[assembly: AssemblyTrademark("CoiniumServ")] -[assembly: AssemblyCulture("")] - // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. diff --git a/src/CoiniumServ/Utils/Versions/VersionInfo.cs b/src/CoiniumServ/Utils/Versions/VersionInfo.cs index e8a8c90bd..864203d31 100644 --- a/src/CoiniumServ/Utils/Versions/VersionInfo.cs +++ b/src/CoiniumServ/Utils/Versions/VersionInfo.cs @@ -31,7 +31,7 @@ public static class VersionInfo /// /// Codename. /// - public const string CodeName = "Medivh"; + public const string CodeName = "Piri Reis"; /// /// Main assembly versions info. From 8ab54451112856a2ab0ef0000177ca36ce68ae06 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Wed, 23 Jul 2014 16:00:40 +0300 Subject: [PATCH 131/230] moved donors section to front. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3f5f1002f..376d41b19 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,12 @@ You can contribute the development of the project by donating; * DOGE: `DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr` * RDD: `Rb9kcLs96VDHTmiXVjcWC2RBsfCJ73UQyr` +###### Donors + +Here is a list of our generous donors that keep the project ongoing; + +* [reddapi.com](https://www.reddapi.com) + ###### Bounties BountySource integration available over [here](https://www.bountysource.com/trackers/401667-coiniumserv). You can set bounties and solve them. @@ -131,12 +137,6 @@ Start reading by these; * [Developer's Guide](https://github.com/CoiniumServ/CoiniumServ/wiki/Developer's-Guide) * [Technical Documentation](https://github.com/CoiniumServ/CoiniumServ/wiki/Technical-Documentation) -###### Donors - -Here is a list of our generous donors that keep the project ongoing; - -* [reddapi.com](https://www.reddapi.com) - ### License Copyright (C) 2013 - 2014, CoiniumServ Project - http://www.coinium.org - From 125b671b9d8a51a871054906afe06f60cb4bc4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 23 Jul 2014 16:29:57 +0300 Subject: [PATCH 132/230] Create commercial.md --- licenses/commercial.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 licenses/commercial.md diff --git a/licenses/commercial.md b/licenses/commercial.md new file mode 100644 index 000000000..1b98f181b --- /dev/null +++ b/licenses/commercial.md @@ -0,0 +1,3 @@ +You have to acquire a commercial license in order to be able to use this project commercially (ie selling hosted solutions) or while-label it. + +Please contact us over [http://blog.coinium.org/contact/](http://blog.coinium.org/contact/) for more details. From 95cae287eb8049300a649f68354767fe29a1ed72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Wed, 23 Jul 2014 16:30:26 +0300 Subject: [PATCH 133/230] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 376d41b19..2ca2c42c4 100644 --- a/README.md +++ b/README.md @@ -155,5 +155,5 @@ GNU General Public License for more details. For the terms of this license, see [licenses/gpl_v3.txt](https://github.com/CoiniumServ/CoiniumServ/blob/develop/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](https://github.com/CoiniumServ/CoiniumServ/blob/develop/licenses/commercial.txt). +license or white-label it as set out in [licenses/commercial.md](https://github.com/CoiniumServ/CoiniumServ/blob/develop/licenses/commercial.md). From fc9ccbaeb8f42aaf1657c2f9dda3544da2de3002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Thu, 24 Jul 2014 02:18:02 +0300 Subject: [PATCH 134/230] Added IStatisticsConfig. Closes #279. --- src/CoiniumServ/CoiniumServ.csproj | 6 +- .../Configuration/ConfigManager.cs | 4 +- .../Server/Web/IWebServerConfig.cs | 3 + src/CoiniumServ/Server/Web/WebServerConfig.cs | 3 + .../Statistics/IStatisticsConfig.cs | 40 +++++++++++++ .../Statistics/StatisticsConfig.cs | 56 +++++++++++++++++++ src/CoiniumServ/config/config-example.json | 9 ++- ...led-example.json => advanced-example.json} | 0 8 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 src/CoiniumServ/Statistics/IStatisticsConfig.cs create mode 100644 src/CoiniumServ/Statistics/StatisticsConfig.cs rename src/CoiniumServ/config/pools/{detailed-example.json => advanced-example.json} (100%) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index c6d5248bd..fa945acb5 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -144,6 +144,7 @@ + @@ -166,6 +167,7 @@ + @@ -792,10 +794,10 @@ PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index 066e2ac59..9bd5a1155 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -64,7 +64,9 @@ public ConfigManager(IConfigFactory configFactory) _coinConfigs = new Dictionary(); LogConfig = new LogConfig(_globalConfigData.logging); - WebServerConfig = new WebServerConfig(_globalConfigData.website); + WebServerConfig = new WebServerConfig(_globalConfigData.website); + + // TODO: implement metrics config. } public void Initialize() diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index c4734b146..7cba75213 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -23,6 +23,7 @@ using System; using CoiniumServ.Configuration; +using CoiniumServ.Statistics; namespace CoiniumServ.Server.Web { @@ -39,5 +40,7 @@ public interface IWebServerConfig:IConfig /// port to listen for http connections. /// Int32 Port { get; } + + IStatisticsConfig Statistics { get; } } } diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index 90c1f91e2..66748dfa9 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -22,6 +22,7 @@ #endregion using System; +using CoiniumServ.Statistics; using Serilog; namespace CoiniumServ.Server.Web @@ -31,6 +32,7 @@ public class WebServerConfig : IWebServerConfig public bool Enabled { get; private set; } public string BindInterface { get; private set; } public int Port { get; private set; } + public IStatisticsConfig Statistics { get; private set; } public bool Valid { get; private set; } public WebServerConfig(dynamic config) { @@ -44,6 +46,7 @@ public WebServerConfig(dynamic config) Enabled = config.enabled; BindInterface = config.bind; Port = config.port; + Statistics = new StatisticsConfig(config.stats); Valid = true; } diff --git a/src/CoiniumServ/Statistics/IStatisticsConfig.cs b/src/CoiniumServ/Statistics/IStatisticsConfig.cs new file mode 100644 index 000000000..9837338a1 --- /dev/null +++ b/src/CoiniumServ/Statistics/IStatisticsConfig.cs @@ -0,0 +1,40 @@ +#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 CoiniumServ.Configuration; + +namespace CoiniumServ.Statistics +{ + public interface IStatisticsConfig:IConfig + { + /// + /// interval for recaching statistics. + /// + int UpdateInterval { get; } + + /// + /// how many seconds worth of shares should be gathered to generate hashrate. + /// + int HashrateWindow { get; } + } +} diff --git a/src/CoiniumServ/Statistics/StatisticsConfig.cs b/src/CoiniumServ/Statistics/StatisticsConfig.cs new file mode 100644 index 000000000..a8f53b934 --- /dev/null +++ b/src/CoiniumServ/Statistics/StatisticsConfig.cs @@ -0,0 +1,56 @@ +#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 Serilog; + +namespace CoiniumServ.Statistics +{ + public class StatisticsConfig:IStatisticsConfig + { + public bool Valid { get; private set; } + public int UpdateInterval { get; private set; } + public int HashrateWindow { get; private set; } + + public StatisticsConfig(dynamic config) + { + try + { + // set the defaults; + UpdateInterval = 60; + HashrateWindow = 300; + + // load the config data. + UpdateInterval = config.updateInterval; + HashrateWindow = config.hashrateWindow; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading website statistics configuration"); + } + } + } +} diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index daf92bac9..0c60f2690 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -6,12 +6,19 @@ # enabled: set this true to enable frontend. # bind: interface to bind webserver. # port: port to listen for http connections. + # stats: + # updateInterval: interval for recaching statistics. + # hashrateWindow: how many seconds worth of shares should be gathered to generate hashrate. # website configuration "website": { "enabled": true, "bind": "127.0.0.1", - "port": 80 + "port": 80, + "stats": { + "updateInterval": 60, + "hashrateWindow": 300 + } }, # ------------------------------- diff --git a/src/CoiniumServ/config/pools/detailed-example.json b/src/CoiniumServ/config/pools/advanced-example.json similarity index 100% rename from src/CoiniumServ/config/pools/detailed-example.json rename to src/CoiniumServ/config/pools/advanced-example.json From 1863965c02d5f292a6cf7c092aa1f2575a0e000f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Thu, 24 Jul 2014 02:19:05 +0300 Subject: [PATCH 135/230] Tiny update for last commit. --- src/CoiniumServ/CoiniumServ.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index fa945acb5..ecf31ffea 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -797,7 +797,7 @@ PreserveNewest - + PreserveNewest From 47acb2f66a3d8e1f8968d1c8ae098c9a7a9a02ce Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 24 Jul 2014 14:03:59 +0300 Subject: [PATCH 136/230] All pool related object now take a IPoolConfig as parameter so that we are consistent in parameter usage. Closes #278. Fixed a bug in jobmanager when daemon was not connected to coin network, job-manager would only try to create a job only once - it should continously pool daemon now. --- src/CoiniumServ/Banning/BanManager.cs | 7 +-- src/CoiniumServ/Daemon/DaemonBase.cs | 12 +++-- src/CoiniumServ/Daemon/DaemonClient.cs | 6 +-- src/CoiniumServ/Factories/IObjectFactory.cs | 25 ++++----- src/CoiniumServ/Factories/ObjectFactory.cs | 54 ++++++++----------- src/CoiniumServ/Jobs/Manager/JobManager.cs | 48 +++++++++-------- src/CoiniumServ/Jobs/Tracker/JobTracker.cs | 2 + src/CoiniumServ/Miners/MinerManager.cs | 5 +- src/CoiniumServ/Payments/PaymentProcessor.cs | 7 +-- src/CoiniumServ/Pools/Pool.cs | 23 ++++---- .../Mining/Stratum/Service/StratumService.cs | 6 +-- .../Server/Mining/Stratum/StratumServer.cs | 8 +-- .../Mining/Vanilla/Service/VanillaService.cs | 6 ++- .../Server/Mining/Vanilla/VanillaServer.cs | 6 +-- src/CoiniumServ/Shares/ShareManager.cs | 7 +-- src/CoiniumServ/Vardiff/VardiffManager.cs | 17 +++--- src/Tests/Pools/PoolTests.cs | 2 +- 17 files changed, 120 insertions(+), 121 deletions(-) diff --git a/src/CoiniumServ/Banning/BanManager.cs b/src/CoiniumServ/Banning/BanManager.cs index f44a821bb..52be751df 100644 --- a/src/CoiniumServ/Banning/BanManager.cs +++ b/src/CoiniumServ/Banning/BanManager.cs @@ -28,6 +28,7 @@ using System.Threading; using CoiniumServ.Miners; using CoiniumServ.Networking.Server.Sockets; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Vanilla; using CoiniumServ.Shares; using CoiniumServ.Utils.Helpers.Time; @@ -45,14 +46,14 @@ public class BanManager:IBanManager private readonly ILogger _logger; - public BanManager(string pool, IShareManager shareManager, IBanConfig banConfig) + public BanManager(IPoolConfig poolConfig, IShareManager shareManager) { - Config = banConfig; + Config = poolConfig.Banning; if (!Config.Enabled) return; - _logger = Log.ForContext().ForContext("Component", pool); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); _bannedIps = new Dictionary(); _timer = new Timer(CheckBans, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index f0f333820..524345d9f 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -29,6 +29,8 @@ using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Factories; using CoiniumServ.Logging; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Utils.Extensions; using Newtonsoft.Json; using Serilog; @@ -44,13 +46,13 @@ public class DaemonBase : IDaemonBase private readonly ILogger _logger; - public DaemonBase(string pool, IDaemonConfig daemonConfig) + public DaemonBase(IPoolConfig poolConfig) { - RpcUrl = string.Format("http://{0}:{1}", daemonConfig.Host, daemonConfig.Port); - RpcUser = daemonConfig.Username; - RpcPassword = daemonConfig.Password; + RpcUrl = string.Format("http://{0}:{1}", poolConfig.Daemon.Host, poolConfig.Daemon.Port); + RpcUser = poolConfig.Daemon.Username; + RpcPassword = poolConfig.Daemon.Password; RequestCounter = 0; - _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool); + _logger = LogManager.PacketLogger.ForContext().ForContext("Component", poolConfig.Coin.Name); } /// diff --git a/src/CoiniumServ/Daemon/DaemonClient.cs b/src/CoiniumServ/Daemon/DaemonClient.cs index 4e7f3c04f..0392a34aa 100644 --- a/src/CoiniumServ/Daemon/DaemonClient.cs +++ b/src/CoiniumServ/Daemon/DaemonClient.cs @@ -27,7 +27,6 @@ using CoiniumServ.Daemon.Config; using CoiniumServ.Daemon.Requests; using CoiniumServ.Daemon.Responses; - /* This file is based on https://github.com/BitKoot/BitcoinRpcSharp */ /* Possible alternative implementations: @@ -39,6 +38,7 @@ // Original bitcoin api call list: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list // Rpc error codes: https://github.com/bitcoin/bitcoin/blob/master/src/rpcprotocol.h#L34 +using CoiniumServ.Pools.Config; namespace CoiniumServ.Daemon { @@ -49,8 +49,8 @@ public class DaemonClient : DaemonBase, IDaemonClient { public static readonly object[] EmptyString = {}; // used as empty parameter. - public DaemonClient(string pool, IDaemonConfig daemonConfig) - : base(pool, daemonConfig) + public DaemonClient(IPoolConfig poolConfig) + : base(poolConfig) { } /// diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index cce97f862..c3d720e1f 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -69,26 +69,23 @@ public interface IObjectFactory /// /// Returns a new instance of daemon client. /// - /// - /// /// - IDaemonClient GetDaemonClient(string pool, IDaemonConfig daemonConfig); + IDaemonClient GetDaemonClient(IPoolConfig poolConfig); - IMinerManager GetMiningManager(string pool, IDaemonClient daemonClient); + IMinerManager GetMinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient); - IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, - IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, - IRewardsConfig rewardsConfig); + IJobManager GetJobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm); IJobTracker GetJobTracker(); - IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage); + IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage); - IPaymentProcessor GetPaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage, IWalletConfig walletConfig); + IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage); - IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig); + IBanManager GetBanManager(IPoolConfig poolConfig, IShareManager shareManager); - IVardiffManager GetVardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig); + IVardiffManager GetVardiffManager(IPoolConfig poolConfig, IShareManager shareManager); #endregion @@ -112,10 +109,10 @@ IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker j #region server & service objects - IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManager, IJobManager jobManager, - IBanManager banManager, ICoinConfig coinConfig); + IMiningServer GetMiningServer(string type, IPoolConfig poolConfig, IPool pool, IMinerManager minerManager, IJobManager jobManager, + IBanManager banManager); - IRpcService GetMiningService(string type, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient); + IRpcService GetMiningService(string type, IPoolConfig poolConfig, IShareManager shareManager, IDaemonClient daemonClient); IWebServer GetWebServer(); diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index 48d37b0df..e2112f812 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -25,7 +25,6 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; -using CoiniumServ.Daemon.Config; using CoiniumServ.Jobs.Manager; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Logging; @@ -103,44 +102,39 @@ public IPool GetPool(IPoolConfig poolConfig) /// /// Returns a new instance of daemon client. /// - /// - /// /// - public IDaemonClient GetDaemonClient(string pool, IDaemonConfig daemonConfig) + public IDaemonClient GetDaemonClient(IPoolConfig poolConfig) { var @params = new NamedParameterOverloads { - {"pool", pool}, - {"daemonConfig", daemonConfig}, + {"poolConfig", poolConfig} }; return _applicationContext.Container.Resolve(@params); } - public IMinerManager GetMiningManager(string pool, IDaemonClient daemonClient) + public IMinerManager GetMinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) { var @params = new NamedParameterOverloads { - {"pool", pool}, + {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, }; return _applicationContext.Container.Resolve(@params); } - public IJobManager GetJobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, - IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, IRewardsConfig rewardsConfig) + public IJobManager GetJobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm) { var @params = new NamedParameterOverloads { - {"pool", pool}, + {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, {"jobTracker", jobTracker}, {"shareManager", shareManager}, {"minerManager", minerManager}, {"hashAlgorithm", hashAlgorithm}, - {"walletConfig", walletConfig}, - {"rewardsConfig", rewardsConfig}, }; return _applicationContext.Container.Resolve(@params); @@ -151,11 +145,11 @@ public IJobTracker GetJobTracker() return _applicationContext.Container.Resolve(); } - public IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) + public IShareManager GetShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) { var @params = new NamedParameterOverloads { - {"pool", pool}, + {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, {"jobTracker", jobTracker}, {"storage", storage}, @@ -164,39 +158,35 @@ public IShareManager GetShareManager(string pool, IDaemonClient daemonClient, IJ return _applicationContext.Container.Resolve(@params); } - public IPaymentProcessor GetPaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage, - IWalletConfig walletConfig) + public IPaymentProcessor GetPaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage) { var @params = new NamedParameterOverloads { - {"pool", pool}, + {"poolConfig", poolConfig}, {"daemonClient", daemonClient}, - {"storage", storage}, - {"walletConfig", walletConfig}, + {"storage", storage}, }; return _applicationContext.Container.Resolve(@params); } - public IBanManager GetBanManager(string pool, IShareManager shareManager, IBanConfig banConfig) + public IBanManager GetBanManager(IPoolConfig poolConfig, IShareManager shareManager) { var @params = new NamedParameterOverloads { - {"pool", pool}, - {"shareManager", shareManager}, - {"banConfig", banConfig}, + {"poolConfig", poolConfig}, + {"shareManager", shareManager}, }; return _applicationContext.Container.Resolve(@params); } - public IVardiffManager GetVardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig) + public IVardiffManager GetVardiffManager(IPoolConfig poolConfig, IShareManager shareManager) { var @params = new NamedParameterOverloads { - {"pool", pool}, + {"poolConfig", poolConfig}, {"shareManager", shareManager}, - {"vardiffConfig", vardiffConfig}, }; return _applicationContext.Container.Resolve(@params); @@ -266,26 +256,26 @@ public IBlocks GetBlockStats(ILatestBlocks latestBlocks, IStorage storage) #region server & service objects - public IMiningServer GetMiningServer(string type, IPool pool, IMinerManager minerManager, IJobManager jobManager, - IBanManager banManager, ICoinConfig coinConfig) + public IMiningServer GetMiningServer(string type, IPoolConfig poolConfig, IPool pool, IMinerManager minerManager, IJobManager jobManager, + IBanManager banManager) { var @params = new NamedParameterOverloads { + {"poolConfig", poolConfig}, {"pool", pool}, {"minerManager", minerManager}, {"jobManager", jobManager}, {"banManager", banManager}, - {"coinConfig", coinConfig} }; return _applicationContext.Container.Resolve(type, @params); } - public IRpcService GetMiningService(string type, ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient) + public IRpcService GetMiningService(string type, IPoolConfig poolConfig, IShareManager shareManager, IDaemonClient daemonClient) { var @params = new NamedParameterOverloads { - {"coinConfig", coinConfig}, + {"poolConfig", poolConfig}, {"shareManager", shareManager}, {"daemonClient", daemonClient} }; diff --git a/src/CoiniumServ/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Jobs/Manager/JobManager.cs index 0cf7a5847..4e089d938 100644 --- a/src/CoiniumServ/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/JobManager.cs @@ -29,6 +29,7 @@ using CoiniumServ.Jobs.Tracker; using CoiniumServ.Miners; using CoiniumServ.Payments; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Vanilla; @@ -66,20 +67,19 @@ public class JobManager : IJobManager private Timer _timer; private const int TimerExpiration = 60; - public JobManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, - IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IWalletConfig walletConfig, - IRewardsConfig rewardsConfig) + public JobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, + IMinerManager minerManager, IHashAlgorithm hashAlgorithm) { _daemonClient = daemonClient; _jobTracker = jobTracker; _shareManager = shareManager; _minerManager = minerManager; _hashAlgorithm = hashAlgorithm; - _walletConfig = walletConfig; - _rewardsConfig = rewardsConfig; + _walletConfig = poolConfig.Wallet; + _rewardsConfig = poolConfig.Rewards; _jobCounter = new JobCounter(); // todo make this ioc based too. - _logger = Log.ForContext().ForContext("Component", pool); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } public void Initialize(UInt32 instanceId) @@ -102,30 +102,32 @@ private void IdleJobTimer(object state) BroadcastNewJob(true); } - private void BroadcastNewJob(bool initiatedByTimer) + private void OnMinerAuthenticated(object sender, EventArgs e) { - var job = GetNewJob(); // create a new job. - var count = Broadcast(job); // broadcast to miners. + var miner = ((MinerEventArgs)e).Miner; - if (job == null) + if (miner == null) return; - if (initiatedByTimer) - _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, TimerExpiration); - else - _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id, count); - - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); // reset the idle-block timer. + if(_jobTracker.Current != null) // if we have a valid job, + SendJobToMiner(miner, _jobTracker.Current); // send it to newly connected miner. } - private void OnMinerAuthenticated(object sender, EventArgs e) - { - var miner = ((MinerEventArgs) e).Miner; + private void BroadcastNewJob(bool initiatedByTimer) + { + var job = GetNewJob(); // create a new job. - if (miner == null) - return; + if (job != null) // if we were able to create a new job + { + var count = Broadcast(job); // broadcast to miners. - var result = SendJobToMiner(miner, _jobTracker.Current); + if (initiatedByTimer) + _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, TimerExpiration); + else + _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id, count); + } + + _timer.Change(TimerExpiration * 1000, Timeout.Infinite); // reset the idle-block timer. } private IJob GetNewJob() @@ -153,7 +155,7 @@ private IJob GetNewJob() } catch (RpcException rpcException) { - _logger.Error(rpcException, "New job creation failed:"); + _logger.Error("New job creation failed: {0:l}", rpcException.Message); return null; } catch (Exception e) diff --git a/src/CoiniumServ/Jobs/Tracker/JobTracker.cs b/src/CoiniumServ/Jobs/Tracker/JobTracker.cs index 940193414..0f6ad6dd3 100644 --- a/src/CoiniumServ/Jobs/Tracker/JobTracker.cs +++ b/src/CoiniumServ/Jobs/Tracker/JobTracker.cs @@ -48,5 +48,7 @@ public void Add(IJob job) _jobs.Add(job.Id, job); Current = job; } + + // TODO: remove expired jobs. } } diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 2a1c4673e..9e46b2e48 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -27,6 +27,7 @@ using CoiniumServ.Daemon; using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using Serilog; @@ -46,11 +47,11 @@ public class MinerManager : IMinerManager private readonly ILogger _logger; - public MinerManager(string pool, IDaemonClient daemonClient) + public MinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) { _daemonClient = daemonClient; _miners = new Dictionary(); - _logger = Log.ForContext().ForContext("Component", pool); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } public IMiner GetMiner(Int32 id) diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index dcb83d212..51b7222f4 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -30,6 +30,7 @@ using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Persistance; using CoiniumServ.Persistance.Blocks; +using CoiniumServ.Pools.Config; using Serilog; namespace CoiniumServ.Payments @@ -57,12 +58,12 @@ public class PaymentProcessor : IPaymentProcessor private readonly ILogger _logger; - public PaymentProcessor(string pool, IDaemonClient daemonClient, IStorage storage , IWalletConfig walletConfig) + public PaymentProcessor(IPoolConfig poolConfig, IDaemonClient daemonClient, IStorage storage ) { _daemonClient = daemonClient; _storage = storage; - _walletConfig = walletConfig; - _logger = Log.ForContext().ForContext("Component", pool); + _walletConfig = poolConfig.Wallet; + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } public void Initialize(IPaymentConfig config) diff --git a/src/CoiniumServ/Pools/Pool.cs b/src/CoiniumServ/Pools/Pool.cs index 079eaa878..ca7015d76 100644 --- a/src/CoiniumServ/Pools/Pool.cs +++ b/src/CoiniumServ/Pools/Pool.cs @@ -108,7 +108,7 @@ private void InitDaemon() if (Config.Daemon == null || Config.Daemon.Valid == false) _logger.Error("Coin daemon configuration is not valid!"); - _daemonClient = _objectFactory.GetDaemonClient(Config.Coin.Name, Config.Daemon); + _daemonClient = _objectFactory.GetDaemonClient(Config); } private void InitManagers() @@ -118,21 +118,20 @@ private void InitManagers() _storage = _objectFactory.GetStorage(Storages.Redis, Config); - _paymentProcessor = _objectFactory.GetPaymentProcessor(Config.Coin.Name, _daemonClient, _storage, Config.Wallet); + _paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, _storage); _paymentProcessor.Initialize(Config.Payments); - _minerManager = _objectFactory.GetMiningManager(Config.Coin.Name, _daemonClient); + _minerManager = _objectFactory.GetMinerManager(Config, _daemonClient); _jobTracker = _objectFactory.GetJobTracker(); - _shareManager = _objectFactory.GetShareManager(Config.Coin.Name, _daemonClient, _jobTracker, _storage); + _shareManager = _objectFactory.GetShareManager(Config, _daemonClient, _jobTracker, _storage); - _vardiffManager = _objectFactory.GetVardiffManager(Config.Coin.Name, _shareManager, Config.Stratum.Vardiff); + _vardiffManager = _objectFactory.GetVardiffManager(Config, _shareManager); - _banningManager = _objectFactory.GetBanManager(Config.Coin.Name, _shareManager, Config.Banning); + _banningManager = _objectFactory.GetBanManager(Config, _shareManager); - _jobManager = _objectFactory.GetJobManager(Config.Coin.Name, _daemonClient, _jobTracker, _shareManager, _minerManager, - _hashAlgorithm, Config.Wallet, Config.Rewards); + _jobManager = _objectFactory.GetJobManager(Config, _daemonClient, _jobTracker, _shareManager, _minerManager,_hashAlgorithm); _jobManager.Initialize(InstanceId); @@ -150,8 +149,8 @@ private void InitServers() if (Config.Stratum != null && Config.Stratum.Enabled) { - var stratumServer = _objectFactory.GetMiningServer("Stratum", this, _minerManager, _jobManager, _banningManager, Config.Coin); - var stratumService = _objectFactory.GetMiningService("Stratum", Config.Coin, _shareManager, _daemonClient); + var stratumServer = _objectFactory.GetMiningServer("Stratum", Config, this, _minerManager, _jobManager, _banningManager); + var stratumService = _objectFactory.GetMiningService("Stratum", Config, _shareManager, _daemonClient); stratumServer.Initialize(Config.Stratum); _servers.Add(stratumServer, stratumService); @@ -159,8 +158,8 @@ private void InitServers() if (Config.Vanilla != null && Config.Vanilla.Enabled) { - var vanillaServer = _objectFactory.GetMiningServer("Vanilla", this, _minerManager, _jobManager, _banningManager, Config.Coin); - var vanillaService = _objectFactory.GetMiningService("Vanilla", Config.Coin, _shareManager, _daemonClient); + var vanillaServer = _objectFactory.GetMiningServer("Vanilla", Config, this, _minerManager, _jobManager, _banningManager); + var vanillaService = _objectFactory.GetMiningService("Vanilla", Config, _shareManager, _daemonClient); vanillaServer.Initialize(Config.Vanilla); diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index cb3c8eb5a..69ae4c1e2 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -22,8 +22,8 @@ #endregion using AustinHarris.JsonRpc; -using CoiniumServ.Coin.Config; using CoiniumServ.Jobs; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Server.Mining.Stratum.Responses; using CoiniumServ.Shares; @@ -37,8 +37,8 @@ public class StratumService : JsonRpcService, IRpcService { private readonly IShareManager _shareManager; - public StratumService(ICoinConfig coinConfig, IShareManager shareManager): - base(coinConfig.Name) + public StratumService(IPoolConfig poolConfig, IShareManager shareManager): + base(poolConfig.Coin.Name) { _shareManager = shareManager; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs index 977f3f39d..fc6912b99 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumServer.cs @@ -25,11 +25,11 @@ using System.Net; using System.Net.Sockets; using CoiniumServ.Banning; -using CoiniumServ.Coin.Config; using CoiniumServ.Jobs.Manager; using CoiniumServ.Miners; using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using Serilog; // stratum server uses json-rpc 2.0 (over raw sockets) & json-rpc.net (http://jsonrpc2.codeplex.com/) @@ -61,14 +61,14 @@ public class StratumServer : SocketServer, IMiningServer /// The miner manager. /// /// - /// - public StratumServer(IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager, ICoinConfig coinConfig) + /// + public StratumServer(IPoolConfig poolConfig, IPool pool, IMinerManager minerManager, IJobManager jobManager, IBanManager banManager) { _pool = pool; _minerManager = minerManager; _jobManager = jobManager; _banManager = banManager; - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } /// diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs index 5bfa6f36f..9348deba4 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Service/VanillaService.cs @@ -25,6 +25,8 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Daemon; using CoiniumServ.Daemon.Responses; +using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Service; using CoiniumServ.Shares; using Serilog; @@ -40,8 +42,8 @@ public class VanillaService : JsonRpcService, IRpcService private readonly IShareManager _shareManager; - public VanillaService(ICoinConfig coinConfig, IShareManager shareManager, IDaemonClient daemonClient): - base(coinConfig.Name) + public VanillaService(IPoolConfig poolConfig, IShareManager shareManager, IDaemonClient daemonClient): + base(poolConfig.Coin.Name) { _daemonClient = daemonClient; _shareManager = shareManager; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs index 9c371d048..677960992 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaServer.cs @@ -24,11 +24,11 @@ using System.Net; // classic server uses json-rpc 1.0 (over http) & json-rpc.net (http://jsonrpc2.codeplex.com/) -using CoiniumServ.Coin.Config; using CoiniumServ.Jobs.Manager; using CoiniumServ.Miners; using CoiniumServ.Networking.Server.Http.Basic; using CoiniumServ.Pools; +using CoiniumServ.Pools.Config; using Serilog; namespace CoiniumServ.Server.Mining.Vanilla @@ -45,12 +45,12 @@ public class VanillaServer : HttpServer, IMiningServer private readonly ILogger _logger; - public VanillaServer(IPool pool, IMinerManager minerManager, IJobManager jobManager, ICoinConfig coinConfig) + public VanillaServer(IPoolConfig poolConfig, IPool pool, IMinerManager minerManager, IJobManager jobManager) { _pool = pool; _minerManager = minerManager; _jobManager = jobManager; - _logger = Log.ForContext().ForContext("Component", coinConfig.Name); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } public void Initialize(IServerConfig config) diff --git a/src/CoiniumServ/Shares/ShareManager.cs b/src/CoiniumServ/Shares/ShareManager.cs index c52d4bb41..84bc6f7e6 100644 --- a/src/CoiniumServ/Shares/ShareManager.cs +++ b/src/CoiniumServ/Shares/ShareManager.cs @@ -26,6 +26,7 @@ using CoiniumServ.Daemon; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Persistance; +using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Stratum.Errors; using CoiniumServ.Server.Mining.Vanilla; @@ -51,16 +52,16 @@ public class ShareManager : IShareManager /// /// Initializes a new instance of the class. /// - /// + /// /// /// /// - public ShareManager(string pool, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) + public ShareManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IStorage storage) { _daemonClient = daemonClient; _jobTracker = jobTracker; _storage = storage; - _logger = Log.ForContext().ForContext("Component", pool); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } /// diff --git a/src/CoiniumServ/Vardiff/VardiffManager.cs b/src/CoiniumServ/Vardiff/VardiffManager.cs index 049f14ed1..a0804bc9d 100644 --- a/src/CoiniumServ/Vardiff/VardiffManager.cs +++ b/src/CoiniumServ/Vardiff/VardiffManager.cs @@ -22,6 +22,7 @@ #endregion using System; +using CoiniumServ.Pools.Config; using CoiniumServ.Shares; using CoiniumServ.Utils.Buffers; using CoiniumServ.Utils.Helpers.Time; @@ -38,21 +39,21 @@ public class VardiffManager:IVardiffManager private readonly float _tMax; private readonly ILogger _logger; - public VardiffManager(string pool, IShareManager shareManager, IVardiffConfig vardiffConfig) + public VardiffManager(IPoolConfig poolConfig, IShareManager shareManager) { - _logger = Log.ForContext().ForContext("Component", pool); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); - Config = vardiffConfig; + Config = poolConfig.Stratum.Vardiff; if (!Config.Enabled) return; shareManager.ShareSubmitted += OnShare; - - var variance = vardiffConfig.TargetTime*((float)vardiffConfig.VariancePercent/100); - _bufferSize = vardiffConfig.RetargetTime/vardiffConfig.TargetTime*4; - _tMin = vardiffConfig.TargetTime - variance; - _tMax = vardiffConfig.TargetTime + variance; + + var variance = Config.TargetTime * ((float)Config.VariancePercent / 100); + _bufferSize = Config.RetargetTime / Config.TargetTime * 4; + _tMin = Config.TargetTime - variance; + _tMax = Config.TargetTime + variance; } private void OnShare(object sender, EventArgs e) diff --git a/src/Tests/Pools/PoolTests.cs b/src/Tests/Pools/PoolTests.cs index bdfe7ad58..c8cb5ee39 100644 --- a/src/Tests/Pools/PoolTests.cs +++ b/src/Tests/Pools/PoolTests.cs @@ -53,7 +53,7 @@ public PoolTests() _config.Daemon.Valid.Returns(true); // daemon client mockup. - _daemonClient = _objectFactory.GetDaemonClient(_config.Coin.Name, _config.Daemon); + _daemonClient = _objectFactory.GetDaemonClient(_config); _daemonClient.GetInfo().Returns(new Info()); _daemonClient.GetMiningInfo().Returns(new MiningInfo()); } From af0f6aa8b383a36a7f18eef7fdacb55d10cfba26 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 24 Jul 2014 14:41:05 +0300 Subject: [PATCH 137/230] Fixed an outstanding bug in merging default.json and pool-config.jsons, where default.json values were never overrided by pool-config.json. Added exception handler to getmininginfo() call in Pool:PrintPoolInfo(). MinerManager will now honor the "miner:validateUsername" setting in config. --- .../Configuration/ConfigManager.cs | 2 +- src/CoiniumServ/Miners/IMinerConfig.cs | 1 + src/CoiniumServ/Miners/MinerManager.cs | 10 +++- src/CoiniumServ/Pools/Pool.cs | 59 ++++++++++--------- .../Server/Mining/Stratum/StratumMiner.cs | 1 - .../Transactions/GenerationTransaction.cs | 4 +- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index 9bd5a1155..e9b0abd0e 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -101,7 +101,7 @@ private void LoadPoolConfigs() var coinConfig = GetCoinConfig(coinName); if(_defaultPoolConfig != null) - data = JsonConfig.Merger.Merge(_defaultPoolConfig, data); // if we do have a default.json config, merge with it. + data = JsonConfig.Merger.Merge(data, _defaultPoolConfig); // if we do have a default.json config, merge with it. PoolConfigs.Add(_configFactory.GetPoolConfig(data, coinConfig)); } diff --git a/src/CoiniumServ/Miners/IMinerConfig.cs b/src/CoiniumServ/Miners/IMinerConfig.cs index d9dbe7a92..1603507fa 100644 --- a/src/CoiniumServ/Miners/IMinerConfig.cs +++ b/src/CoiniumServ/Miners/IMinerConfig.cs @@ -32,6 +32,7 @@ public interface IMinerConfig : IConfig /// bool ValidateUsername { get; } + // todo: need to utilize this! /// /// timeout in seconds to disconnect miners that did not submit any shares for the period. /// diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 9e46b2e48..787b939a7 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -43,12 +43,15 @@ public class MinerManager : IMinerManager private int _counter = 0; // counter for assigining unique id's to miners. + private readonly IMinerConfig _config; + private readonly IDaemonClient _daemonClient; private readonly ILogger _logger; public MinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) { + _config = poolConfig.Miner; _daemonClient = daemonClient; _miners = new Dictionary(); _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); @@ -98,10 +101,13 @@ public void Remove(IConnection connection) public void Authenticate(IMiner miner) { - miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; + if (_config.ValidateUsername) // should we validate miner username? + miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; // if so validate it against coin daemon as an address. + else + miner.Authenticated = true; // else just accept him. _logger.Information( - miner.Authenticated ? "Authenticated miner: {0:l} [{1:l}]" : "Unauthenticated miner: {0:l} [{1:l}]", + miner.Authenticated ? "Authenticated miner: {0:l} [{1:l}]" : "Miner authentication failed: {0:l} [{1:l}]", miner.Username, ((IClient) miner).Connection.RemoteEndPoint); if (!miner.Authenticated) diff --git a/src/CoiniumServ/Pools/Pool.cs b/src/CoiniumServ/Pools/Pool.cs index ca7015d76..f6fa23168 100644 --- a/src/CoiniumServ/Pools/Pool.cs +++ b/src/CoiniumServ/Pools/Pool.cs @@ -28,11 +28,10 @@ using CoiniumServ.Coin.Helpers; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Factories; using CoiniumServ.Jobs.Manager; -using CoiniumServ.Jobs.Tracker; using CoiniumServ.Miners; -using CoiniumServ.Payments; using CoiniumServ.Persistance; using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining; @@ -40,7 +39,6 @@ using CoiniumServ.Shares; using CoiniumServ.Statistics; using CoiniumServ.Utils.Helpers.Validation; -using CoiniumServ.Vardiff; using Serilog; namespace CoiniumServ.Pools @@ -54,17 +52,15 @@ public class Pool : IPool public IPerPool Statistics { get; private set; } + // object factory. private readonly IObjectFactory _objectFactory; + // dependent objects. private IDaemonClient _daemonClient; private IMinerManager _minerManager; - private IJobTracker _jobTracker; private IJobManager _jobManager; private IShareManager _shareManager; - private IStorage _storage; private IHashAlgorithm _hashAlgorithm; - private IPaymentProcessor _paymentProcessor; - private IVardiffManager _vardiffManager; private IBanManager _banningManager; private Dictionary _servers; @@ -116,28 +112,28 @@ private void InitManagers() // init the algorithm _hashAlgorithm = _objectFactory.GetHashAlgorithm(Config.Coin.Algorithm); - _storage = _objectFactory.GetStorage(Storages.Redis, Config); + var storage = _objectFactory.GetStorage(Storages.Redis, Config); - _paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, _storage); - _paymentProcessor.Initialize(Config.Payments); + var paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, storage); + paymentProcessor.Initialize(Config.Payments); _minerManager = _objectFactory.GetMinerManager(Config, _daemonClient); - _jobTracker = _objectFactory.GetJobTracker(); + var jobTracker = _objectFactory.GetJobTracker(); - _shareManager = _objectFactory.GetShareManager(Config, _daemonClient, _jobTracker, _storage); + _shareManager = _objectFactory.GetShareManager(Config, _daemonClient, jobTracker, storage); - _vardiffManager = _objectFactory.GetVardiffManager(Config, _shareManager); + var vardiffManager = _objectFactory.GetVardiffManager(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); - 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); } private void InitServers() @@ -170,16 +166,10 @@ private void InitServers() private void PrintPoolInfo() { var info = _daemonClient.GetInfo(); - var miningInfo = _daemonClient.GetMiningInfo(); - // TODO: add downloading blocks information from getblocktemplate(). - // TODO: somecoins like namecoin do not have the method getmininginfo(), so divide this information and handle exceptions. - // TODO: read services from config so that we can print pool info even before starting the servers. _logger.Information("Coin symbol: {0:l} algorithm: {1:l} " + "Coin version: {2} protocol: {3} wallet: {4} " + - "Daemon network: {5:l} peers: {6} blocks: {7} errors: {8:l} " + - "Network difficulty: {9:0.00000000} block difficulty: {10:0.00} " + - "Network hashrate: {11:l} ", + "Daemon network: {5:l} peers: {6} blocks: {7} errors: {8:l} ", Config.Coin.Symbol, Config.Coin.Algorithm, info.Version, @@ -187,11 +177,22 @@ private void PrintPoolInfo() info.WalletVersion, info.Testnet ? "testnet" : "mainnet", info.Connections, info.Blocks, - string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors, - miningInfo.Difficulty, - miningInfo.Difficulty * _hashAlgorithm.Multiplier, - miningInfo.NetworkHashps.GetReadableHashrate() - ); + string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors); + + try + { + // try reading mininginfo(), some coins may not support it. + var miningInfo = _daemonClient.GetMiningInfo(); + + _logger.Information("Network difficulty: {0:0.00000000} block difficulty: {1:0.00} Network hashrate: {2:l} ", + miningInfo.Difficulty, + miningInfo.Difficulty*_hashAlgorithm.Multiplier, + miningInfo.NetworkHashps.GetReadableHashrate()); + } + catch (RpcException e) + { + _logger.Error("Can not read mininginfo() as coin daemon doesn't support it"); + } } public void Start() diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 634504386..0def3a693 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -93,7 +93,6 @@ public class StratumMiner : IClient, IStratumMiner /// /// /// - /// public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool pool, IMinerManager minerManager) { Id = id; // the id of the miner. diff --git a/src/CoiniumServ/Transactions/GenerationTransaction.cs b/src/CoiniumServ/Transactions/GenerationTransaction.cs index 37b4fcb1d..52cadff9f 100644 --- a/src/CoiniumServ/Transactions/GenerationTransaction.cs +++ b/src/CoiniumServ/Transactions/GenerationTransaction.cs @@ -123,7 +123,9 @@ public UInt32 InputsCount /// public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, IBlockTemplate blockTemplate, IWalletConfig walletConfig, IRewardsConfig rewardsConfig, bool supportTxMessages = false) { - DaemonClient = daemonClient; + // TODO: we need a whole refactoring here. + // we should use DI and it shouldn't really require daemonClient connection to function. + BlockTemplate = blockTemplate; ExtraNonce = extraNonce; SupportTxMessages = supportTxMessages; From 43cd4bf589c39e87de138a325f34d9a076e141a0 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 24 Jul 2014 16:44:47 +0300 Subject: [PATCH 138/230] JobManager now polls block-daemon for new blocks as it should be doing so and honors values from jobConfig. Was a major bug :) Statistics.cs / PerPool.cs now honor website:stats parameters. Statistics.cs now has a last-update field that's honored by / page. Added a sample network configuration section config.js. --- .../Configuration/ConfigManager.cs | 2 +- src/CoiniumServ/Jobs/Manager/JobManager.cs | 62 ++++++++++++++----- src/CoiniumServ/Payments/PaymentProcessor.cs | 3 +- .../Mining/Stratum/Notifications/IJob.cs | 2 + .../Mining/Stratum/Notifications/Job.cs | 6 ++ src/CoiniumServ/Statistics/IStatistics.cs | 5 ++ src/CoiniumServ/Statistics/PerPool.cs | 11 ++-- src/CoiniumServ/Statistics/Statistics.cs | 33 ++++++++-- src/CoiniumServ/config/config-example.json | 11 +++- src/CoiniumServ/web/default/index.cshtml | 6 +- 10 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index e9b0abd0e..b985e8920 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -78,7 +78,7 @@ public void Initialize() private void LoadPoolConfigs() { - _logger.Verbose("Discovering enabled pool configs.."); + _logger.Debug("Discovering enabled pool configs.."); var files = FileHelpers.GetFilesByExtensionRecursive(PoolConfigRoot, ".json"); diff --git a/src/CoiniumServ/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Jobs/Manager/JobManager.cs index 4e089d938..ef3ea7b82 100644 --- a/src/CoiniumServ/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/JobManager.cs @@ -53,6 +53,8 @@ public class JobManager : IJobManager private readonly IJobCounter _jobCounter; + private readonly IJobConfig _jobConfig; + private readonly IWalletConfig _walletConfig; private readonly IRewardsConfig _rewardsConfig; @@ -63,9 +65,9 @@ public class JobManager : IJobManager public IExtraNonce ExtraNonce { get { return _extraNonce; } } + private Timer _reBroadcastTimer; // timer for rebroadcasting jobs after an pre-configured idle perioud. - private Timer _timer; - private const int TimerExpiration = 60; + private Timer _blockPollerTimer; // timer for polling new blocks. public JobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracker jobTracker, IShareManager shareManager, IMinerManager minerManager, IHashAlgorithm hashAlgorithm) @@ -75,8 +77,11 @@ public JobManager(IPoolConfig poolConfig, IDaemonClient daemonClient, IJobTracke _shareManager = shareManager; _minerManager = minerManager; _hashAlgorithm = hashAlgorithm; + + _jobConfig = poolConfig.Job; _walletConfig = poolConfig.Wallet; _rewardsConfig = poolConfig.Rewards; + _jobCounter = new JobCounter(); // todo make this ioc based too. _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); @@ -88,18 +93,43 @@ public void Initialize(UInt32 instanceId) _shareManager.BlockFound += OnBlockFound; _minerManager.MinerAuthenticated += OnMinerAuthenticated; - _timer = new Timer(IdleJobTimer, null,Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. - BroadcastNewJob(true); // broadcast a new job initially - which will also setup the timer. + // create the timers as disabled. + _reBroadcastTimer = new Timer(IdleJobTimer, null,Timeout.Infinite, Timeout.Infinite); + _blockPollerTimer = new Timer(BlockPoller, null, Timeout.Infinite, Timeout.Infinite); + + CreateAndBroadcastNewJob(true); // broadcast a new job initially - which will also setup the timers. } private void OnBlockFound(object sender, EventArgs e) { - BroadcastNewJob(false); + CreateAndBroadcastNewJob(false); } private void IdleJobTimer(object state) { - BroadcastNewJob(true); + CreateAndBroadcastNewJob(true); + } + + 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(); + + if (blockTemplate.Height != _jobTracker.Current.Height) // if network reports a new block-height + { + _logger.Verbose("A new block {0} emerged in network, rebroadcasting new work", blockTemplate.Height); + CreateAndBroadcastNewJob(false); // broadcast a new job. + } + else + _logger.Verbose("No new blocks found in network, current job: 0x{0:x} height: {1}, network height: {2}", _jobTracker.Current.Id, _jobTracker.Current.Height, blockTemplate.Height); + } + catch (RpcException) { } // just skip any exceptions caused by the block-pooler queries. + + _blockPollerTimer.Change(_jobConfig.BlockRefreshInterval, Timeout.Infinite); // reset the block-poller timer so we can keep polling. } private void OnMinerAuthenticated(object sender, EventArgs e) @@ -113,33 +143,33 @@ private void OnMinerAuthenticated(object sender, EventArgs e) SendJobToMiner(miner, _jobTracker.Current); // send it to newly connected miner. } - private void BroadcastNewJob(bool initiatedByTimer) + private void CreateAndBroadcastNewJob(bool initiatedByTimer) { var job = GetNewJob(); // create a new job. if (job != null) // if we were able to create a new job { - var count = Broadcast(job); // broadcast to miners. + var count = BroadcastJob(job); // broadcast to miners. + + _blockPollerTimer.Change(_jobConfig.BlockRefreshInterval, Timeout.Infinite); // reset the block-poller timer so we can start or keep polling for a new block in the network. if (initiatedByTimer) - _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, TimerExpiration); + _logger.Information("Broadcasted new job 0x{0:x} to {1} subscribers as no new blocks found for last {2} seconds.", job.Id, count, _jobConfig.RebroadcastTimeout); else - _logger.Information("Broadcasted job 0x{0:x} to {1} subscribers as we have just found a new block.", job.Id, count); + _logger.Information("Broadcasted new job 0x{0:x} to {1} subscribers as network found a new block.", job.Id, count); } - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); // reset the idle-block timer. + // no matter we created a job successfully or not, reset the rebroadcast timer, so we can keep trying. + _reBroadcastTimer.Change(_jobConfig.RebroadcastTimeout * 1000, Timeout.Infinite); } private IJob GetNewJob() { try { - // TODO: fix the error for [Error] [JobManager] [n/a] New job creation failed: - // Coinium.Daemon.Exceptions.RpcException: Dogecoin is downloading blocks... - var blockTemplate = _daemonClient.GetBlockTemplate(); - // TODO: convert generation transaction to ioc based. + // TODO: convert generation transaction to ioc & DI based. var generationTransaction = new GenerationTransaction(ExtraNonce, _daemonClient, blockTemplate,_walletConfig, _rewardsConfig); generationTransaction.Create(); @@ -171,7 +201,7 @@ private IJob GetNewJob() /// /// sample communication: http://bitcoin.stackexchange.com/a/23112/8899 /// - private Int32 Broadcast(IJob job) + private Int32 BroadcastJob(IJob job) { try { diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 51b7222f4..76c71c6a9 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -102,7 +102,6 @@ private void RunPayments(object state) { _stopWatch.Start(); - var pendingBlocks = _storage.GetPendingBlocks(); // get all the pending blocks. var finalizedBlocks = GetFinalizedBlocks(pendingBlocks); @@ -114,7 +113,7 @@ private void RunPayments(object state) ProcessRemainingBalances(workerBalances); // process the remaining balances. ProcessRounds(rounds); // process the rounds. - _logger.Information("Payments processed - took {0:0.000} seconds.", (float)_stopWatch.ElapsedMilliseconds / 1000); + _logger.Information("Payments processed - took {0:0.000} seconds", (float)_stopWatch.ElapsedMilliseconds / 1000); _stopWatch.Reset(); diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs index 5aab2076d..d601ad4e8 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/IJob.cs @@ -35,6 +35,8 @@ public interface IJob : IEnumerable { UInt64 Id { get; } + int Height { get; } + string PreviousBlockHash { get; } string PreviousBlockHashReversed { get; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs index a26d4bbcc..8a87a51bc 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Notifications/Job.cs @@ -47,6 +47,11 @@ public class Job : IJob [JsonIgnore] public UInt64 Id { get; private set; } + /// + /// Height of the block we are looking for. + /// + public int Height { get; private set; } + public string PreviousBlockHash { get; private set; } /// @@ -134,6 +139,7 @@ public Job(UInt64 id, IHashAlgorithm algorithm, IBlockTemplate blockTemplate, IG Id = id; HashAlgorithm = algorithm; BlockTemplate = blockTemplate; + Height = blockTemplate.Height; GenerationTransaction = generationTransaction; PreviousBlockHash = blockTemplate.PreviousBlockHash.HexToByteArray().ToHexString(); PreviousBlockHashReversed = blockTemplate.PreviousBlockHash.HexToByteArray().ReverseByteOrder().ToHexString(); diff --git a/src/CoiniumServ/Statistics/IStatistics.cs b/src/CoiniumServ/Statistics/IStatistics.cs index febf8ac63..49c6b9af5 100644 --- a/src/CoiniumServ/Statistics/IStatistics.cs +++ b/src/CoiniumServ/Statistics/IStatistics.cs @@ -20,6 +20,9 @@ // license or white-label it as set out in licenses/commercial.txt. // #endregion + +using System; + namespace CoiniumServ.Statistics { public interface IStatistics @@ -29,5 +32,7 @@ public interface IStatistics IAlgorithms Algorithms { get; } IPools Pools { get; } + + DateTime LastUpdate { get; } } } diff --git a/src/CoiniumServ/Statistics/PerPool.cs b/src/CoiniumServ/Statistics/PerPool.cs index be7e45189..e781786b7 100644 --- a/src/CoiniumServ/Statistics/PerPool.cs +++ b/src/CoiniumServ/Statistics/PerPool.cs @@ -24,6 +24,7 @@ using System; using System.Dynamic; using System.Linq; +using CoiniumServ.Configuration; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Miners; @@ -49,14 +50,16 @@ public class PerPool:IPerPool private readonly IDaemonClient _daemonClient; private readonly IStorage _storage; private readonly IMinerManager _minerManager; + private readonly IStatisticsConfig _statisticsConfig; + private readonly dynamic _response; private readonly double _shareMultiplier; - private const int HashrateWindow = 300; /* How many seconds worth of shares should be gathered to generate hashrate. */ - public PerPool(IPoolConfig poolConfig, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) + public PerPool(IPoolConfig poolConfig, IConfigManager configManager, IDaemonClient daemonClient,IMinerManager minerManager, IHashAlgorithm hashAlgorithm, IBlocks blockStatistics, IStorage storage) { Config = poolConfig; + _statisticsConfig = configManager.WebServerConfig.Statistics; _daemonClient = daemonClient; _minerManager = minerManager; Blocks = blockStatistics; @@ -95,12 +98,12 @@ public void Recache(object state) private void ReadHashrate() { // read hashrate stats. - var windowTime = TimeHelpers.NowInUnixTime() - HashrateWindow; + var windowTime = TimeHelpers.NowInUnixTime() - _statisticsConfig.HashrateWindow; _storage.DeleteExpiredHashrateData(windowTime); var hashrates = _storage.GetHashrateData(windowTime); double total = hashrates.Sum(pair => pair.Value); - Hashrate = Convert.ToUInt64(_shareMultiplier * total / HashrateWindow); + Hashrate = Convert.ToUInt64(_shareMultiplier * total / _statisticsConfig.HashrateWindow); } private void ReadCoinData() diff --git a/src/CoiniumServ/Statistics/Statistics.cs b/src/CoiniumServ/Statistics/Statistics.cs index 646d02d49..c04d3927e 100644 --- a/src/CoiniumServ/Statistics/Statistics.cs +++ b/src/CoiniumServ/Statistics/Statistics.cs @@ -21,8 +21,12 @@ // #endregion +using System; +using System.Diagnostics; using System.Threading; +using CoiniumServ.Configuration; using CoiniumServ.Factories; +using Serilog; namespace CoiniumServ.Statistics { @@ -31,28 +35,45 @@ public class Statistics:IStatistics, IStatisticsProvider public IGlobal Global { get; private set; } public IAlgorithms Algorithms { get; private set; } public IPools Pools { get; private set; } + public DateTime LastUpdate { get; private set; } - private readonly Timer _timer; - private const int TimerExpiration = 10; + private readonly Timer _recacheTimer; // timer for recaching stastics. - public Statistics(IObjectFactory statisticsObjectFactory) + private readonly Stopwatch _stopWatch = new Stopwatch(); + + private readonly IStatisticsConfig _config; + + private readonly ILogger _logger; + + public Statistics(IConfigManager configManager, IObjectFactory statisticsObjectFactory) { + _config = configManager.WebServerConfig.Statistics; + Pools = statisticsObjectFactory.GetPoolStats(); Global = statisticsObjectFactory.GetGlobalStatistics(); Algorithms = statisticsObjectFactory.GetAlgorithmStatistics(); - _timer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. + _logger = Log.ForContext(); + + _recacheTimer = new Timer(Recache, null, Timeout.Infinite, Timeout.Infinite); // create the timer as disabled. Recache(null); // recache data initially. } public void Recache(object state) { + _stopWatch.Start(); + + // recache data. Pools.Recache(state); Algorithms.Recache(state); Global.Recache(state); - // reset the recache timer. - _timer.Change(TimerExpiration * 1000, Timeout.Infinite); + LastUpdate = DateTime.Now; + + _logger.Debug("Recached statistics - took {0:0.000} seconds", (float)_stopWatch.ElapsedMilliseconds / 1000); + _stopWatch.Reset(); + + _recacheTimer.Change(_config.UpdateInterval * 1000, Timeout.Infinite); // reset the recache timer. } } } diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index 0c60f2690..45098d3d2 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -1,4 +1,13 @@ { + # ------------------------------- + # Network Configuration + # ------------------------------- + + "network": { + "name": "CoiniumServ.com", + "motd": "Welcome to CoiniumServ pool network, enjoy your stay! - http://www.coiniumserv.com" + }, + # ------------------------------- # Website Configuration # ------------------------------- @@ -16,7 +25,7 @@ "bind": "127.0.0.1", "port": 80, "stats": { - "updateInterval": 60, + "updateInterval": 1, "hashrateWindow": 300 } }, diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index f484f94a4..2b5588502 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -107,5 +107,9 @@ + + - \ No newline at end of file +
    +

    Data last updated at @Model.Statistics.LastUpdate.ToLongTimeString().

    +
    \ No newline at end of file From 41fe99976e17fc744e8f3deb73dbfe0fcfcb6547 Mon Sep 17 00:00:00 2001 From: bonesoul Date: Thu, 24 Jul 2014 19:01:03 +0300 Subject: [PATCH 139/230] Added software & version identification to miners. JsonReaderException is now correctly handled in StratumMiner.cs:Parse() method instead of socket-server. Got rid of difficulty.cs, quite optimization there now sending a difficulty change message. Implemented stratum-extension client.show_message, a MOTD is now sent when a miner connects and he also gets a block change message (this one should be optional though) Added meta-config section to pools which contains the motd parameter. Removed the very generic exception handler from SocketServer.cs:BeginRecieve, exceptions should be handled in proper spots. Added stack config to global config json where we'll be able to add list of servers and name the stack. --- src/CoiniumServ/CoiniumServ.csproj | 6 +- .../Configuration/ConfigManager.cs | 4 +- .../Configuration/IConfigManager.cs | 2 + src/CoiniumServ/Configuration/IStackConfig.cs | 30 +++++ .../StackConfig.cs} | 50 +++----- src/CoiniumServ/Jobs/Manager/JobManager.cs | 3 + src/CoiniumServ/Miners/IMetaConfig.cs | 32 +++++ src/CoiniumServ/Miners/IMiner.cs | 5 + src/CoiniumServ/Miners/IMinerManager.cs | 10 +- src/CoiniumServ/Miners/MetaConfig.cs | 53 +++++++++ src/CoiniumServ/Miners/MinerManager.cs | 29 +++-- src/CoiniumServ/Miners/MinerSoftware.cs | 34 ++++++ .../Networking/Server/Sockets/SocketServer.cs | 5 - src/CoiniumServ/Pools/Config/IPoolConfig.cs | 2 + src/CoiniumServ/Pools/Config/PoolConfig.cs | 2 + .../Server/Mining/Stratum/IStratumMiner.cs | 7 +- .../Mining/Stratum/Service/StratumService.cs | 2 +- .../Server/Mining/Stratum/StratumMiner.cs | 109 ++++++++++++++---- .../Server/Mining/Vanilla/VanillaMiner.cs | 8 +- src/CoiniumServ/config/config-example.json | 7 +- .../config/pools/advanced-example.json | 17 +++ .../config/pools/default-example.json | 12 +- src/CoiniumServ/config/pools/example.json | 9 +- 23 files changed, 352 insertions(+), 86 deletions(-) create mode 100644 src/CoiniumServ/Configuration/IStackConfig.cs rename src/CoiniumServ/{Server/Mining/Stratum/Notifications/Difficulty.cs => Configuration/StackConfig.cs} (54%) create mode 100644 src/CoiniumServ/Miners/IMetaConfig.cs create mode 100644 src/CoiniumServ/Miners/MetaConfig.cs create mode 100644 src/CoiniumServ/Miners/MinerSoftware.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index ecf31ffea..b26945839 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -111,6 +111,8 @@ + + @@ -131,7 +133,10 @@ + + + @@ -308,7 +313,6 @@ - diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index b985e8920..8bc8b0676 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -40,6 +40,7 @@ public class ConfigManager:IConfigManager public bool ConfigExists { get { return _globalConfigData != null; } } public IWebServerConfig WebServerConfig { get; private set; } public ILogConfig LogConfig { get; private set; } + public IStackConfig StackConfig { get; private set; } public List PoolConfigs { get; private set; } @@ -60,11 +61,12 @@ public ConfigManager(IConfigFactory configFactory) _configFactory = configFactory; _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. - PoolConfigs = new List(); _coinConfigs = new Dictionary(); + PoolConfigs = new List(); LogConfig = new LogConfig(_globalConfigData.logging); WebServerConfig = new WebServerConfig(_globalConfigData.website); + StackConfig = new StackConfig(_globalConfigData.stack); // TODO: implement metrics config. } diff --git a/src/CoiniumServ/Configuration/IConfigManager.cs b/src/CoiniumServ/Configuration/IConfigManager.cs index a9391826c..1096a8268 100644 --- a/src/CoiniumServ/Configuration/IConfigManager.cs +++ b/src/CoiniumServ/Configuration/IConfigManager.cs @@ -36,6 +36,8 @@ public interface IConfigManager ILogConfig LogConfig { get; } + IStackConfig StackConfig { get; } + List PoolConfigs { get; } void Initialize(); diff --git a/src/CoiniumServ/Configuration/IStackConfig.cs b/src/CoiniumServ/Configuration/IStackConfig.cs new file mode 100644 index 000000000..7f51a9afb --- /dev/null +++ b/src/CoiniumServ/Configuration/IStackConfig.cs @@ -0,0 +1,30 @@ +#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.Configuration +{ + public interface IStackConfig : IConfig + { + string Name { get; } + } +} diff --git a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs b/src/CoiniumServ/Configuration/StackConfig.cs similarity index 54% rename from src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs rename to src/CoiniumServ/Configuration/StackConfig.cs index 5e03dbaba..11c96ce32 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Notifications/Difficulty.cs +++ b/src/CoiniumServ/Configuration/StackConfig.cs @@ -21,45 +21,33 @@ // #endregion -using System.Collections; -using System.Collections.Generic; -using Newtonsoft.Json; +using System; +using Serilog; -namespace CoiniumServ.Server.Mining.Stratum.Notifications +namespace CoiniumServ.Configuration { - // TODO: can we get rid of this? - - [JsonArray] - public class Difficulty : IEnumerable + public class StackConfig : IStackConfig { - /// - /// Difficulty for jobs. - /// - [JsonIgnore] - private readonly float _diff; - - /// - /// Creates a new instance of JobNotification. - /// - /// - public Difficulty(float difficulty) - { - _diff = difficulty; - } + public bool Valid { get; private set; } + public string Name { get; private set; } - public IEnumerator GetEnumerator() + public StackConfig(dynamic config) { - var data = new List + try { - _diff - }; + // set the defaults; + Name = "CoiniumServ.com"; - return data.GetEnumerator(); - } + // load the config data. + Name = config.name; - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading stack configuration"); + } } } } diff --git a/src/CoiniumServ/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Jobs/Manager/JobManager.cs index ef3ea7b82..3e6ac16a6 100644 --- a/src/CoiniumServ/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/JobManager.cs @@ -239,6 +239,9 @@ private bool SendJobToMiner(IMiner miner, IJob job) stratumMiner.SendJob(job); + // todo: this message should be configurable and optional + stratumMiner.SendMessage(string.Format("New job 0x{0:x} for next block {1}.", job.Id, job.Height)); + return true; } } diff --git a/src/CoiniumServ/Miners/IMetaConfig.cs b/src/CoiniumServ/Miners/IMetaConfig.cs new file mode 100644 index 000000000..1adf61025 --- /dev/null +++ b/src/CoiniumServ/Miners/IMetaConfig.cs @@ -0,0 +1,32 @@ +#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 CoiniumServ.Configuration; + +namespace CoiniumServ.Miners +{ + public interface IMetaConfig:IConfig + { + string MOTD { get; } + } +} diff --git a/src/CoiniumServ/Miners/IMiner.cs b/src/CoiniumServ/Miners/IMiner.cs index 2a17f7527..86bf9558a 100644 --- a/src/CoiniumServ/Miners/IMiner.cs +++ b/src/CoiniumServ/Miners/IMiner.cs @@ -21,6 +21,7 @@ // #endregion +using System; using CoiniumServ.Pools; namespace CoiniumServ.Miners @@ -54,6 +55,10 @@ public interface IMiner int InvalidShares { get; set; } + MinerSoftware Software { get; } + + Version Version { get; } + /// /// Authenticates the miner. /// diff --git a/src/CoiniumServ/Miners/IMinerManager.cs b/src/CoiniumServ/Miners/IMinerManager.cs index 81e2e62ca..99606029f 100644 --- a/src/CoiniumServ/Miners/IMinerManager.cs +++ b/src/CoiniumServ/Miners/IMinerManager.cs @@ -25,25 +25,27 @@ using System.Collections.Generic; using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Pools; +using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Vanilla; namespace CoiniumServ.Miners { public interface IMinerManager { + event EventHandler MinerAuthenticated; + IList Miners { get; } IMiner GetMiner(Int32 id); IMiner GetByConnection(IConnection connection); - T Create(IPool pool) where T : IMiner; + T Create(IPool pool) where T : IVanillaMiner; - T Create(UInt32 extraNonce, IConnection connection, IPool pool) where T : IMiner; + T Create(UInt32 extraNonce, IConnection connection, IPool pool) where T : IStratumMiner; void Remove(IConnection connection); void Authenticate(IMiner miner); - - event EventHandler MinerAuthenticated; } } diff --git a/src/CoiniumServ/Miners/MetaConfig.cs b/src/CoiniumServ/Miners/MetaConfig.cs new file mode 100644 index 000000000..33229ae73 --- /dev/null +++ b/src/CoiniumServ/Miners/MetaConfig.cs @@ -0,0 +1,53 @@ +#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 Serilog; + +namespace CoiniumServ.Miners +{ + public class MetaConfig :IMetaConfig + { + public bool Valid { get; private set; } + public string MOTD { get; private set; } + + public MetaConfig(dynamic config) + { + try + { + // set the defaults; + MOTD = "Welcome to CoiniumServ pool, enjoy your stay! - http://www.coinumserv.com"; + + // load the config data. + MOTD = config.motd; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading meta configuration"); + } + } + } +} diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 787b939a7..88475b99e 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -29,6 +29,7 @@ using CoiniumServ.Pools; using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; +using CoiniumServ.Server.Mining.Vanilla; using Serilog; namespace CoiniumServ.Miners @@ -43,7 +44,9 @@ public class MinerManager : IMinerManager private int _counter = 0; // counter for assigining unique id's to miners. - private readonly IMinerConfig _config; + private readonly IMinerConfig _minerConfig; + + private readonly IMetaConfig _metaConfig; private readonly IDaemonClient _daemonClient; @@ -51,7 +54,8 @@ public class MinerManager : IMinerManager public MinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) { - _config = poolConfig.Miner; + _minerConfig = poolConfig.Miner; + _metaConfig = poolConfig.Meta; _daemonClient = daemonClient; _miners = new Dictionary(); _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); @@ -70,19 +74,19 @@ public IMiner GetByConnection(IConnection connection) select pair.Value).FirstOrDefault(); } - public T Create(IPool pool) where T : IMiner + public T Create(IPool pool) where T : IVanillaMiner { var instance = Activator.CreateInstance(typeof(T), new object[] { _counter++, pool, this }); // create an instance of the miner. - var miner = (IMiner)instance; + var miner = (IVanillaMiner)instance; _miners.Add(miner.Id, miner); // add it to our collection. return (T)miner; } - public T Create(UInt32 extraNonce, IConnection connection, IPool pool) where T : IMiner + public T Create(UInt32 extraNonce, IConnection connection, IPool pool) where T : IStratumMiner { var instance = Activator.CreateInstance(typeof(T), new object[] { _counter++, extraNonce, connection, pool, this }); // create an instance of the miner. - var miner = (IMiner)instance; + var miner = (IStratumMiner)instance; _miners.Add(miner.Id, miner); // add it to our collection. return (T)miner; @@ -101,7 +105,7 @@ public void Remove(IConnection connection) public void Authenticate(IMiner miner) { - if (_config.ValidateUsername) // should we validate miner username? + if (_minerConfig.ValidateUsername) // should we validate miner username? miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; // if so validate it against coin daemon as an address. else miner.Authenticated = true; // else just accept him. @@ -112,13 +116,18 @@ public void Authenticate(IMiner miner) if (!miner.Authenticated) return; - - if(miner is IStratumMiner) - (miner as IStratumMiner).SendDifficulty(); // send the initial difficulty. + if (miner is IStratumMiner) + { + var stratumMiner = (IStratumMiner) miner; + stratumMiner.SendDifficulty(); // send the initial difficulty. + stratumMiner.SendMessage(_metaConfig.MOTD); // send the motd. + } + OnMinerAuthenticated(new MinerEventArgs(miner)); // notify listeners about the new authenticated miner. } + // todo: consider exposing this event by miner object itself. protected virtual void OnMinerAuthenticated(MinerEventArgs e) { var handler = MinerAuthenticated; diff --git a/src/CoiniumServ/Miners/MinerSoftware.cs b/src/CoiniumServ/Miners/MinerSoftware.cs new file mode 100644 index 000000000..022c26b5e --- /dev/null +++ b/src/CoiniumServ/Miners/MinerSoftware.cs @@ -0,0 +1,34 @@ +#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.Miners +{ + public enum MinerSoftware + { + Unknown, + BfgMiner, + CCMiner, + CGMiner, + CudaMiner + } +} diff --git a/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs b/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs index b3d993325..d3573c3c0 100644 --- a/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs +++ b/src/CoiniumServ/Networking/Server/Sockets/SocketServer.cs @@ -224,11 +224,6 @@ private void ReceiveCallback(IAsyncResult result) Log.ForContext().Debug(e, "ReceiveCallback"); RemoveConnection(connection); // An error occured while receiving, connection has disconnected. } - catch (Exception e) - { - Log.ForContext().Debug(e, "ReceiveCallback"); - RemoveConnection(connection); // An error occured while receiving, the connection may have been disconnected. - } } #endregion diff --git a/src/CoiniumServ/Pools/Config/IPoolConfig.cs b/src/CoiniumServ/Pools/Config/IPoolConfig.cs index fc84a403c..65f75e7db 100644 --- a/src/CoiniumServ/Pools/Config/IPoolConfig.cs +++ b/src/CoiniumServ/Pools/Config/IPoolConfig.cs @@ -45,6 +45,8 @@ public interface IPoolConfig:IConfig IDaemonConfig Daemon { get; } + IMetaConfig Meta { get; } + IWalletConfig Wallet { get; } IRewardsConfig Rewards { get; } diff --git a/src/CoiniumServ/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Pools/Config/PoolConfig.cs index c128a4da0..673896674 100644 --- a/src/CoiniumServ/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Pools/Config/PoolConfig.cs @@ -45,6 +45,7 @@ public class PoolConfig : IPoolConfig public bool Enabled { get; private set; } public ICoinConfig Coin { get; private set; } public IDaemonConfig Daemon { get; private set; } + public IMetaConfig Meta { get; private set; } public IWalletConfig Wallet { get; private set; } public IRewardsConfig Rewards { get; private set; } public IPaymentConfig Payments { get; private set; } @@ -71,6 +72,7 @@ public PoolConfig(dynamic config, ICoinConfig coinConfig) Coin = coinConfig; Daemon = new DaemonConfig(config.daemon); + Meta = new MetaConfig(config.meta); Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); Payments = new PaymentConfig(config.payments); diff --git a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs index ba4facbea..f0197cba0 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/IStratumMiner.cs @@ -42,6 +42,11 @@ public interface IStratumMiner:IMiner, IVardiffMiner float Difficulty { get; set; } + /// + /// Sends message of the day to miner. + /// + void SendMessage(string message); + /// /// Sends difficulty to the miner. /// @@ -52,6 +57,6 @@ public interface IStratumMiner:IMiner, IVardiffMiner /// void SendJob(IJob job); - void Subscribe(); + void Subscribe(string signature); } } diff --git a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs index 69ae4c1e2..b5d377495 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Service/StratumService.cs @@ -59,7 +59,7 @@ public SubscribeResponse SubscribeMiner(string signature) ExtraNonce2Size = ExtraNonce.ExpectedExtraNonce2Size // Represents expected length of extranonce2 which will be generated by the miner. (http://mining.bitcoin.cz/stratum-mining) }; - miner.Subscribe(); + miner.Subscribe(signature); return response; } diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index 0def3a693..f03a79567 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -22,6 +22,7 @@ #endregion using System; +using System.Collections.Generic; using System.Text; using AustinHarris.JsonRpc; using CoiniumServ.Logging; @@ -85,6 +86,9 @@ public class StratumMiner : IClient, IStratumMiner private readonly ILogger _logger; + public MinerSoftware Software { get; private set; } + public Version Version { get; private set; } + /// /// Creates a new miner instance. /// @@ -109,14 +113,6 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool.Config.Coin.Name); } - /// - /// Subscribes the miner to mining service. - /// - public void Subscribe() - { - Subscribed = true; - } - /// /// Authenticates the miner. /// @@ -134,14 +130,54 @@ public bool Authenticate(string user, string password) return Authenticated; } + /// + /// Subscribes the miner to mining service. + /// + public void Subscribe(string signature) + { + Subscribed = true; + + // identify the miner software. + try + { + var data = signature.Split('/'); + var software = data[0].ToLower(); + var version = data[1]; + + switch (software) + { + case "bfgminer": + Software = MinerSoftware.BfgMiner; + break; + case "ccminer": + Software = MinerSoftware.CCMiner; + break; + case "cgminer": + Software = MinerSoftware.CGMiner; + break; + case "cudaminer": + Software = MinerSoftware.CudaMiner; + break; + default: + Software = MinerSoftware.Unknown; + break; + } + + Version = new Version(version); + } + catch (Exception e) + { + Software = MinerSoftware.Unknown; + Version = new Version(); + } + } + /// /// Parses the incoming data. /// /// public void Parse(ConnectionDataEventArgs e) { - _logger.Verbose("rx: {0}", e.Data.ToEncodedString().PrettifyJson()); - var rpcResultHandler = new AsyncCallback( callback => { @@ -157,14 +193,39 @@ public void Parse(ConnectionDataEventArgs e) _logger.Verbose("tx: {0}", result.PrettifyJson()); }); - var line = e.Data.ToEncodedString(); - line = line.Replace("\n", ""); + try + { + var line = e.Data.ToEncodedString(); + line = line.Replace("\n", ""); + + var rpcRequest = new SocketServiceRequest(line); + var rpcContext = new SocketServiceContext(this, rpcRequest); - var rpcRequest = new SocketServiceRequest(line); - var rpcContext = new SocketServiceContext(this, rpcRequest); + _logger.Verbose("rx: {0}", line.PrettifyJson()); - var async = new JsonRpcStateAsync(rpcResultHandler, rpcContext) { JsonRpc = line }; - JsonRpcProcessor.Process(Pool.Config.Coin.Name, async, rpcContext); + var async = new JsonRpcStateAsync(rpcResultHandler, rpcContext) { JsonRpc = line }; + JsonRpcProcessor.Process(Pool.Config.Coin.Name, async, rpcContext); + } + catch (JsonReaderException) // if client send an invalid message + { + // TODO: Add tls support! + this.Connection.Disconnect(); // disconnect him. + } + } + + /// + /// Sends message of the day to miner. + /// + public void SendMessage(string message) + { + var notification = new JsonRequest + { + Id = null, + Method = "client.show_message", + Params = new List { message } + }; + + Send(notification); } /// @@ -176,15 +237,10 @@ public void SendDifficulty() { Id = null, Method = "mining.set_difficulty", - Params = new Difficulty(Difficulty) + Params = new List{ Difficulty } }; - var json = JsonConvert.SerializeObject(notification) + "\n"; - - var data = Encoding.UTF8.GetBytes(json); - Connection.Send(data); - - _logger.Verbose("tx: {0}", data.ToEncodedString().PrettifyJson()); + Send(notification); } /// @@ -199,7 +255,12 @@ public void SendJob(IJob job) Params = job }; - var json = JsonConvert.SerializeObject(notification) + "\n"; + Send(notification); + } + + private void Send(JsonRequest request) + { + var json = JsonConvert.SerializeObject(request) + "\n"; var data = Encoding.UTF8.GetBytes(json); Connection.Send(data); diff --git a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs index 91c05ee5c..35c7901a1 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/VanillaMiner.cs @@ -26,7 +26,6 @@ using System.Net; using System.Text; using AustinHarris.JsonRpc; -using CoiniumServ.Factories; using CoiniumServ.Logging; using CoiniumServ.Miners; using CoiniumServ.Pools; @@ -58,6 +57,9 @@ public class VanillaMiner : IVanillaMiner public IPool Pool { get; private set; } + public MinerSoftware Software { get; private set; } + public Version Version { get; private set; } + private readonly IMinerManager _minerManager; private readonly ILogger _logger; @@ -68,7 +70,6 @@ public class VanillaMiner : IVanillaMiner /// /// /// - /// public VanillaMiner(int id, IPool pool, IMinerManager minerManager) { Id = id; // the id of the miner. @@ -77,6 +78,9 @@ public VanillaMiner(int id, IPool pool, IMinerManager minerManager) Authenticated = false; // miner has to authenticate. + Software = MinerSoftware.Unknown; + Version = new Version(); + _logger = LogManager.PacketLogger.ForContext().ForContext("Component", pool.Config.Coin.Name); } diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index 45098d3d2..833de9f5a 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -1,11 +1,10 @@ { # ------------------------------- - # Network Configuration + # Stack Configuration # ------------------------------- - "network": { - "name": "CoiniumServ.com", - "motd": "Welcome to CoiniumServ pool network, enjoy your stay! - http://www.coiniumserv.com" + "stack": { + "name": "CoiniumServ.com" }, # ------------------------------- diff --git a/src/CoiniumServ/config/pools/advanced-example.json b/src/CoiniumServ/config/pools/advanced-example.json index a44a81591..626b75648 100644 --- a/src/CoiniumServ/config/pools/advanced-example.json +++ b/src/CoiniumServ/config/pools/advanced-example.json @@ -2,6 +2,13 @@ # detailed sample config file for pool which explicility sets all settings. "enabled": false, + + # ------------------------------- + # Coin configuration + # ------------------------------- + + # coin: name of the coin configuration file that should exist in config/coins/. + "coin": "litecoin.json", # ------------------------------- @@ -20,6 +27,16 @@ "password": "password" }, + # ------------------------------- + # Meta Configuration + # ------------------------------- + + # motd: message of the day. + + "meta": { + "motd": "Welcome to CoiniumServ pool, enjoy your stay! - http://www.coinumserv.com" + }, + # ------------------------------- # Wallet & Rewards Configuration # ------------------------------- diff --git a/src/CoiniumServ/config/pools/default-example.json b/src/CoiniumServ/config/pools/default-example.json index b680af9a0..64c7fbc5d 100644 --- a/src/CoiniumServ/config/pools/default-example.json +++ b/src/CoiniumServ/config/pools/default-example.json @@ -1,7 +1,7 @@ { # default pool configuration # if a per-pool config file doesn't override a setting, default value from this file will be applied - + # ------------------------------- # Coin Daemon RPC Connection # ------------------------------- @@ -12,6 +12,16 @@ "host": "127.0.0.1" }, + # ------------------------------- + # Meta Configuration + # ------------------------------- + + # motd: message of the day. + + "meta": { + "motd": "Welcome to CoiniumServ pool, enjoy your stay! - http://www.coinumserv.com" + }, + # ------------------------------- # Payment Processing Configuration # ------------------------------- diff --git a/src/CoiniumServ/config/pools/example.json b/src/CoiniumServ/config/pools/example.json index 0a863a6dc..782598349 100644 --- a/src/CoiniumServ/config/pools/example.json +++ b/src/CoiniumServ/config/pools/example.json @@ -2,7 +2,14 @@ # sample pool config file that only sets specific settings for the pool and gets the others from default.json "enabled": false, - "coin": "litecoin.json", + + # ------------------------------- + # Coin configuration + # ------------------------------- + + # coin: name of the coin configuration file that should exist in config/coins/. + + "coin": "litecoin.json", # ------------------------------- # Coin Daemon RPC Connection From 8ba516d91070eb489600df901e9692543a204d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 25 Jul 2014 00:47:13 +0300 Subject: [PATCH 140/230] Added metrics section to global config. Added a few sample metrics & health-checks. updated serilog to 1.3.36 Added sample metrics logs. Added metrics support for nancy @ /admin/metrics --- src/CoiniumServ/CoiniumServ.csproj | 10 ++++++---- src/CoiniumServ/Miners/MinerManager.cs | 6 +++++- .../Networking/Server/Http/Web/WebBootstrapper.cs | 10 ++++++++-- src/CoiniumServ/Persistance/Redis/Redis.cs | 10 +++++++--- src/CoiniumServ/Program.cs | 13 ++++++++++++- src/CoiniumServ/Server/Web/Modules/Pool.cs | 1 - src/CoiniumServ/Statistics/Global.cs | 6 +++++- src/CoiniumServ/config/config-example.json | 9 ++++++++- src/CoiniumServ/packages.config | 2 +- 9 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index b26945839..39b1f87f4 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -62,7 +62,8 @@ False ..\..\build\packages\HashLib.2.0.1\lib\net40\HashLib.dll - + + False ..\..\build\packages\Metrics.NET.0.1.9\lib\net45\Metrics.dll @@ -77,7 +78,8 @@ False ..\..\build\packages\Nancy.Hosting.Self.0.23.2\lib\net40\Nancy.Hosting.Self.dll - + + False ..\..\build\packages\NancyFx.Metrics.0.1.9\lib\net45\Nancy.Metrics.dll @@ -90,11 +92,11 @@ False - ..\..\build\packages\Serilog.1.3.35\lib\net45\Serilog.dll + ..\..\build\packages\Serilog.1.3.36\lib\net45\Serilog.dll False - ..\..\build\packages\Serilog.1.3.35\lib\net45\Serilog.FullNetFx.dll + ..\..\build\packages\Serilog.1.3.36\lib\net45\Serilog.FullNetFx.dll False diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 88475b99e..1dbabf882 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -30,6 +30,7 @@ using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Vanilla; +using Metrics; using Serilog; namespace CoiniumServ.Miners @@ -58,7 +59,10 @@ public MinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) _metaConfig = poolConfig.Meta; _daemonClient = daemonClient; _miners = new Dictionary(); - _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); + + // add metrics + Metric.Gauge(string.Format("{0}-workers", poolConfig.Coin.Name.ToLower()), () => Miners.Count, Unit.Items); } public IMiner GetMiner(Int32 id) diff --git a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs index 1121ddbcd..6f7ac5b44 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs @@ -22,6 +22,7 @@ #endregion using CoiniumServ.Repository.Context; +using Metrics; using Nancy; using Nancy.Bootstrapper; using Nancy.Conventions; @@ -43,8 +44,13 @@ public WebBootstrapper(IApplicationContext applicationContext) } protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) - { - StaticConfiguration.EnableRequestTracing = true; + { + // enable metrics module + // todo: enable authentication support + Metric.Config.WithNancy(config => config + .WithMetricsModule("/admin/metrics")); + //.WithMetricsModule(m => m.RequiresAuthentication(), "/admin/metrics")); + CustomErrors.Enable(pipelines, new ErrorConfiguration()); } diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index b014050a0..d4de4d3d0 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -27,13 +27,13 @@ using System.Linq; using System.Net; using System.Net.Sockets; -using CoiniumServ.Factories; using CoiniumServ.Payments; using CoiniumServ.Persistance.Blocks; using CoiniumServ.Pools.Config; using CoiniumServ.Shares; using CoiniumServ.Utils.Extensions; using CoiniumServ.Utils.Helpers.Time; +using Metrics; using Serilog; using StackExchange.Redis; @@ -42,7 +42,8 @@ namespace CoiniumServ.Persistance.Redis public class Redis:IStorage, IRedis { public bool IsEnabled { get; private set; } - public bool IsConnected { get { return _connectionMultiplexer.IsConnected; } } + + public bool IsConnected { get { return _connectionMultiplexer != null && _connectionMultiplexer.IsConnected; } } private readonly Version _requiredMinimumVersion = new Version(2, 6); private readonly IRedisConfig _redisConfig; @@ -65,6 +66,10 @@ public Redis(PoolConfig poolConfig) if (IsEnabled) Initialize(); + + // add health check. + HealthChecks.RegisterHealthCheck(string.Format("{0}-redis", _poolConfig.Coin.Name.ToLower()), + () => IsConnected ? HealthCheckResult.Healthy() : HealthCheckResult.Unhealthy("connection problem")); } public void AddShare(IShare share) @@ -454,7 +459,6 @@ private void Initialize() } catch (Exception e) { - IsEnabled = false; _logger.Error(string.Format("Storage initialization failed: {0:l}:{1}.", endpoint.Host, endpoint.Port)); } } diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index a8462bba3..821876cf9 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -29,8 +29,10 @@ using CoiniumServ.Repository; using CoiniumServ.Utils; using CoiniumServ.Utils.Commands; +using CoiniumServ.Utils.Helpers.IO; using CoiniumServ.Utils.Platform; using CoiniumServ.Utils.Versions; +using Metrics; using Nancy.TinyIoc; using Serilog; @@ -57,7 +59,7 @@ static void Main(string[] args) // start the ioc kernel. var kernel = TinyIoCContainer.Current; - var bootstrapper = new Bootstrapper(kernel); + new Bootstrapper(kernel); var objectFactory = kernel.Resolve(); var configFactory = kernel.Resolve(); @@ -87,6 +89,15 @@ static void Main(string[] args) // initialize config manager. configManager.Initialize(); + // todo: move to it's own class + // initialize metrics support + Metric.Config + .WithAllCounters() + .WithReporting(c => c + .WithTextFileReport(string.Format(@"{0}\\logs\\metrics\\report.log", FileHelpers.AssemblyRoot), TimeSpan.FromSeconds(60)) + .WithCSVReports(string.Format(@"{0}\\logs\\metrics\\csv", FileHelpers.AssemblyRoot), TimeSpan.FromSeconds(1))) + .WithErrorHandler(exception => _logger.Error("Metrics error: {0}", exception.Message)); + // start pool manager. var poolManager = objectFactory.GetPoolManager(); poolManager.Run(); diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index 3d1bd5423..cf3dcaa45 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -38,7 +38,6 @@ public PoolModule(IPoolManager poolManager) if (pool != null) return View["pool", pool]; - var error = new Error { Summary = "Pool not found", diff --git a/src/CoiniumServ/Statistics/Global.cs b/src/CoiniumServ/Statistics/Global.cs index d83337418..1c2776e94 100644 --- a/src/CoiniumServ/Statistics/Global.cs +++ b/src/CoiniumServ/Statistics/Global.cs @@ -23,6 +23,7 @@ using System; using System.Dynamic; +using Metrics; using Newtonsoft.Json; namespace CoiniumServ.Statistics @@ -37,12 +38,15 @@ public class Global : IGlobal private readonly IPools _pools; private readonly IAlgorithms _algorithms; - public Global(IPools pools, IAlgorithms algorithms) { _pools = pools; _algorithms = algorithms; _response = new ExpandoObject(); + + // add metrics + Metric.Gauge("global-workers", () => WorkerCount, Unit.Items); + Metric.Gauge("global-hashrate", () => Hashrate, Unit.Custom("hashes")); } public void Recache(object state) diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index 833de9f5a..875a478a1 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -17,6 +17,9 @@ # stats: # updateInterval: interval for recaching statistics. # hashrateWindow: how many seconds worth of shares should be gathered to generate hashrate. + # backend: + # enabled: set this true to enable admin backend. + # password: password for enabling administrator # website configuration "website": { @@ -24,8 +27,12 @@ "bind": "127.0.0.1", "port": 80, "stats": { - "updateInterval": 1, + "updateInterval": 60, "hashrateWindow": 300 + }, + "backend" : { + "password": "your-password-here", + "metrics": true } }, diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 042cd075d..6e647893c 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -12,6 +12,6 @@ - + \ No newline at end of file From 7ab7dff8bf3f89758f7a71ccee5a108f2472126f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 25 Jul 2014 01:32:11 +0300 Subject: [PATCH 141/230] Changed release mode output path to /bin/Release/. Fixed nancy build for mono. --- src/CoiniumServ/CoiniumServ.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 39b1f87f4..e7025d38d 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -33,7 +33,7 @@ AnyCPU pdbonly true - bin\Release\ + ..\..\bin\Release\ TRACE prompt 4 @@ -998,10 +998,10 @@ - + - + From d511d37070f16d66ff8a93aedd2ff46a24a7f0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Fri, 25 Jul 2014 01:38:54 +0300 Subject: [PATCH 142/230] another nancy for mono fix --- src/CoiniumServ/CoiniumServ.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index e7025d38d..ea0bc60b6 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -1000,16 +1000,16 @@ - - + + if $(ConfigurationName) == Debug ( -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\Net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(SolutionDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\net40\Nancy.ViewEngines.Razor.dll" "$(SolutionDir)bin\" ) - - + + if $(ConfigurationName) == Debug ( -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(SolutionDir)bin\" -xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\net40\Nancy.ViewEngines.Razor.dll" "$(SolutionDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\BuildProviders\Nancy.ViewEngines.Razor.BuildProviders.dll" "$(ProjectDir)bin\" +xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\net40\Nancy.ViewEngines.Razor.dll" "$(ProjectDir)bin\" ) - \ No newline at end of file + From b42a038efe64db8d077d6e2b9a2aeca338aa926a Mon Sep 17 00:00:00 2001 From: bonesoul Date: Fri, 25 Jul 2014 18:07:56 +0300 Subject: [PATCH 155/230] Implemented backendconfig. Moved metrics stuff to metricsmanager.cs. --- src/CoiniumServ/CoiniumServ.csproj | 6 +- src/CoiniumServ/Factories/ConfigFactory.cs | 2 + src/CoiniumServ/Factories/IConfigFactory.cs | 6 ++ src/CoiniumServ/Factories/IObjectFactory.cs | 5 +- src/CoiniumServ/Factories/ObjectFactory.cs | 7 ++- src/CoiniumServ/Metrics/IMetricsManager.cs | 30 ++++++++++ src/CoiniumServ/Metrics/MetricsManager.cs | 59 +++++++++++++++++++ src/CoiniumServ/Miners/MinerManager.cs | 5 +- .../Server/Http/Web/WebBootstrapper.cs | 11 ++-- src/CoiniumServ/Program.cs | 12 +--- .../Repository/Registries/ClassRegistry.cs | 3 +- .../Repository/Registries/ManagerRegistry.cs | 4 ++ src/CoiniumServ/Server/Web/IBackendConfig.cs | 32 ++++++++++ .../Server/Web/IWebServerConfig.cs | 2 + .../Server/Web/Modules/BackendConfig.cs | 50 ++++++++++++++++ src/CoiniumServ/Server/Web/WebServerConfig.cs | 3 + src/CoiniumServ/Statistics/Global.cs | 9 ++- src/CoiniumServ/config/config-example.json | 7 ++- 18 files changed, 224 insertions(+), 29 deletions(-) create mode 100644 src/CoiniumServ/Metrics/IMetricsManager.cs create mode 100644 src/CoiniumServ/Metrics/MetricsManager.cs create mode 100644 src/CoiniumServ/Server/Web/IBackendConfig.cs create mode 100644 src/CoiniumServ/Server/Web/Modules/BackendConfig.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 6accc0203..25c86da2a 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -136,6 +136,8 @@ + + @@ -147,6 +149,8 @@ + + @@ -1020,4 +1024,4 @@ xcopy /s /y /R "$(SolutionDir)packages\Nancy.Viewengines.Razor.0.23.2\lib\net40\ --> - + \ No newline at end of file diff --git a/src/CoiniumServ/Factories/ConfigFactory.cs b/src/CoiniumServ/Factories/ConfigFactory.cs index 65902fcaa..d1a82bab1 100644 --- a/src/CoiniumServ/Factories/ConfigFactory.cs +++ b/src/CoiniumServ/Factories/ConfigFactory.cs @@ -23,8 +23,10 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Configuration; +using CoiniumServ.Logging; using CoiniumServ.Pools.Config; using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Web; using Nancy.TinyIoc; namespace CoiniumServ.Factories diff --git a/src/CoiniumServ/Factories/IConfigFactory.cs b/src/CoiniumServ/Factories/IConfigFactory.cs index 5c8b1cac2..8d049b6b1 100644 --- a/src/CoiniumServ/Factories/IConfigFactory.cs +++ b/src/CoiniumServ/Factories/IConfigFactory.cs @@ -23,7 +23,9 @@ using CoiniumServ.Coin.Config; using CoiniumServ.Configuration; +using CoiniumServ.Logging; using CoiniumServ.Pools.Config; +using CoiniumServ.Server.Web; namespace CoiniumServ.Factories { @@ -34,8 +36,12 @@ public interface IConfigFactory { IConfigManager GetConfigManager(); + #region per-pool configs + IPoolConfig GetPoolConfig(dynamic config, ICoinConfig coinConfig); ICoinConfig GetCoinConfig(dynamic config); + + #endregion } } diff --git a/src/CoiniumServ/Factories/IObjectFactory.cs b/src/CoiniumServ/Factories/IObjectFactory.cs index c3d720e1f..bd8d3b256 100644 --- a/src/CoiniumServ/Factories/IObjectFactory.cs +++ b/src/CoiniumServ/Factories/IObjectFactory.cs @@ -22,13 +22,12 @@ #endregion using CoiniumServ.Banning; -using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; -using CoiniumServ.Daemon.Config; using CoiniumServ.Jobs.Manager; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Logging; +using CoiniumServ.Metrics; using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; @@ -125,6 +124,8 @@ IMiningServer GetMiningServer(string type, IPoolConfig poolConfig, IPool pool, I ILogManager GetLogManager(); + IMetricsManager GetMetricsManager(); + #endregion } } diff --git a/src/CoiniumServ/Factories/ObjectFactory.cs b/src/CoiniumServ/Factories/ObjectFactory.cs index e2112f812..3f7bec4a3 100644 --- a/src/CoiniumServ/Factories/ObjectFactory.cs +++ b/src/CoiniumServ/Factories/ObjectFactory.cs @@ -22,12 +22,12 @@ #endregion using CoiniumServ.Banning; -using CoiniumServ.Coin.Config; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; using CoiniumServ.Jobs.Manager; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Logging; +using CoiniumServ.Metrics; using CoiniumServ.Miners; using CoiniumServ.Payments; using CoiniumServ.Persistance; @@ -312,6 +312,11 @@ public ILogManager GetLogManager() return _applicationContext.Container.Resolve(); } + public IMetricsManager GetMetricsManager() + { + return _applicationContext.Container.Resolve(); + } + #endregion } } diff --git a/src/CoiniumServ/Metrics/IMetricsManager.cs b/src/CoiniumServ/Metrics/IMetricsManager.cs new file mode 100644 index 000000000..1768d7933 --- /dev/null +++ b/src/CoiniumServ/Metrics/IMetricsManager.cs @@ -0,0 +1,30 @@ +#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.Metrics +{ + public interface IMetricsManager + { + + } +} diff --git a/src/CoiniumServ/Metrics/MetricsManager.cs b/src/CoiniumServ/Metrics/MetricsManager.cs new file mode 100644 index 000000000..1491d6e0d --- /dev/null +++ b/src/CoiniumServ/Metrics/MetricsManager.cs @@ -0,0 +1,59 @@ +#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 CoiniumServ.Configuration; +using CoiniumServ.Server.Web; +using CoiniumServ.Utils.Helpers.IO; +using CoiniumServ.Utils.Platform; +using Metrics; +using Serilog; + +namespace CoiniumServ.Metrics +{ + public class MetricsManager : IMetricsManager + { + private readonly IBackendConfig _config; + + private readonly ILogger _logger; + + public MetricsManager(IConfigManager configManager) + { + _config = configManager.WebServerConfig.Backend; + + if (!_config.MetricsEnabled) + return; + + _logger = Log.ForContext(); + + Metric.Config + .WithReporting(c => c + .WithTextFileReport(string.Format("{0}/logs/metrics/report.log", FileHelpers.AssemblyRoot),TimeSpan.FromSeconds(5)) + .WithCSVReports(string.Format(@"{0}/logs/metrics/csv", FileHelpers.AssemblyRoot),TimeSpan.FromSeconds(5))) + .WithErrorHandler(exception => _logger.Error("Metrics error: {0}", exception.Message)); + + if (PlatformManager.Framework == Frameworks.DotNet) + Metric.Config.WithAllCounters(); // there is a still unresolved bug with mono borking with system.security.claimsidentity. + } + } +} diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 1dbabf882..0bd6cafe3 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -59,10 +59,7 @@ public MinerManager(IPoolConfig poolConfig, IDaemonClient daemonClient) _metaConfig = poolConfig.Meta; _daemonClient = daemonClient; _miners = new Dictionary(); - _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); - - // add metrics - Metric.Gauge(string.Format("{0}-workers", poolConfig.Coin.Name.ToLower()), () => Miners.Count, Unit.Items); + _logger = Log.ForContext().ForContext("Component", poolConfig.Coin.Name); } public IMiner GetMiner(Int32 id) diff --git a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs index 6f7ac5b44..9c804a46c 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/WebBootstrapper.cs @@ -21,6 +21,7 @@ // #endregion +using CoiniumServ.Configuration; using CoiniumServ.Repository.Context; using Metrics; using Nancy; @@ -44,12 +45,12 @@ public WebBootstrapper(IApplicationContext applicationContext) } protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) - { - // enable metrics module + { + var configManager = container.Resolve(); + // todo: enable authentication support - Metric.Config.WithNancy(config => config - .WithMetricsModule("/admin/metrics")); - //.WithMetricsModule(m => m.RequiresAuthentication(), "/admin/metrics")); + if(configManager.WebServerConfig.Backend.MetricsEnabled) + Metric.Config.WithNancy(config => config.WithMetricsModule("/admin/metrics")); CustomErrors.Enable(pipelines, new ErrorConfiguration()); } diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index c60c75092..7429335f1 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -89,23 +89,15 @@ static void Main(string[] args) // initialize config manager. configManager.Initialize(); - // todo: move to it's own class // initialize metrics support - Metric.Config - .WithReporting(c => c - .WithTextFileReport(string.Format(@"{0}\\logs\\metrics\\report.log", FileHelpers.AssemblyRoot), TimeSpan.FromSeconds(60)) - .WithCSVReports(string.Format(@"{0}\\logs\\metrics\\csv", FileHelpers.AssemblyRoot), TimeSpan.FromSeconds(1))) - .WithErrorHandler(exception => _logger.Error("Metrics error: {0}", exception.Message)); - - if (PlatformManager.Framework == Frameworks.DotNet) - Metric.Config.WithAllCounters(); // there is a still unresolved bug with mono borking with system.security.claimsidentity. + objectFactory.GetMetricsManager(); // start pool manager. var poolManager = objectFactory.GetPoolManager(); poolManager.Run(); // start web server. - var webServer = objectFactory.GetWebServer(); + objectFactory.GetWebServer(); while (true) // idle loop & command parser { diff --git a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs index a803d673d..d987929e7 100644 --- a/src/CoiniumServ/Repository/Registries/ClassRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ClassRegistry.cs @@ -22,6 +22,7 @@ #endregion using CoiniumServ.Coin.Config; +using CoiniumServ.Configuration; using CoiniumServ.Daemon; using CoiniumServ.Jobs.Tracker; using CoiniumServ.Logging; @@ -32,6 +33,7 @@ using CoiniumServ.Pools; using CoiniumServ.Pools.Config; using CoiniumServ.Repository.Context; +using CoiniumServ.Server.Web; using CoiniumServ.Statistics; using Nancy.Bootstrapper; @@ -62,7 +64,6 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); - _applicationContext.Container.Register().AsSingleton(); _applicationContext.Container.Register().AsSingleton(); } } diff --git a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs index 629e64be2..437c70781 100644 --- a/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs +++ b/src/CoiniumServ/Repository/Registries/ManagerRegistry.cs @@ -24,6 +24,8 @@ using CoiniumServ.Banning; using CoiniumServ.Configuration; using CoiniumServ.Jobs.Manager; +using CoiniumServ.Logging; +using CoiniumServ.Metrics; using CoiniumServ.Miners; using CoiniumServ.Pools; using CoiniumServ.Repository.Context; @@ -51,6 +53,8 @@ public void RegisterInstances() _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsMultiInstance(); _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); + _applicationContext.Container.Register().AsSingleton(); } } } diff --git a/src/CoiniumServ/Server/Web/IBackendConfig.cs b/src/CoiniumServ/Server/Web/IBackendConfig.cs new file mode 100644 index 000000000..10d9a76f7 --- /dev/null +++ b/src/CoiniumServ/Server/Web/IBackendConfig.cs @@ -0,0 +1,32 @@ +#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 CoiniumServ.Configuration; + +namespace CoiniumServ.Server.Web +{ + public interface IBackendConfig : IConfig + { + bool MetricsEnabled { get; } + } +} diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index 7cba75213..a28355f3f 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -42,5 +42,7 @@ public interface IWebServerConfig:IConfig Int32 Port { get; } IStatisticsConfig Statistics { get; } + + IBackendConfig Backend { get; } } } diff --git a/src/CoiniumServ/Server/Web/Modules/BackendConfig.cs b/src/CoiniumServ/Server/Web/Modules/BackendConfig.cs new file mode 100644 index 000000000..60b736224 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/BackendConfig.cs @@ -0,0 +1,50 @@ +#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 Serilog; + +namespace CoiniumServ.Server.Web.Modules +{ + public class BackendConfig: IBackendConfig + { + public bool Valid { get; private set; } + public bool MetricsEnabled { get; private set; } + + public BackendConfig(dynamic config) + { + try + { + // load the config data. + MetricsEnabled = config.metrics.enabled; + + Valid = true; + } + catch (Exception e) + { + Valid = false; + Log.Logger.ForContext().Error(e, "Error loading backend configuration"); + } + } + } +} diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index 66748dfa9..947015cdb 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -22,6 +22,7 @@ #endregion using System; +using CoiniumServ.Server.Web.Modules; using CoiniumServ.Statistics; using Serilog; @@ -33,6 +34,7 @@ public class WebServerConfig : IWebServerConfig public string BindInterface { get; private set; } public int Port { get; private set; } public IStatisticsConfig Statistics { get; private set; } + public IBackendConfig Backend { get; private set; } public bool Valid { get; private set; } public WebServerConfig(dynamic config) { @@ -47,6 +49,7 @@ public WebServerConfig(dynamic config) BindInterface = config.bind; Port = config.port; Statistics = new StatisticsConfig(config.stats); + Backend = new BackendConfig(config.backend); Valid = true; } diff --git a/src/CoiniumServ/Statistics/Global.cs b/src/CoiniumServ/Statistics/Global.cs index 1c2776e94..874093f72 100644 --- a/src/CoiniumServ/Statistics/Global.cs +++ b/src/CoiniumServ/Statistics/Global.cs @@ -23,6 +23,7 @@ using System; using System.Dynamic; +using CoiniumServ.Configuration; using Metrics; using Newtonsoft.Json; @@ -38,15 +39,17 @@ public class Global : IGlobal private readonly IPools _pools; private readonly IAlgorithms _algorithms; - public Global(IPools pools, IAlgorithms algorithms) + public Global(IPools pools, IAlgorithms algorithms, IConfigManager configManager) { _pools = pools; _algorithms = algorithms; _response = new ExpandoObject(); + // add metrics - Metric.Gauge("global-workers", () => WorkerCount, Unit.Items); - Metric.Gauge("global-hashrate", () => Hashrate, Unit.Custom("hashes")); + if(configManager.WebServerConfig.Backend.MetricsEnabled) + Metric.Gauge("global-workers", () => WorkerCount, Unit.Items); + Metric.Gauge("global-hashrate", () => Hashrate, Unit.Custom("hashes")); } public void Recache(object state) diff --git a/src/CoiniumServ/config/config-example.json b/src/CoiniumServ/config/config-example.json index 875a478a1..d184f67b4 100644 --- a/src/CoiniumServ/config/config-example.json +++ b/src/CoiniumServ/config/config-example.json @@ -3,6 +3,8 @@ # Stack Configuration # ------------------------------- + # name: name of the pool stack. + "stack": { "name": "CoiniumServ.com" }, @@ -31,8 +33,9 @@ "hashrateWindow": 300 }, "backend" : { - "password": "your-password-here", - "metrics": true + "metrics": { + "enabled": false + } } }, From 0b06b416bd8c0e48a4f6b75ead634c9352b4a9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 26 Jul 2014 03:16:03 +0300 Subject: [PATCH 156/230] ConfigManager.cs work. --- .../Configuration/ConfigManager.cs | 32 ++++++++++++------- .../Configuration/IConfigManager.cs | 2 -- src/CoiniumServ/Program.cs | 7 ---- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index 7c2509c37..85f18fddf 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Management.Instrumentation; using CoiniumServ.Coin.Config; using CoiniumServ.Factories; using CoiniumServ.Logging; @@ -37,11 +38,9 @@ namespace CoiniumServ.Configuration { public class ConfigManager:IConfigManager { - public bool ConfigExists { get { return _globalConfigData != null; } } public IWebServerConfig WebServerConfig { get; private set; } public ILogConfig LogConfig { get; private set; } public IStackConfig StackConfig { get; private set; } - public List PoolConfigs { get; private set; } private const string GlobalConfigFilename = "config/config.json"; // global config filename. @@ -50,7 +49,6 @@ public class ConfigManager:IConfigManager private readonly Dictionary _coinConfigs; // cache for loaded coin configs. - private readonly dynamic _globalConfigData; // global config data. private dynamic _defaultPoolConfig; private readonly IConfigFactory _configFactory; @@ -60,18 +58,28 @@ public ConfigManager(IConfigFactory configFactory) { _configFactory = configFactory; - _globalConfigData = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. - _coinConfigs = new Dictionary(); + _coinConfigs = new Dictionary(); // dictionary of coin configurations. + PoolConfigs = new List(); // list of pool configurations. + + ReadGlobalConfig(); + } + + private void ReadGlobalConfig() + { + var data = JsonConfigReader.Read(GlobalConfigFilename); // read the global config data. - PoolConfigs = new List(); + if (data == null) // make sure it exists, else gracefully exists + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Couldn't read config/config.json! Make sure you rename config/config-example.json as config/config.json."); + Console.ResetColor(); - if(_globalConfigData == null) - return; + Environment.Exit(-1); + } - LogConfig = new LogConfig(_globalConfigData.logging); - WebServerConfig = new WebServerConfig(_globalConfigData.website); - StackConfig = new StackConfig(_globalConfigData.stack); - // TODO: implement metrics config. + LogConfig = new LogConfig(data.logging); + WebServerConfig = new WebServerConfig(data.website); + StackConfig = new StackConfig(data.stack); } public void Initialize() diff --git a/src/CoiniumServ/Configuration/IConfigManager.cs b/src/CoiniumServ/Configuration/IConfigManager.cs index 1096a8268..d9ff85e19 100644 --- a/src/CoiniumServ/Configuration/IConfigManager.cs +++ b/src/CoiniumServ/Configuration/IConfigManager.cs @@ -30,8 +30,6 @@ namespace CoiniumServ.Configuration { public interface IConfigManager { - bool ConfigExists { get; } - IWebServerConfig WebServerConfig { get; } ILogConfig LogConfig { get; } diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 7429335f1..2fd33cd7c 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -69,13 +69,6 @@ static void Main(string[] args) // check if we have a valid config file. var configManager = configFactory.GetConfigManager(); - if (!configManager.ConfigExists) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Couldn't read config/config.json! Make sure you rename config/config-example.json as config/config.json."); - Console.ResetColor(); - return; - } // initialize log-manager. var logManager = objectFactory.GetLogManager(); From 5307fd60ba8cbae4770e7f4465c5d39b5b894b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 26 Jul 2014 16:57:58 +0300 Subject: [PATCH 157/230] StackConfig,WebServerConfig, StatisticsConfig, LogConfig will now set defaults if it can read from config json. Fixed a tiny bug with LogTarget where it was throwing an exception incorrectly for non-file based targets. --- .../Configuration/ConfigManager.cs | 8 ++--- src/CoiniumServ/Configuration/StackConfig.cs | 5 +-- src/CoiniumServ/Logging/ILogManager.cs | 4 +-- src/CoiniumServ/Logging/LogConfig.cs | 31 +++++++++++++++++-- src/CoiniumServ/Logging/LogManager.cs | 4 ++- src/CoiniumServ/Logging/LogTarget.cs | 8 +++-- src/CoiniumServ/Program.cs | 7 ++--- .../Server/Web/IWebServerConfig.cs | 2 +- src/CoiniumServ/Server/Web/WebServerConfig.cs | 8 ++--- .../Statistics/StatisticsConfig.cs | 8 ++--- 10 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index 85f18fddf..612e79ee4 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -25,7 +25,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Management.Instrumentation; using CoiniumServ.Coin.Config; using CoiniumServ.Factories; using CoiniumServ.Logging; @@ -50,6 +49,7 @@ public class ConfigManager:IConfigManager private readonly Dictionary _coinConfigs; // cache for loaded coin configs. private dynamic _defaultPoolConfig; + private readonly IConfigFactory _configFactory; private ILogger _logger; @@ -61,7 +61,7 @@ public ConfigManager(IConfigFactory configFactory) _coinConfigs = new Dictionary(); // dictionary of coin configurations. PoolConfigs = new List(); // list of pool configurations. - ReadGlobalConfig(); + ReadGlobalConfig(); // read the global config. } private void ReadGlobalConfig() @@ -77,9 +77,9 @@ private void ReadGlobalConfig() Environment.Exit(-1); } - LogConfig = new LogConfig(data.logging); - WebServerConfig = new WebServerConfig(data.website); StackConfig = new StackConfig(data.stack); + WebServerConfig = new WebServerConfig(data.website); + LogConfig = new LogConfig(data.logging); } public void Initialize() diff --git a/src/CoiniumServ/Configuration/StackConfig.cs b/src/CoiniumServ/Configuration/StackConfig.cs index 11c96ce32..bb9cda9e3 100644 --- a/src/CoiniumServ/Configuration/StackConfig.cs +++ b/src/CoiniumServ/Configuration/StackConfig.cs @@ -35,11 +35,8 @@ public StackConfig(dynamic config) { try { - // set the defaults; - Name = "CoiniumServ.com"; - // load the config data. - Name = config.name; + Name = string.IsNullOrEmpty(config.name) ? "CoiniumServ.com" : config.name; Valid = true; } diff --git a/src/CoiniumServ/Logging/ILogManager.cs b/src/CoiniumServ/Logging/ILogManager.cs index e76ade3b8..a135bed4e 100644 --- a/src/CoiniumServ/Logging/ILogManager.cs +++ b/src/CoiniumServ/Logging/ILogManager.cs @@ -24,7 +24,5 @@ namespace CoiniumServ.Logging { public interface ILogManager - { - void Initialize(); - } + { } } diff --git a/src/CoiniumServ/Logging/LogConfig.cs b/src/CoiniumServ/Logging/LogConfig.cs index 6dbd5ff73..c278cfde1 100644 --- a/src/CoiniumServ/Logging/LogConfig.cs +++ b/src/CoiniumServ/Logging/LogConfig.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; +using System.Dynamic; using Serilog; namespace CoiniumServ.Logging @@ -37,12 +38,18 @@ public LogConfig(dynamic config) { try { - Root = config.root; + Root = string.IsNullOrEmpty(config.root) ? "logs" : config.root; Targets = new List(); - foreach (var target in config.targets) + + if (config.targets is JsonConfig.NullExceptionPreventer) + AddDefaults(); // if we don't have any targets defined, setup a few default ones. + else { - Targets.Add(new LogTarget(target)); + foreach (var target in config.targets) + { + Targets.Add(new LogTarget(target)); + } } Valid = true; @@ -53,5 +60,23 @@ public LogConfig(dynamic config) Log.Logger.ForContext().Error(e, "Error loading logging configuration"); } } + + private void AddDefaults() + { + dynamic consoleLog = new ExpandoObject(); + consoleLog.enabled = true; + consoleLog.type = "console"; + consoleLog.level = "debug"; + + dynamic serverLog = new ExpandoObject(); + serverLog.enabled = true; + serverLog.type = "file"; + serverLog.filename = "server.log"; + serverLog.level = "information"; + serverLog.rolling = false; + + Targets.Add(new LogTarget(consoleLog)); + Targets.Add(new LogTarget(serverLog)); + } } } diff --git a/src/CoiniumServ/Logging/LogManager.cs b/src/CoiniumServ/Logging/LogManager.cs index 25adbf06b..7d0c2801f 100644 --- a/src/CoiniumServ/Logging/LogManager.cs +++ b/src/CoiniumServ/Logging/LogManager.cs @@ -44,9 +44,11 @@ public class LogManager:ILogManager public LogManager(IConfigManager configManager) { _config = configManager.LogConfig; + + Initialize(); } - public void Initialize() + private void Initialize() { // read the root folder for logs. _rootFolder = !string.IsNullOrEmpty(_config.Root) ? _config.Root : "logs"; diff --git a/src/CoiniumServ/Logging/LogTarget.cs b/src/CoiniumServ/Logging/LogTarget.cs index 1983316da..9d9e2ee48 100644 --- a/src/CoiniumServ/Logging/LogTarget.cs +++ b/src/CoiniumServ/Logging/LogTarget.cs @@ -41,8 +41,6 @@ public LogTarget(dynamic config) try { Enabled = config.enabled; - Filename = config.filename; - Rolling = config.rolling; switch ((string) config.type) { @@ -79,6 +77,12 @@ public LogTarget(dynamic config) break; } + if (Type == LogTargetType.File || Type == LogTargetType.Packet) + { + Filename = config.filename; + Rolling = config.rolling; + } + Valid = true; } catch (Exception e) diff --git a/src/CoiniumServ/Program.cs b/src/CoiniumServ/Program.cs index 2fd33cd7c..8729ceefd 100644 --- a/src/CoiniumServ/Program.cs +++ b/src/CoiniumServ/Program.cs @@ -67,12 +67,11 @@ static void Main(string[] args) ConsoleWindow.PrintBanner(); ConsoleWindow.PrintLicense(); - // check if we have a valid config file. + // load the config-manager. var configManager = configFactory.GetConfigManager(); - // initialize log-manager. - var logManager = objectFactory.GetLogManager(); - logManager.Initialize(); + // initialize log-manager as we'll need it below. + objectFactory.GetLogManager(); // print a version banner. _logger = Log.ForContext(); diff --git a/src/CoiniumServ/Server/Web/IWebServerConfig.cs b/src/CoiniumServ/Server/Web/IWebServerConfig.cs index a28355f3f..12cfdcca2 100644 --- a/src/CoiniumServ/Server/Web/IWebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/IWebServerConfig.cs @@ -39,7 +39,7 @@ public interface IWebServerConfig:IConfig /// /// port to listen for http connections. /// - Int32 Port { get; } + int Port { get; } IStatisticsConfig Statistics { get; } diff --git a/src/CoiniumServ/Server/Web/WebServerConfig.cs b/src/CoiniumServ/Server/Web/WebServerConfig.cs index 947015cdb..6d180cdfc 100644 --- a/src/CoiniumServ/Server/Web/WebServerConfig.cs +++ b/src/CoiniumServ/Server/Web/WebServerConfig.cs @@ -40,14 +40,10 @@ public WebServerConfig(dynamic config) { try { - // set the defaults; - BindInterface = "127.0.0.1"; - Port = 80; - // load the config data. Enabled = config.enabled; - BindInterface = config.bind; - Port = config.port; + BindInterface = string.IsNullOrEmpty(config.bind) ? "127.0.0.1" : config.bind; + Port = config.port == 0 ? 80 : config.port; Statistics = new StatisticsConfig(config.stats); Backend = new BackendConfig(config.backend); diff --git a/src/CoiniumServ/Statistics/StatisticsConfig.cs b/src/CoiniumServ/Statistics/StatisticsConfig.cs index a8f53b934..3a1b51974 100644 --- a/src/CoiniumServ/Statistics/StatisticsConfig.cs +++ b/src/CoiniumServ/Statistics/StatisticsConfig.cs @@ -36,13 +36,9 @@ public StatisticsConfig(dynamic config) { try { - // set the defaults; - UpdateInterval = 60; - HashrateWindow = 300; - // load the config data. - UpdateInterval = config.updateInterval; - HashrateWindow = config.hashrateWindow; + UpdateInterval = config.updateInterval == 0 ? 60 : config.updateInterval; + HashrateWindow = config.hashrateWindow == 0 ? 300 : config.hashrateWindow; Valid = true; } From bc4a0f34207ec47a994fc699674e9e116d969e0f Mon Sep 17 00:00:00 2001 From: huseyin uslu Date: Sat, 26 Jul 2014 17:18:32 +0300 Subject: [PATCH 158/230] added exception handler for nancy trying to run on a well-known port without being root --- .../Networking/Server/Http/Web/HttpServer.cs | 14 +++++++++----- src/CoiniumServ/Persistance/Redis/Redis.cs | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs index 43ed5ef4d..0e5acc711 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs @@ -23,6 +23,7 @@ using System; using System.Net; +using System.Net.Sockets; using Nancy.Bootstrapper; using Nancy.Hosting.Self; using Serilog; @@ -71,14 +72,17 @@ public bool Start() host.Start(); IsListening = true; } - catch (InvalidOperationException e) // nancy requires elevated privileges to run on port 80. - { - _logger.Error("Need elevated privileges to listen on port {0}. Try running as administrator or root.", Port); + catch (InvalidOperationException) { // nancy requires elevated privileges to run on port well known ports - thrown when we are on Windows. + _logger.Error("Need elevated privileges to listen on port {0}. Try running as administrator.", Port); IsListening = false; return false; } - catch (HttpListenerException e) - { + catch(SocketException) { // nancy requires elevated privileges to run on port well known ports - thrown when we are on mono. + _logger.Error("Need elevated privileges to listen on port {0}. Try running as root.", Port); + IsListening = false; + return false; + } + catch (HttpListenerException) { _logger.Error("Can not listen on requested interface: {0:l}",BindIP); IsListening = false; return false; diff --git a/src/CoiniumServ/Persistance/Redis/Redis.cs b/src/CoiniumServ/Persistance/Redis/Redis.cs index ef9d6cc6b..80f6e379c 100644 --- a/src/CoiniumServ/Persistance/Redis/Redis.cs +++ b/src/CoiniumServ/Persistance/Redis/Redis.cs @@ -461,7 +461,7 @@ private void Initialize() } catch (Exception e) { - _logger.Error("Storage initialization failed: {0:l}:{1} - {2}.", endpoint.Host, endpoint.Port, e.InnerException.Message); + _logger.Error("Storage initialization failed: {0:l}:{1} - {2:l}.", endpoint.Host, endpoint.Port, e.InnerException.Message); } } From e938052fb66f9ef69ddcca6ebe172a829f7644b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sat, 26 Jul 2014 22:08:34 +0300 Subject: [PATCH 159/230] Removed coin-config caches, as most of time we won't need to load a coin config more then once. Coin-configs are now correctly valided and if one fails the validation referring pool config will be also skipped. --- src/CoiniumServ/Coin/Config/CoinConfig.cs | 5 ++++- .../Configuration/ConfigManager.cs | 22 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index 79bd6b962..e5bfd68d1 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -43,7 +43,10 @@ public CoinConfig(dynamic config) Algorithm = config.algorithm; Options = config; - Valid = true; + if (Name == null || Symbol == null || Algorithm == null) + Valid = false; + else + Valid = true; } catch (Exception e) { diff --git a/src/CoiniumServ/Configuration/ConfigManager.cs b/src/CoiniumServ/Configuration/ConfigManager.cs index 612e79ee4..8be195ffd 100644 --- a/src/CoiniumServ/Configuration/ConfigManager.cs +++ b/src/CoiniumServ/Configuration/ConfigManager.cs @@ -46,8 +46,6 @@ public class ConfigManager:IConfigManager private const string PoolConfigRoot = "config/pools"; // root of pool configs. private const string CoinConfigRoot = "config/coins"; // root of pool configs. - private readonly Dictionary _coinConfigs; // cache for loaded coin configs. - private dynamic _defaultPoolConfig; private readonly IConfigFactory _configFactory; @@ -58,7 +56,6 @@ public ConfigManager(IConfigFactory configFactory) { _configFactory = configFactory; - _coinConfigs = new Dictionary(); // dictionary of coin configurations. PoolConfigs = new List(); // list of pool configurations. ReadGlobalConfig(); // read the global config. @@ -112,6 +109,12 @@ private void LoadPoolConfigs() var coinName = Path.GetFileNameWithoutExtension(data.coin); var coinConfig = GetCoinConfig(coinName); + if (!coinConfig.Valid) + { + _logger.Error("coins/{0:l}.json doesnt't contain a valid configuration, skipping pool configuration: pools/{1:l}.json", coinName, filename); + continue; + } + if(_defaultPoolConfig != null) data = JsonConfig.Merger.Merge(data, _defaultPoolConfig); // if we do have a default.json config, merge with it. @@ -124,16 +127,11 @@ private void LoadPoolConfigs() private ICoinConfig GetCoinConfig(string name) { - if (!_coinConfigs.ContainsKey(name)) - { - var fileName = string.Format("{0}/{1}.json", CoinConfigRoot, name); - var data = JsonConfigReader.Read(fileName); - var coinConfig = _configFactory.GetCoinConfig(data); - - _coinConfigs.Add(name, coinConfig); - } + var fileName = string.Format("{0}/{1}.json", CoinConfigRoot, name); + var data = JsonConfigReader.Read(fileName); + var coinConfig = _configFactory.GetCoinConfig(data); - return _coinConfigs[name]; + return coinConfig; } } } From be371ad8b77c4d9087f2ef46d29635733f72c312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sun, 3 Aug 2014 17:53:54 +0300 Subject: [PATCH 160/230] Added reddcoin donation address. Added a better web-exception error message to DaemonBase.cs. Removed unhandled exception handler from httpserver.cs. Removed any unnecissary generic exception handler from jobmanager.cs. Added rpc-exception handler to MinerManager.cs:Authenticate(). Added rpc-exception handler to PaymentProcessor.cs:ValidatePoolAddress() Added rpc-exception handler to PerPool.cs:ReadCoinData() Moved PrintPoolInfo to InitDaemon in Pool.cs. --- src/CoiniumServ/Daemon/DaemonBase.cs | 2 +- .../Daemon/Exceptions/RpcException.cs | 2 +- src/CoiniumServ/Jobs/Manager/JobManager.cs | 5 -- src/CoiniumServ/Miners/MinerManager.cs | 10 ++- .../Networking/Server/Http/Web/HttpServer.cs | 10 --- src/CoiniumServ/Payments/PaymentProcessor.cs | 20 +++-- src/CoiniumServ/Pools/Pool.cs | 84 ++++++++++--------- src/CoiniumServ/Statistics/PerPool.cs | 18 +++- src/CoiniumServ/Utils/ConsoleWindow.cs | 7 +- 9 files changed, 87 insertions(+), 71 deletions(-) diff --git a/src/CoiniumServ/Daemon/DaemonBase.cs b/src/CoiniumServ/Daemon/DaemonBase.cs index 524345d9f..b919337e4 100644 --- a/src/CoiniumServ/Daemon/DaemonBase.cs +++ b/src/CoiniumServ/Daemon/DaemonBase.cs @@ -139,7 +139,7 @@ private HttpWebRequest MakeHttpRequest(DaemonRequest walletRequest) } catch (WebException exception) { - throw new RpcException("An unknown web exception occured while trying to send the JSON request.", exception); + throw new RpcException(string.Format("json-rpc exception: {0}", exception.Message), exception); } return webRequest; diff --git a/src/CoiniumServ/Daemon/Exceptions/RpcException.cs b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs index 26b62531b..3e2098f5b 100644 --- a/src/CoiniumServ/Daemon/Exceptions/RpcException.cs +++ b/src/CoiniumServ/Daemon/Exceptions/RpcException.cs @@ -32,7 +32,7 @@ public class RpcException : Exception public RpcException(string message, Exception innerException) : base(message, innerException) { - Code = Int32.MinValue; + Code = 0; } public RpcException(DaemonErrorResponse response) : diff --git a/src/CoiniumServ/Jobs/Manager/JobManager.cs b/src/CoiniumServ/Jobs/Manager/JobManager.cs index 3e6ac16a6..81985fe05 100644 --- a/src/CoiniumServ/Jobs/Manager/JobManager.cs +++ b/src/CoiniumServ/Jobs/Manager/JobManager.cs @@ -188,11 +188,6 @@ private IJob GetNewJob() _logger.Error("New job creation failed: {0:l}", rpcException.Message); return null; } - catch (Exception e) - { - _logger.Error(e, "New job creation failed:"); - return null; - } } /// diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index 0bd6cafe3..dd93baff8 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.Linq; using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Pools; using CoiniumServ.Pools.Config; @@ -107,7 +108,14 @@ public void Remove(IConnection connection) public void Authenticate(IMiner miner) { if (_minerConfig.ValidateUsername) // should we validate miner username? - miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; // if so validate it against coin daemon as an address. + try + { + miner.Authenticated = _daemonClient.ValidateAddress(miner.Username).IsValid; // if so validate it against coin daemon as an address. + } + catch (RpcException e) + { + miner.Authenticated = false; + } else miner.Authenticated = true; // else just accept him. diff --git a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs index 0e5acc711..f18a169c7 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs @@ -62,7 +62,6 @@ public bool Start() var uri = new Uri(string.Format("http://{0}:{1}", BindIP, Port)); var hostConfiguration = new HostConfiguration(); - hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; hostConfiguration.UrlReservations.CreateAutomatically = true; var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); @@ -97,15 +96,6 @@ public bool Stop() throw new NotImplementedException(); } - /// - /// Unhandled exception callback for nancy based web-server. - /// - /// - private void UnhandledExceptionHandler(Exception exception) - { - _logger.Error("Web-server: {0}", exception); - } - public void Dispose() { Stop(); diff --git a/src/CoiniumServ/Payments/PaymentProcessor.cs b/src/CoiniumServ/Payments/PaymentProcessor.cs index 76c71c6a9..db242ca93 100644 --- a/src/CoiniumServ/Payments/PaymentProcessor.cs +++ b/src/CoiniumServ/Payments/PaymentProcessor.cs @@ -332,14 +332,22 @@ private void GetPoolAccount() private bool ValidatePoolAddress() { - var result = _daemonClient.ValidateAddress(_walletConfig.Adress); + try + { + var result = _daemonClient.ValidateAddress(_walletConfig.Adress); - // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. - if (result.IsValid && result.IsMine) - return true; + // make sure the pool central wallet address is valid and belongs to the daemon we are connected to. + if (result.IsValid && result.IsMine) + return true; - _logger.Error("Halted as daemon we are connected to does not own the pool address: {0:l}.", _walletConfig.Adress); - return false; + _logger.Error("Halted as daemon we are connected to does not own the pool address: {0:l}.",_walletConfig.Adress); + return false; + } + catch (RpcException e) + { + _logger.Error("Halted as we can not connect to configured coin daemon: {0:l}", e.Message); + return false; + } } private bool DeterminePrecision() diff --git a/src/CoiniumServ/Pools/Pool.cs b/src/CoiniumServ/Pools/Pool.cs index f6fa23168..da2627a67 100644 --- a/src/CoiniumServ/Pools/Pool.cs +++ b/src/CoiniumServ/Pools/Pool.cs @@ -88,30 +88,69 @@ public Pool( // TODO: validate pool central wallet & rewards within the startup. - Config = poolConfig; + Config = poolConfig; _logger = Log.ForContext().ForContext("Component", Config.Coin.Name); GenerateInstanceId(); + InitDaemon(); InitManagers(); InitServers(); - PrintPoolInfo(); } private void InitDaemon() { if (Config.Daemon == null || Config.Daemon.Valid == false) + { _logger.Error("Coin daemon configuration is not valid!"); + return; + } _daemonClient = _objectFactory.GetDaemonClient(Config); + + try + { + var info = _daemonClient.GetInfo(); + + _logger.Information("Coin symbol: {0:l} algorithm: {1:l} " + + "Coin version: {2} protocol: {3} wallet: {4} " + + "Daemon network: {5:l} peers: {6} blocks: {7} errors: {8:l} ", + Config.Coin.Symbol, + Config.Coin.Algorithm, + info.Version, + info.ProtocolVersion, + info.WalletVersion, + info.Testnet ? "testnet" : "mainnet", + info.Connections, info.Blocks, + string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors); + } + catch (RpcException e) + { + _logger.Error("Can not read getinfo(): {0:l}", e.Message); + return; + } + + try + { + _hashAlgorithm = _objectFactory.GetHashAlgorithm(Config.Coin.Algorithm); + + // try reading mininginfo(), some coins may not support it. + var miningInfo = _daemonClient.GetMiningInfo(); + + _logger.Information("Network difficulty: {0:0.00000000} block difficulty: {1:0.00} Network hashrate: {2:l} ", + miningInfo.Difficulty, + miningInfo.Difficulty * _hashAlgorithm.Multiplier, + miningInfo.NetworkHashps.GetReadableHashrate()); + } + catch (RpcException e) + { + _logger.Error("Can not read mininginfo() - the coin may not support the request: {0:l}", e.Message); + } } private void InitManagers() { - // init the algorithm - _hashAlgorithm = _objectFactory.GetHashAlgorithm(Config.Coin.Algorithm); - var storage = _objectFactory.GetStorage(Storages.Redis, Config); var paymentProcessor = _objectFactory.GetPaymentProcessor(Config, _daemonClient, storage); @@ -140,9 +179,6 @@ private void InitServers() { _servers = new Dictionary(); - // TODO: we don't need here a server config list as a pool can host only one instance of stratum and one vanilla server. - // we must be dictative here, using a server list may cause situations we don't want (multiple stratum configs etc..) - if (Config.Stratum != null && Config.Stratum.Enabled) { var stratumServer = _objectFactory.GetMiningServer("Stratum", Config, this, _minerManager, _jobManager, _banningManager); @@ -163,38 +199,6 @@ private void InitServers() } } - private void PrintPoolInfo() - { - var info = _daemonClient.GetInfo(); - - _logger.Information("Coin symbol: {0:l} algorithm: {1:l} " + - "Coin version: {2} protocol: {3} wallet: {4} " + - "Daemon network: {5:l} peers: {6} blocks: {7} errors: {8:l} ", - Config.Coin.Symbol, - Config.Coin.Algorithm, - info.Version, - info.ProtocolVersion, - info.WalletVersion, - info.Testnet ? "testnet" : "mainnet", - info.Connections, info.Blocks, - string.IsNullOrEmpty(info.Errors) ? "none" : info.Errors); - - try - { - // try reading mininginfo(), some coins may not support it. - var miningInfo = _daemonClient.GetMiningInfo(); - - _logger.Information("Network difficulty: {0:0.00000000} block difficulty: {1:0.00} Network hashrate: {2:l} ", - miningInfo.Difficulty, - miningInfo.Difficulty*_hashAlgorithm.Multiplier, - miningInfo.NetworkHashps.GetReadableHashrate()); - } - catch (RpcException e) - { - _logger.Error("Can not read mininginfo() as coin daemon doesn't support it"); - } - } - public void Start() { if (!Config.Valid) diff --git a/src/CoiniumServ/Statistics/PerPool.cs b/src/CoiniumServ/Statistics/PerPool.cs index e781786b7..bc3988a4c 100644 --- a/src/CoiniumServ/Statistics/PerPool.cs +++ b/src/CoiniumServ/Statistics/PerPool.cs @@ -27,6 +27,7 @@ using CoiniumServ.Configuration; using CoiniumServ.Cryptology.Algorithms; using CoiniumServ.Daemon; +using CoiniumServ.Daemon.Exceptions; using CoiniumServ.Miners; using CoiniumServ.Persistance; using CoiniumServ.Pools.Config; @@ -108,10 +109,19 @@ private void ReadHashrate() private void ReadCoinData() { - var miningInfo = _daemonClient.GetMiningInfo(); - NetworkHashrate = miningInfo.NetworkHashps; - Difficulty = miningInfo.Difficulty; - CurrentBlock = miningInfo.Blocks; + try + { + var miningInfo = _daemonClient.GetMiningInfo(); + NetworkHashrate = miningInfo.NetworkHashps; + Difficulty = miningInfo.Difficulty; + CurrentBlock = miningInfo.Blocks; + } + catch (RpcException e) + { + NetworkHashrate = 0; + Difficulty = 0; + CurrentBlock = -1; + } } public object GetResponseObject() diff --git a/src/CoiniumServ/Utils/ConsoleWindow.cs b/src/CoiniumServ/Utils/ConsoleWindow.cs index e6d61e75d..d8b6cccde 100644 --- a/src/CoiniumServ/Utils/ConsoleWindow.cs +++ b/src/CoiniumServ/Utils/ConsoleWindow.cs @@ -59,9 +59,10 @@ public static void PrintLicense() Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("You can contribute the development of the project by donating;"); Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine("BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D"); - Console.WriteLine("LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa"); - Console.WriteLine("DOGE: DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr"); + Console.WriteLine(" BTC : 18qqrtR4xHujLKf9oqiCsjmwmH5vGpch4D"); + Console.WriteLine(" LTC : LMXfRb3w8cMUBfqZb6RUkFTPaT6vbRozPa"); + Console.WriteLine(" DOGE: DM8FW8REMHj3P4xtcMWDn33ccjikCWJnQr"); + Console.WriteLine(" RDD : Rb9kcLs96VDHTmiXVjcWC2RBsfCJ73UQyr"); Console.WriteLine(); Console.ResetColor(); } From a24d48a63e881966f672bfab630ce44f1970f79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sun, 3 Aug 2014 19:39:41 +0300 Subject: [PATCH 161/230] Fixed default values for BanConfig, DaemonConfig, JobConfig, MetaConfig, MinerConfig, PaymentConfig, RedisConfig, StratumServerConfig, VanillaServerConfig, VardiffConfig. --- src/CoiniumServ/Banning/BanConfig.cs | 14 ++++---------- src/CoiniumServ/Coin/Config/CoinConfig.cs | 2 +- src/CoiniumServ/Daemon/Config/DaemonConfig.cs | 5 +---- src/CoiniumServ/Jobs/Manager/JobConfig.cs | 8 ++------ src/CoiniumServ/Miners/MetaConfig.cs | 7 +++---- src/CoiniumServ/Miners/MinerConfig.cs | 6 +----- src/CoiniumServ/Payments/PaymentConfig.cs | 8 ++------ .../Persistance/Redis/RedisConfig.cs | 11 +++-------- src/CoiniumServ/Pools/Config/PoolConfig.cs | 4 +++- .../Stratum/Config/StratumServerConfig.cs | 7 ++----- .../Vanilla/Config/VanillaServerConfig.cs | 5 +---- src/CoiniumServ/Vardiff/VardiffConfig.cs | 17 +++++------------ 12 files changed, 28 insertions(+), 66 deletions(-) diff --git a/src/CoiniumServ/Banning/BanConfig.cs b/src/CoiniumServ/Banning/BanConfig.cs index a9bbc93d7..81df6caa1 100644 --- a/src/CoiniumServ/Banning/BanConfig.cs +++ b/src/CoiniumServ/Banning/BanConfig.cs @@ -39,18 +39,12 @@ public BanConfig(dynamic config) { try { - // set the defaults; - Duration = 600; - InvalidPercent = 50; - CheckThreshold = 100; - PurgeInterval = 300; - // load the config data. Enabled = config.enabled; - Duration = config.duration; - InvalidPercent = config.invalidPercent; - CheckThreshold = config.checkThreshold; - PurgeInterval = config.purgeInterval; + Duration = config.duration == 0 ? 600 : config.duration; + InvalidPercent = config.invalidPercent == 0 ? 50 : config.invalidPercent; + CheckThreshold = config.checkThreshold == 0 ? 100 : config.checkThreshold; + PurgeInterval = config.purgeInterval == 0 ? 300 : config.purgeInterval; Valid = true; } diff --git a/src/CoiniumServ/Coin/Config/CoinConfig.cs b/src/CoiniumServ/Coin/Config/CoinConfig.cs index e5bfd68d1..fa5ad6243 100644 --- a/src/CoiniumServ/Coin/Config/CoinConfig.cs +++ b/src/CoiniumServ/Coin/Config/CoinConfig.cs @@ -43,7 +43,7 @@ public CoinConfig(dynamic config) Algorithm = config.algorithm; Options = config; - if (Name == null || Symbol == null || Algorithm == null) + if (Name == null || Symbol == null || Algorithm == null) // make sure we have valid name, symbol and algorithm data. Valid = false; else Valid = true; diff --git a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs index 9f9da4a4d..42ead0978 100644 --- a/src/CoiniumServ/Daemon/Config/DaemonConfig.cs +++ b/src/CoiniumServ/Daemon/Config/DaemonConfig.cs @@ -42,11 +42,8 @@ public DaemonConfig(dynamic config) { try { - // set the defaults; - Host = "0.0.0.0"; - // load the config data. - Host = config.host; + Host = string.IsNullOrEmpty(config.host) ? "0.0.0.0" : config.host; Port = config.port; Username = config.username; Password = config.password; diff --git a/src/CoiniumServ/Jobs/Manager/JobConfig.cs b/src/CoiniumServ/Jobs/Manager/JobConfig.cs index dcf15acaf..9aaf46e4c 100644 --- a/src/CoiniumServ/Jobs/Manager/JobConfig.cs +++ b/src/CoiniumServ/Jobs/Manager/JobConfig.cs @@ -36,13 +36,9 @@ public JobConfig(dynamic config) { try { - // set the defaults; - BlockRefreshInterval = 1000; - RebroadcastTimeout = 55; - // load the config data. - BlockRefreshInterval = config.blockRefreshInterval; - RebroadcastTimeout = config.rebroadcastTimeout; + BlockRefreshInterval = config.blockRefreshInterval == 0 ? 1000 : config.blockRefreshInterval; + RebroadcastTimeout = config.rebroadcastTimeout == 0 ? 55 : config.rebroadcastTimeout; Valid = true; } diff --git a/src/CoiniumServ/Miners/MetaConfig.cs b/src/CoiniumServ/Miners/MetaConfig.cs index 33229ae73..803be8801 100644 --- a/src/CoiniumServ/Miners/MetaConfig.cs +++ b/src/CoiniumServ/Miners/MetaConfig.cs @@ -35,11 +35,10 @@ public MetaConfig(dynamic config) { try { - // set the defaults; - MOTD = "Welcome to CoiniumServ pool, enjoy your stay! - http://www.coinumserv.com"; - // load the config data. - MOTD = config.motd; + MOTD = string.IsNullOrEmpty(config.motd) + ? "Welcome to CoiniumServ pool, enjoy your stay! - http://www.coinumserv.com" + : config.motd; Valid = true; } diff --git a/src/CoiniumServ/Miners/MinerConfig.cs b/src/CoiniumServ/Miners/MinerConfig.cs index 93d3f23fd..58908597d 100644 --- a/src/CoiniumServ/Miners/MinerConfig.cs +++ b/src/CoiniumServ/Miners/MinerConfig.cs @@ -36,13 +36,9 @@ public MinerConfig(dynamic config) { try { - // set the defaults; - ValidateUsername = true; - Timeout = 300; - // load the config data. ValidateUsername = config.validateUsername; - Timeout = config.timeout; + Timeout = config.timeout == 0 ? 300 : config.timeout; Valid = true; } diff --git a/src/CoiniumServ/Payments/PaymentConfig.cs b/src/CoiniumServ/Payments/PaymentConfig.cs index 40491bed5..6a1ec4e2d 100644 --- a/src/CoiniumServ/Payments/PaymentConfig.cs +++ b/src/CoiniumServ/Payments/PaymentConfig.cs @@ -37,14 +37,10 @@ public PaymentConfig(dynamic config) { try { - // set the defaults; - Interval = 60; - Minimum = 0.01; - // load the config data. Enabled = config.enabled; - Interval = config.interval; - Minimum = config.minimum; + Interval = config.interval == 0 ? 60 : config.interval; + Minimum = config.minimum == 0 ? 0.01 : config.minimum; Valid = true; } diff --git a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs index 46c271e56..e0a9e714d 100644 --- a/src/CoiniumServ/Persistance/Redis/RedisConfig.cs +++ b/src/CoiniumServ/Persistance/Redis/RedisConfig.cs @@ -39,17 +39,12 @@ public RedisConfig(dynamic config) { try { - // set the defaults; - Host = "127.0.0.1"; - Port = 6379; - DatabaseId = 0; - // load the config data. Enabled = config.enabled; - Host = config.host; - Port = config.port; + Host = string.IsNullOrEmpty(config.host) ? "127.0.0.1" : config.host; + Port = config.port == 0 ? 6379 : config.port; Password = config.password; - DatabaseId = config.databaseId; + DatabaseId = config.databaseId; } catch (Exception e) { diff --git a/src/CoiniumServ/Pools/Config/PoolConfig.cs b/src/CoiniumServ/Pools/Config/PoolConfig.cs index 673896674..27bc84176 100644 --- a/src/CoiniumServ/Pools/Config/PoolConfig.cs +++ b/src/CoiniumServ/Pools/Config/PoolConfig.cs @@ -70,7 +70,9 @@ public PoolConfig(dynamic config, ICoinConfig coinConfig) if (Enabled == false) // if the configuration is not enabled return; // just skip reading rest of the parameters. - Coin = coinConfig; + Coin = coinConfig; // assign the coin config. + + // load the sections. Daemon = new DaemonConfig(config.daemon); Meta = new MetaConfig(config.meta); Wallet = new WalletConfig(config.wallet); diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index 80e9f1b68..c88421e3c 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -44,14 +44,11 @@ public StratumServerConfig(dynamic config) { try { - // set the defaults; - BindInterface = "0.0.0.0"; - // load the config data. Enabled = config.enabled; - BindInterface = config.bind; + BindInterface = string.IsNullOrEmpty(config.bind) ? "0.0.0.0" : config.bind; Port = config.port; - Diff = config.diff; + Diff = config.diff == 0 ? 16 : config.diff; Vardiff = new VardiffConfig(config.vardiff); Valid = true; diff --git a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs index 468c47bba..feae21a60 100644 --- a/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Vanilla/Config/VanillaServerConfig.cs @@ -40,12 +40,9 @@ public VanillaServerConfig(dynamic config) { try { - // set the defaults; - BindInterface = "0.0.0.0"; - // load the config data. Enabled = config.enabled; - BindInterface = config.bind; + BindInterface = string.IsNullOrEmpty(config.bind) ? "0.0.0.0" : config.bind; Port = config.port; Valid = true; diff --git a/src/CoiniumServ/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Vardiff/VardiffConfig.cs index 80306fb68..5cafdc6a6 100644 --- a/src/CoiniumServ/Vardiff/VardiffConfig.cs +++ b/src/CoiniumServ/Vardiff/VardiffConfig.cs @@ -40,20 +40,13 @@ public VardiffConfig(dynamic config) { try { - // set the defaults; - MinimumDifficulty = 8; - MaximumDifficulty = 512; - TargetTime = 15; - RetargetTime = 90; - VariancePercent = 30; - // load the config data. Enabled = config.enabled; - MinimumDifficulty = config.minDiff; - MaximumDifficulty = config.maxDiff; - TargetTime = config.targetTime; - RetargetTime = config.retargetTime; - VariancePercent = config.variancePercent; + MinimumDifficulty = config.minDiff == 0 ? 8: config.minDiff; + MaximumDifficulty = config.maxDiff == 0? 512: config.maxDiff; + TargetTime = config.targetTime == 0 ? 15 : config.targetTime; + RetargetTime = config.retargetTime == 0 ? 90 : config.retargetTime; + VariancePercent = config.variancePercent == 0 ? 30 : config.variancePercent; Valid = true; } From 409dc7846436173b623c4f5c207878c91d28b990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Sun, 3 Aug 2014 23:18:43 +0300 Subject: [PATCH 162/230] Changed IStratumServerConfig.cs:Diff, VardiffConfig.cs:MinDiff and MaxDiff to a float so X11 coins can be used now too. Fixed a bug within StratumMiner.cs where miner default difficulty was not using configuration based value (fixes #313). --- src/CoiniumServ/Miners/MinerManager.cs | 21 ++++++++++++++++--- .../Stratum/Config/IStratumServerConfig.cs | 3 +-- .../Stratum/Config/StratumServerConfig.cs | 5 +++-- .../Server/Mining/Stratum/StratumMiner.cs | 3 ++- src/CoiniumServ/Vardiff/IVardiffConfig.cs | 4 ++-- src/CoiniumServ/Vardiff/VardiffConfig.cs | 8 +++---- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/CoiniumServ/Miners/MinerManager.cs b/src/CoiniumServ/Miners/MinerManager.cs index dd93baff8..3f5efec5b 100644 --- a/src/CoiniumServ/Miners/MinerManager.cs +++ b/src/CoiniumServ/Miners/MinerManager.cs @@ -31,7 +31,6 @@ using CoiniumServ.Pools.Config; using CoiniumServ.Server.Mining.Stratum; using CoiniumServ.Server.Mining.Vanilla; -using Metrics; using Serilog; namespace CoiniumServ.Miners @@ -78,7 +77,14 @@ public IMiner GetByConnection(IConnection connection) public T Create(IPool pool) where T : IVanillaMiner { - var instance = Activator.CreateInstance(typeof(T), new object[] { _counter++, pool, this }); // create an instance of the miner. + var @params = new object[] + { + _counter++, + pool, + this + }; + + var instance = Activator.CreateInstance(typeof(T), @params); // create an instance of the miner. var miner = (IVanillaMiner)instance; _miners.Add(miner.Id, miner); // add it to our collection. @@ -87,7 +93,16 @@ public T Create(IPool pool) where T : IVanillaMiner public T Create(UInt32 extraNonce, IConnection connection, IPool pool) where T : IStratumMiner { - var instance = Activator.CreateInstance(typeof(T), new object[] { _counter++, extraNonce, connection, pool, this }); // create an instance of the miner. + var @params = new object[] + { + _counter++, + extraNonce, + connection, + pool, + this + }; + + var instance = Activator.CreateInstance(typeof(T), @params); // create an instance of the miner. var miner = (IStratumMiner)instance; _miners.Add(miner.Id, miner); // add it to our collection. diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs index 3620b32c8..4ee93096c 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/IStratumServerConfig.cs @@ -21,7 +21,6 @@ // #endregion -using System; using CoiniumServ.Vardiff; namespace CoiniumServ.Server.Mining.Stratum.Config @@ -31,7 +30,7 @@ public interface IStratumServerConfig : IServerConfig /// /// default difficulty assigned to newly connected miners. /// - Int32 Diff { get; } + float Diff { get; } /// /// vardiff configuration. diff --git a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs index c88421e3c..30d3c2c53 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/Config/StratumServerConfig.cs @@ -37,7 +37,8 @@ public class StratumServerConfig:IStratumServerConfig public Int32 Port { get; private set; } - public Int32 Diff { get; private set; } + public float Diff { get; private set; } + public IVardiffConfig Vardiff { get; private set; } public StratumServerConfig(dynamic config) @@ -48,7 +49,7 @@ public StratumServerConfig(dynamic config) Enabled = config.enabled; BindInterface = string.IsNullOrEmpty(config.bind) ? "0.0.0.0" : config.bind; Port = config.port; - Diff = config.diff == 0 ? 16 : config.diff; + Diff = config.diff == 0 ? 16 : (float)config.diff; Vardiff = new VardiffConfig(config.vardiff); Valid = true; diff --git a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs index f03a79567..d48dfc0ec 100644 --- a/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs +++ b/src/CoiniumServ/Server/Mining/Stratum/StratumMiner.cs @@ -29,6 +29,7 @@ using CoiniumServ.Miners; using CoiniumServ.Networking.Server.Sockets; using CoiniumServ.Pools; +using CoiniumServ.Server.Mining.Stratum.Config; using CoiniumServ.Server.Mining.Stratum.Errors; using CoiniumServ.Server.Mining.Stratum.Notifications; using CoiniumServ.Server.Mining.Stratum.Service; @@ -105,7 +106,7 @@ public StratumMiner(int id, UInt32 extraNonce, IConnection connection, IPool poo _minerManager = minerManager; Pool = pool; - Difficulty = 16; // set miner difficulty. + Difficulty = pool.Config.Stratum.Diff; // set miner difficulty. Subscribed = false; // miner has to subscribe. Authenticated = false; // miner has to authenticate. diff --git a/src/CoiniumServ/Vardiff/IVardiffConfig.cs b/src/CoiniumServ/Vardiff/IVardiffConfig.cs index 65cdef2a8..1d791fb28 100644 --- a/src/CoiniumServ/Vardiff/IVardiffConfig.cs +++ b/src/CoiniumServ/Vardiff/IVardiffConfig.cs @@ -32,12 +32,12 @@ public interface IVardiffConfig : IConfig /// /// minimum difficulty that can be assigned to miners. /// - int MinimumDifficulty { get; } + float MinimumDifficulty { get; } /// /// maximum difficulty that can be assigned to miners. /// - int MaximumDifficulty { get; } + float MaximumDifficulty { get; } /// /// try to get a single share per this many seconds from miner. diff --git a/src/CoiniumServ/Vardiff/VardiffConfig.cs b/src/CoiniumServ/Vardiff/VardiffConfig.cs index 5cafdc6a6..c4da3d265 100644 --- a/src/CoiniumServ/Vardiff/VardiffConfig.cs +++ b/src/CoiniumServ/Vardiff/VardiffConfig.cs @@ -29,8 +29,8 @@ namespace CoiniumServ.Vardiff public class VardiffConfig:IVardiffConfig { public bool Enabled { get; private set; } - public int MinimumDifficulty { get; private set; } - public int MaximumDifficulty { get; private set; } + public float MinimumDifficulty { get; private set; } + public float MaximumDifficulty { get; private set; } public int TargetTime { get; private set; } public int RetargetTime { get; private set; } public int VariancePercent { get; private set; } @@ -42,8 +42,8 @@ public VardiffConfig(dynamic config) { // load the config data. Enabled = config.enabled; - MinimumDifficulty = config.minDiff == 0 ? 8: config.minDiff; - MaximumDifficulty = config.maxDiff == 0? 512: config.maxDiff; + MinimumDifficulty = config.minDiff == 0 ? 8: (float)config.minDiff; + MaximumDifficulty = config.maxDiff == 0 ? 512 : (float)config.maxDiff; TargetTime = config.targetTime == 0 ? 15 : config.targetTime; RetargetTime = config.retargetTime == 0 ? 90 : config.retargetTime; VariancePercent = config.variancePercent == 0 ? 30 : config.variancePercent; From c92ead7054813050e8760028ab3d62b44ced6588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20Uslu?= Date: Mon, 4 Aug 2014 00:05:50 +0300 Subject: [PATCH 163/230] Improved nancy view models. Updated dependencies; metrics.net, nancy.customerrors, nancy.metrics, json.net, serilog Added back unhandled exception handler for nancy webserver. --- src/CoiniumServ/CoiniumServ.csproj | 21 +++++------ .../Networking/Server/Http/Web/HttpServer.cs | 10 ++++++ src/CoiniumServ/Server/Web/Modules/Index.cs | 14 +++----- .../Models/{Error.cs => ErrorModel.cs} | 4 ++- .../Server/Web/Modules/Models/IndexModel.cs | 36 +++++++++++++++++++ .../Server/Web/Modules/Models/PoolModel.cs | 32 +++++++++++++++++ src/CoiniumServ/Server/Web/Modules/Pool.cs | 17 ++++----- src/CoiniumServ/packages.config | 10 +++--- src/CoiniumServ/web/default/index.cshtml | 2 +- src/CoiniumServ/web/default/layout.cshtml | 4 +-- src/CoiniumServ/web/default/pool.cshtml | 28 +++++++-------- 11 files changed, 126 insertions(+), 52 deletions(-) rename src/CoiniumServ/Server/Web/Modules/Models/{Error.cs => ErrorModel.cs} (94%) create mode 100644 src/CoiniumServ/Server/Web/Modules/Models/IndexModel.cs create mode 100644 src/CoiniumServ/Server/Web/Modules/Models/PoolModel.cs diff --git a/src/CoiniumServ/CoiniumServ.csproj b/src/CoiniumServ/CoiniumServ.csproj index 25c86da2a..e9208ea2b 100644 --- a/src/CoiniumServ/CoiniumServ.csproj +++ b/src/CoiniumServ/CoiniumServ.csproj @@ -64,15 +64,15 @@ False - ..\..\build\packages\Metrics.NET.0.1.9\lib\net45\Metrics.dll + ..\..\build\packages\Metrics.NET.0.1.10\lib\net45\Metrics.dll False ..\..\build\packages\Nancy.0.23.2\lib\net40\Nancy.dll - + False - ..\..\build\packages\Nancy.CustomErrors.1.0.4.0\lib\net40\Nancy.CustomErrors.dll + ..\..\build\packages\Nancy.CustomErrors.1.0.5.0\lib\net40\Nancy.CustomErrors.dll False @@ -80,7 +80,7 @@ False - ..\..\build\packages\NancyFx.Metrics.0.1.9\lib\net45\Nancy.Metrics.dll + ..\..\build\packages\NancyFx.Metrics.0.1.10\lib\net45\Nancy.Metrics.dll False @@ -88,15 +88,14 @@ False - ..\..\build\packages\Newtonsoft.Json.6.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\build\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll False - ..\..\build\packages\Serilog.1.3.39\lib\net45\Serilog.dll + ..\..\build\packages\Serilog.1.3.42\lib\net45\Serilog.dll - - False - ..\..\build\packages\Serilog.1.3.39\lib\net45\Serilog.FullNetFx.dll + + ..\..\build\packages\Serilog.1.3.42\lib\net45\Serilog.FullNetFx.dll False @@ -152,6 +151,8 @@ + + @@ -219,7 +220,7 @@ - + diff --git a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs index f18a169c7..8bea6e069 100644 --- a/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs +++ b/src/CoiniumServ/Networking/Server/Http/Web/HttpServer.cs @@ -63,6 +63,7 @@ public bool Start() var hostConfiguration = new HostConfiguration(); hostConfiguration.UrlReservations.CreateAutomatically = true; + hostConfiguration.UnhandledExceptionCallback += UnhandledExceptionHandler; var host = new NancyHost(_webBootstrapper, hostConfiguration, uri); @@ -96,6 +97,15 @@ public bool Stop() throw new NotImplementedException(); } + /// + /// Unhandled exception callback for nancy based web-server. + /// + /// + private void UnhandledExceptionHandler(Exception exception) + { + _logger.Error("Unhandled web-server exception: {0:l}", exception.Message); + } + public void Dispose() { Stop(); diff --git a/src/CoiniumServ/Server/Web/Modules/Index.cs b/src/CoiniumServ/Server/Web/Modules/Index.cs index 465c861ed..c134b64bf 100644 --- a/src/CoiniumServ/Server/Web/Modules/Index.cs +++ b/src/CoiniumServ/Server/Web/Modules/Index.cs @@ -21,8 +21,9 @@ // #endregion -using System.Collections.Generic; +using CoiniumServ.Configuration; using CoiniumServ.Pools; +using CoiniumServ.Server.Web.Modules.Models; using CoiniumServ.Statistics; using Nancy; @@ -30,20 +31,13 @@ namespace CoiniumServ.Server.Web.Modules { public class IndexModule : NancyModule { - public IndexModule(IPoolManager poolManager, IStatistics statistics) + public IndexModule(IPoolManager poolManager, IStatistics statistics, IConfigManager configManager) { Get["/"] = _ => View["index", new IndexModel { Pools = poolManager.Pools, - Statistics = statistics, + Statistics = statistics }]; } } - - public class IndexModel - { - public IReadOnlyCollection Pools { get; set; } - - public IStatistics Statistics { get; set; } - } } diff --git a/src/CoiniumServ/Server/Web/Modules/Models/Error.cs b/src/CoiniumServ/Server/Web/Modules/Models/ErrorModel.cs similarity index 94% rename from src/CoiniumServ/Server/Web/Modules/Models/Error.cs rename to src/CoiniumServ/Server/Web/Modules/Models/ErrorModel.cs index 3140a3f19..c1650b8d0 100644 --- a/src/CoiniumServ/Server/Web/Modules/Models/Error.cs +++ b/src/CoiniumServ/Server/Web/Modules/Models/ErrorModel.cs @@ -21,9 +21,11 @@ // #endregion +using CoiniumServ.Configuration; + namespace CoiniumServ.Server.Web.Modules.Models { - public class Error + public class ErrorModel { public string Summary { get; set; } public string Details { get; set; } diff --git a/src/CoiniumServ/Server/Web/Modules/Models/IndexModel.cs b/src/CoiniumServ/Server/Web/Modules/Models/IndexModel.cs new file mode 100644 index 000000000..5e69fa410 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Models/IndexModel.cs @@ -0,0 +1,36 @@ +#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 CoiniumServ.Pools; +using CoiniumServ.Statistics; + +namespace CoiniumServ.Server.Web.Modules.Models +{ + public class IndexModel + { + public IReadOnlyCollection Pools { get; set; } + + public IStatistics Statistics { get; set; } + } +} diff --git a/src/CoiniumServ/Server/Web/Modules/Models/PoolModel.cs b/src/CoiniumServ/Server/Web/Modules/Models/PoolModel.cs new file mode 100644 index 000000000..0de676ff4 --- /dev/null +++ b/src/CoiniumServ/Server/Web/Modules/Models/PoolModel.cs @@ -0,0 +1,32 @@ +#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 CoiniumServ.Pools; + +namespace CoiniumServ.Server.Web.Modules.Models +{ + public class PoolModel + { + public IPool Pool { get; set; } + } +} diff --git a/src/CoiniumServ/Server/Web/Modules/Pool.cs b/src/CoiniumServ/Server/Web/Modules/Pool.cs index cf3dcaa45..eddef2ec0 100644 --- a/src/CoiniumServ/Server/Web/Modules/Pool.cs +++ b/src/CoiniumServ/Server/Web/Modules/Pool.cs @@ -35,16 +35,17 @@ public PoolModule(IPoolManager poolManager) { var pool = poolManager.GetBySymbol(_.slug); - if (pool != null) - return View["pool", pool]; + if (pool == null) // make sure queried pool exists. + return View["error", new ErrorModel + { + Summary = "Pool not found", + Details = string.Format("The request pool does not exist: {0}", _.slug) + }]; - var error = new Error + return View["pool", new PoolModel { - Summary = "Pool not found", - Details = string.Format("The request pool does not exist: {0}", _.slug) - }; - - return View["error", error]; + Pool = pool + }]; }; } } diff --git a/src/CoiniumServ/packages.config b/src/CoiniumServ/packages.config index 8df8ea1a4..3221e6078 100644 --- a/src/CoiniumServ/packages.config +++ b/src/CoiniumServ/packages.config @@ -4,14 +4,14 @@ - + - + - - - + + + \ No newline at end of file diff --git a/src/CoiniumServ/web/default/index.cshtml b/src/CoiniumServ/web/default/index.cshtml index 2b5588502..f516d2749 100644 --- a/src/CoiniumServ/web/default/index.cshtml +++ b/src/CoiniumServ/web/default/index.cshtml @@ -1,5 +1,5 @@ @using CoiniumServ.Coin.Helpers -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase @{ Layout = "layout.cshtml"; } diff --git a/src/CoiniumServ/web/default/layout.cshtml b/src/CoiniumServ/web/default/layout.cshtml index 4d43f85ea..8196e14f1 100644 --- a/src/CoiniumServ/web/default/layout.cshtml +++ b/src/CoiniumServ/web/default/layout.cshtml @@ -56,9 +56,7 @@