diff --git a/aion_pool/README.md b/aion_pool/README.md index 547d749..59e6e84 100644 --- a/aion_pool/README.md +++ b/aion_pool/README.md @@ -196,6 +196,7 @@ Make the following edits to the config file (aion_pool.json): - ***accountPassword***: Change to contain the "password" which matches the miner account specified in the kernel configuration. - (Optional) Change ***minimumConfirmations*** to the number of blocks (depth in the chain) that must be established before rewards begin to be distributed. - (Optional) ***minimumPeerCount*** is the number of peers your kernel must be connected to minimum this number of peers in order to distribute rewards. This ensures rewards are not distributed should the aion kernel become disconnected from the rest of the network. + - (Optional) ***hashratePercentageCalcInterval*** (seconds) is the interval at which your pool(s) will poll the kernal to get the network hashrate and pool hashrate. These are used to calculate the pool(s)' hashrate percentage of the total network hashrate. More information on the configuration file [here](https://github.com/coinfoundry/miningcore/wiki/Configuration). diff --git a/aion_pool/examples/aion_pool.json b/aion_pool/examples/aion_pool.json index e989264..216a6cb 100644 --- a/aion_pool/examples/aion_pool.json +++ b/aion_pool/examples/aion_pool.json @@ -72,6 +72,8 @@ "jobRebroadcastTimeout": 10, "clientConnectionTimeout": 600, + + "hashratePercentageCalcInterval": 40, "banning": { "enabled": true, @@ -118,4 +120,4 @@ } }] } - \ No newline at end of file + diff --git a/aion_pool/src/MiningCore/Api/ApiServer.cs b/aion_pool/src/MiningCore/Api/ApiServer.cs index b67749c..0cdcd93 100644 --- a/aion_pool/src/MiningCore/Api/ApiServer.cs +++ b/aion_pool/src/MiningCore/Api/ApiServer.cs @@ -351,7 +351,7 @@ private async Task GetMiningPoolHashrateStats(HttpContext context, Match m) PoolValueStat[] stats = cf.Run(con => statsRepo.GetPoolHashrate(con, pool.Id, start, end, granularity)); await SendJsonAsync(context, stats); } - + private async Task GetMiningPoolStats(HttpContext context, Match m) { var pool = GetPool(context, m); diff --git a/aion_pool/src/MiningCore/Api/Responses/GetPoolStatsResponse.cs b/aion_pool/src/MiningCore/Api/Responses/GetPoolStatsResponse.cs index 6b7d568..ab915e8 100644 --- a/aion_pool/src/MiningCore/Api/Responses/GetPoolStatsResponse.cs +++ b/aion_pool/src/MiningCore/Api/Responses/GetPoolStatsResponse.cs @@ -28,6 +28,7 @@ public partial class AggregatedPoolStats public int ConnectedMiners { get; set; } public double NetworkHashrate { get; set; } public DateTime Created { get; set; } + public double PoolHashratePercentage {get; set;} } public class GetPoolStatsResponse diff --git a/aion_pool/src/MiningCore/Api/Responses/GetPoolsResponse.cs b/aion_pool/src/MiningCore/Api/Responses/GetPoolsResponse.cs index 6642e30..3e33aaa 100644 --- a/aion_pool/src/MiningCore/Api/Responses/GetPoolsResponse.cs +++ b/aion_pool/src/MiningCore/Api/Responses/GetPoolsResponse.cs @@ -65,6 +65,7 @@ public partial class PoolInfo public BlockchainStats NetworkStats { get; set; } public MinerPerformanceStats[] TopMiners { get; set; } public decimal TotalPaid { get; set; } + } public class GetPoolsResponse diff --git a/aion_pool/src/MiningCore/AutofacModule.cs b/aion_pool/src/MiningCore/AutofacModule.cs index fa88e98..17d678b 100644 --- a/aion_pool/src/MiningCore/AutofacModule.cs +++ b/aion_pool/src/MiningCore/AutofacModule.cs @@ -97,6 +97,9 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .AsSelf(); + + builder.RegisterType() + .AsSelf(); builder.RegisterType() .SingleInstance(); diff --git a/aion_pool/src/MiningCore/Blockchain/Aion/AionConstants.cs b/aion_pool/src/MiningCore/Blockchain/Aion/AionConstants.cs index 13eb836..fa14f62 100644 --- a/aion_pool/src/MiningCore/Blockchain/Aion/AionConstants.cs +++ b/aion_pool/src/MiningCore/Blockchain/Aion/AionConstants.cs @@ -33,6 +33,7 @@ public static class AionCommands public const string GetDifficulty = "getdifficulty"; public const string GetMinerStats = "getMinerStats"; public const string Ping = "ping"; + } } diff --git a/aion_pool/src/MiningCore/Blockchain/Aion/AionJob.cs b/aion_pool/src/MiningCore/Blockchain/Aion/AionJob.cs index 7999c82..c0d6d15 100644 --- a/aion_pool/src/MiningCore/Blockchain/Aion/AionJob.cs +++ b/aion_pool/src/MiningCore/Blockchain/Aion/AionJob.cs @@ -23,6 +23,8 @@ using NBitcoin; using NBitcoin.DataEncoders; using NLog; +using MiningCore.Blockchain.Aion.DaemonResponses; + namespace MiningCore.Blockchain.Aion { @@ -52,7 +54,7 @@ public AionJob(string id, AionBlockTemplate blockTemplate, ILogger logger, Daemo private readonly ILogger logger; private EquihashSolver equihash = EquihashSolver.Instance.Value; private IHashAlgorithm headerHasher = new Blake2b(); - public double Difficulty { get; protected set; } + public double Difficulty { get; set; } public DaemonClient daemonClient; private void RegisterNonce(StratumClient worker, string nonce) @@ -191,8 +193,27 @@ private byte[] SerializeHeader(string nonce) } private double getNetworkDifficulty() { - var response = daemonClient.ExecuteCmdAnyAsync(AionCommands.GetDifficulty).Result; - return (double) Convert.ToInt32(response.Response, 16); + var response = daemonClient.ExecuteStringResponseCmdSingleAsync(AionCommands.GetDifficulty).Result; + try + { + double output = (double)Convert.ToInt32(response, 16); + return output; + } + catch + { + logger.Info(() => $"Error in casting getDifficulty response from string to int. Response: {response}"); + logger.Error($"Network Difficulty Cast error: {response}"); + } + + return 0; + } + + private double GetPoolNetworkPercentage(string poolAddress) + { + var response = daemonClient.ExecuteCmdAnyAsync(AionCommands.GetMinerStats, new [] { poolAddress }).Result; + var networkPercentage = (double) Convert.ToDouble(response.Response.MinerHashrateShare); + return networkPercentage; } + } } \ No newline at end of file diff --git a/aion_pool/src/MiningCore/Blockchain/Aion/AionJobManager.cs b/aion_pool/src/MiningCore/Blockchain/Aion/AionJobManager.cs index daf99c5..c41c424 100644 --- a/aion_pool/src/MiningCore/Blockchain/Aion/AionJobManager.cs +++ b/aion_pool/src/MiningCore/Blockchain/Aion/AionJobManager.cs @@ -248,6 +248,8 @@ protected bool UpdateJob(AionBlockTemplate blockTemplate) BlockchainStats.BlockHeight = (long) currentJob.BlockTemplate.Height; var (networkHashrate, poolHashRate) = getNetworkAndMinerHashRate(); BlockchainStats.NetworkHashrate = networkHashrate; + // Update network difficulty + BlockchainStats.NetworkDifficulty = job.Difficulty; PoolHashRate = poolHashRate; } diff --git a/aion_pool/src/MiningCore/Blockchain/Aion/AionPool.cs b/aion_pool/src/MiningCore/Blockchain/Aion/AionPool.cs index f2289eb..daee478 100644 --- a/aion_pool/src/MiningCore/Blockchain/Aion/AionPool.cs +++ b/aion_pool/src/MiningCore/Blockchain/Aion/AionPool.cs @@ -199,6 +199,8 @@ private async Task OnSubmitAsync(StratumClient client, Timestamped /// If true, internal stratum ports are not initialized diff --git a/aion_pool/src/MiningCore/DaemonInterface/DaemonClient.cs b/aion_pool/src/MiningCore/DaemonInterface/DaemonClient.cs index ef19261..44a986d 100644 --- a/aion_pool/src/MiningCore/DaemonInterface/DaemonClient.cs +++ b/aion_pool/src/MiningCore/DaemonInterface/DaemonClient.cs @@ -187,7 +187,29 @@ public Task> ExecuteCmdSingleAsync(string method) { return ExecuteCmdAnyAsync(method); } + + /// + /// /Executes the request for only getDifficulty + /// + /// + /// + /// + /// + /// + public async Task ExecuteStringResponseCmdSingleAsync(string method, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null, bool throwOnError = false) + { + Contract.Requires(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); + logger.LogInvoke(new[] { method }); + + var tasks = endPoints.Select(endPoint => BuildRequestTask(endPoint, method, payload, payloadJsonSerializerSettings)).ToArray(); + + var taskFirstCompleted = await Task.WhenAny(tasks); + return MapDaemonResponse(0, taskFirstCompleted).Response; + } + + /// /// Executes the request against all configured demons and returns the first successful response /// @@ -200,7 +222,6 @@ public async Task> ExecuteCmdSingleAsync(st where TResponse : class { Contract.Requires(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); - logger.LogInvoke(new[] { method }); var task = BuildRequestTask(endPoints.First(), method, payload, payloadJsonSerializerSettings); diff --git a/aion_pool/src/MiningCore/DaemonInterface/DaemonResponse.cs b/aion_pool/src/MiningCore/DaemonInterface/DaemonResponse.cs index c6b59ff..9f68dea 100644 --- a/aion_pool/src/MiningCore/DaemonInterface/DaemonResponse.cs +++ b/aion_pool/src/MiningCore/DaemonInterface/DaemonResponse.cs @@ -28,5 +28,6 @@ public class DaemonResponse public JsonRpcException Error { get; set; } public T Response { get; set; } public AuthenticatedNetworkEndpointConfig Instance { get; set; } + public string DifficultyResponse { get; set; } } } diff --git a/aion_pool/src/MiningCore/Mining/PoolBase.cs b/aion_pool/src/MiningCore/Mining/PoolBase.cs index cc88f8a..9efa6d7 100644 --- a/aion_pool/src/MiningCore/Mining/PoolBase.cs +++ b/aion_pool/src/MiningCore/Mining/PoolBase.cs @@ -33,6 +33,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using AutoMapper; using MiningCore.Banning; using MiningCore.Blockchain; +using MiningCore.Blockchain.Aion; using MiningCore.Configuration; using MiningCore.Extensions; using MiningCore.Messaging; @@ -312,7 +313,7 @@ private void OutputPoolInfo() Detected Reward Type: {blockchainStats?.RewardType} Current Block Height: {blockchainStats?.BlockHeight} Current Connect Peers: {blockchainStats?.ConnectedPeers} -Network Difficulty: {blockchainStats?.NetworkDifficulty} +Network Difficulty: {FormatUtil.FormatDifficulty(blockchainStats != null ? blockchainStats.NetworkDifficulty: AionUtils.getNetworkDifficulty())} Network Hash Rate: {FormatUtil.FormatHashrate(blockchainStats != null ? blockchainStats.NetworkHashrate : 0)} Stratum Port(s): {(poolConfig.Ports?.Any() == true ? string.Join(", ", poolConfig.Ports.Keys) : string.Empty )} Pool Fee: {(poolConfig.RewardRecipients?.Any() == true ? poolConfig.RewardRecipients.Sum(x => x.Percentage) : 0)}% diff --git a/aion_pool/src/MiningCore/Mining/PoolNetworkPercentageRecorder.cs b/aion_pool/src/MiningCore/Mining/PoolNetworkPercentageRecorder.cs new file mode 100644 index 0000000..cbfdc3b --- /dev/null +++ b/aion_pool/src/MiningCore/Mining/PoolNetworkPercentageRecorder.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; +using System.Net.Sockets; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Autofac; +using AutoMapper; +using MailKit.Search; +using MimeKit.Cryptography; +using MiningCore.Blockchain.Aion; +using MiningCore.DaemonInterface; +using Newtonsoft.Json; +using NLog; +using MiningCore.Blockchain.Aion; +using MiningCore.Configuration; +using MiningCore.JsonRpc; +using MiningCore.Persistence; +using MiningCore.Persistence.Repositories; +using MiningCore.Time; +using MiningCore.Contracts; +using MiningCore.Extensions; +using MiningCore.Persistence.Postgres.Entities; +using Newtonsoft.Json.Bson; +using Newtonsoft.Json.Linq; +using Polly; +using MiningCore.Blockchain.Aion.DaemonResponses; +using MiningCore.Configuration; + + +namespace MiningCore.Mining +{ + + public class PoolNetworkPercRecorder + { + public PoolNetworkPercRecorder(IComponentContext ctx, + IMasterClock clock, + IConnectionFactory cf, + IMapper mapper, + IStatsRepository statsRepo) + { + Contract.RequiresNonNull(ctx, nameof(ctx)); + Contract.RequiresNonNull(clock, nameof(clock)); + Contract.RequiresNonNull(cf, nameof(cf)); + Contract.RequiresNonNull(mapper, nameof(mapper)); + Contract.RequiresNonNull(statsRepo, nameof(statsRepo)); + + this.ctx = ctx; + this.clock = clock; + this.cf = cf; + this.mapper = mapper; + this.statsRepo = statsRepo; + + + BuildFaultHandlingPolicy(); + } + + public PoolNetworkPercRecorder() + { + + } + + private readonly IMasterClock clock; + private readonly IStatsRepository statsRepo; + private readonly IConnectionFactory cf; + private readonly IMapper mapper; + private readonly IComponentContext ctx; + private readonly AutoResetEvent stopEvent = new AutoResetEvent(false); + private readonly ConcurrentDictionary pools = new ConcurrentDictionary(); + private ClusterConfig clusterConfig; + private Thread thread1; + private const int RetryCount = 4; + private Policy readFaultPolicy; + private long delayInSeconds = 40; + + private static double PoolNetworkPercentage = 0; + + private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); + + #region API-Surface + + public void Configure(ClusterConfig clusterConfig) + { + this.clusterConfig = clusterConfig; + } + + public void AttachPool(IMiningPool pool) + { + pools[pool.Config.Id] = pool; + } + + // send to user interface + public double ToUIPoolNetworkPercentage() + { + return PoolNetworkPercentage; + } + + + private void setDelayInSeconds() + { + try + { + delayInSeconds = clusterConfig.Pools[0].HashratePercentageCalcInterval; + } + catch (Exception e) + { + delayInSeconds = 7200; + Console.WriteLine($"There is no HashratePercentage Calc Interval"); + } + } + + public void Start() + { + logger.Info(() => "Online"); + + setDelayInSeconds(); + + thread1 = new Thread(() => + { + // warm-up delay + Thread.Sleep(TimeSpan.FromSeconds(10)); + + var interval = TimeSpan.FromSeconds(delayInSeconds); + + while (true) + { + try + { + RecordPoolHashratePercentage(); + } + + catch (Exception ex) + { + logger.Error(ex); + } + + var waitResult = stopEvent.WaitOne(interval); + + // check if stop was signalled + if (waitResult) + break; + } + }); + + thread1.Name = "PoolHashRatePercentageRecorder"; + thread1.Start(); + } + + public void Stop() + { + logger.Info(() => "Stopping .."); + + stopEvent.Set(); + thread1.Join(); + + logger.Info(() => "Stopped"); + } + + #endregion // API-Surface + + // BEGIN MINER HASHRATE PERCENTAGE CALCULATION + + private void RecordPoolHashratePercentage() + { + Console.WriteLine($"Hashrate percentage calculation call at {DateTime.Now}"); + + var poolIds = pools.Keys; + var start = clock.Now; + var stats = new PoolNetworkPercentageStats{}; + + + foreach (var poolId in poolIds) + { + logger.Info(() => $"Updating hashrates for pool {poolId}"); + + + try + { + string poolAddress = pools[poolId].Config.Address; + PoolNetworkPercentage = 100*GetPoolNetworkPercentage(poolAddress, pools[poolId].Config); + // make the call to write to the database + Persist(poolId, PoolNetworkPercentage, stats); + } + catch(Exception e) + { + Console.WriteLine($"PLEASE ENSURE (IN YOUR 'aion-pool.config') THAT " + + $"YOUR POOL ADDRESS IS CORRECT. YOUR MINER ADDRESS MAY " + + $"NOT BE ON THE NETWORK"); + Console.WriteLine($"Error calculating Pool({poolId}) Hashrate network percentage %"); + Console.WriteLine($"Pool({poolId}) network percentage: {PoolNetworkPercentage}"); + Console.WriteLine($"Exception: {e}"); + } + + } + } + + + // Write to database + private void Persist(string poolId, double networkhashrate, PoolNetworkPercentageStats stats) + { + + cf.RunTx((con, tx) => + { + stats.PoolId = poolId; + stats.NetworkPercentage = networkhashrate; + statsRepo.InsertPoolNetworkPercentageStats(con, tx, stats); + }); + + } + + + private void BuildFaultHandlingPolicy() + { + var retry = Policy + .Handle() + .Or() + .Or() + .Retry(RetryCount, OnPolicyRetry); + + readFaultPolicy = retry; + } + + private static void OnPolicyRetry(Exception ex, int retry, object context) + { + logger.Warn(() => $"Retry {retry} due to {ex.Source}: {ex.GetType().Name} ({ex.Message})"); + } + + private double GetPoolNetworkPercentage(string poolAddress, PoolConfig poolConfig) + { + JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings(); + DaemonClient daemon = new DaemonClient(jsonSerializerSettings); + var daemonEndpoints = poolConfig.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + daemon.Configure(daemonEndpoints); + var response = daemon.ExecuteCmdAnyAsync(AionCommands.GetMinerStats, new [] { poolAddress }).Result; + var networkPercentage = (double) Convert.ToDouble(response.Response.MinerHashrateShare); + return networkPercentage; + } + + } + + +} \ No newline at end of file diff --git a/aion_pool/src/MiningCore/Mining/PoolStats.cs b/aion_pool/src/MiningCore/Mining/PoolStats.cs index b7a8fb5..9789499 100644 --- a/aion_pool/src/MiningCore/Mining/PoolStats.cs +++ b/aion_pool/src/MiningCore/Mining/PoolStats.cs @@ -28,5 +28,7 @@ public class PoolStats public int ConnectedMiners { get; set; } public double PoolHashrate { get; set; } public int SharesPerSecond { get; set; } + public double NetworkDifficulty { get; set; } + public double PoolNetworkPercentage { get; set; } } } diff --git a/aion_pool/src/MiningCore/Persistence/Model/PoolStats.cs b/aion_pool/src/MiningCore/Persistence/Model/PoolStats.cs index 7798050..9d9bfef 100644 --- a/aion_pool/src/MiningCore/Persistence/Model/PoolStats.cs +++ b/aion_pool/src/MiningCore/Persistence/Model/PoolStats.cs @@ -46,7 +46,9 @@ public class PoolStats public long BlockHeight { get; set; } public int ConnectedPeers { get; set; } public int SharesPerSecond { get; set; } + public double PoolNetworkPercentage { get; set; } public DateTime Created { get; set; } } + } diff --git a/aion_pool/src/MiningCore/Persistence/Postgres/Entities/PoolStats.cs b/aion_pool/src/MiningCore/Persistence/Postgres/Entities/PoolStats.cs index cf52339..7bcfa77 100644 --- a/aion_pool/src/MiningCore/Persistence/Postgres/Entities/PoolStats.cs +++ b/aion_pool/src/MiningCore/Persistence/Postgres/Entities/PoolStats.cs @@ -39,7 +39,19 @@ public class PoolStats public long BlockHeight { get; set; } public int ConnectedPeers { get; set; } public int SharesPerSecond { get; set; } - + public double PoolNetworkPercentage { get; set; } + public DateTime Created { get; set; } } + + public class PoolNetworkPercentageStats + { + + //public long Id { get; set; } + public string PoolId { get; set; } + public double NetworkPercentage { get; set; } + //public DateTime Created { get; set; } + + } + } diff --git a/aion_pool/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs b/aion_pool/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs index 6e45795..855318d 100644 --- a/aion_pool/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs +++ b/aion_pool/src/MiningCore/Persistence/Postgres/Repositories/StatsRepository.cs @@ -27,11 +27,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using MiningCore.Extensions; using MiningCore.Persistence.Model; using MiningCore.Persistence.Model.Projections; +using MiningCore.Persistence.Postgres.Entities; using MiningCore.Persistence.Repositories; using MiningCore.Time; using NBitcoin; using NLog; using MinerStats = MiningCore.Persistence.Model.Projections.MinerStats; +using MinerWorkerPerformanceStats = MiningCore.Persistence.Model.MinerWorkerPerformanceStats; +using Payment = MiningCore.Persistence.Model.Payment; +using PoolStats = MiningCore.Persistence.Model.PoolStats; +using PoolValueStat = MiningCore.Persistence.Model.PoolValueStat; +using MiningCore.Mining; + namespace MiningCore.Persistence.Postgres.Repositories { @@ -47,6 +54,7 @@ public StatsRepository(IMapper mapper, IMasterClock clock) private readonly IMasterClock clock; private static readonly ILogger logger = LogManager.GetCurrentClassLogger(); private static readonly TimeSpan MinerStatsMaxAge = TimeSpan.FromMinutes(20); + private static readonly PoolNetworkPercRecorder poolNetworkPercRecorder = new PoolNetworkPercRecorder(); public void InsertPoolStats(IDbConnection con, IDbTransaction tx, PoolStats stats) { @@ -77,18 +85,47 @@ public void InsertMinerWorkerPerformanceStats(IDbConnection con, IDbTransaction con.Execute(query, mapped, tx); } + public void InsertPoolNetworkPercentageStats(IDbConnection con, IDbTransaction tx, + PoolNetworkPercentageStats stats) + { + logger.LogInvoke(); + var mapped = mapper.Map(stats); + + var query = "INSERT INTO poolnetworkpercentagestats(poolid, networkpercentage) " + + "VALUES(@poolid, @networkpercentage)"; + + con.Execute(query, mapped, tx); + } + + public PoolStats GetLastPoolStats(IDbConnection con, string poolId) { logger.LogInvoke(); + /*var query = "SELECT ps.*," + + "pnps.networkpercentage as poolnetworkpercentage " + + "FROM poolstats ps " + + "INNER JOIN poolnetworkpercentagestats pnps " + + "ON pnps.poolid = ps.poolid " + + "WHERE pnps.poolid = @poolId " + + "AND pnps.created = " + + "(SELECT MAX(created) FROM poolnetworkpercentagestats " + + "WHERE pnps.poolid = @poolId )" + + "ORDER BY created DESC FETCH NEXT 1 ROWS ONLY"; +*/ - var query = "SELECT * FROM poolstats WHERE poolid = @poolId ORDER BY created DESC FETCH NEXT 1 ROWS ONLY"; + var query = "SELECT * FROM poolstats WHERE poolid = @poolId " + + "ORDER BY created DESC FETCH NEXT 1 ROWS ONLY"; var entity = con.QuerySingleOrDefault(query, new { poolId }); if (entity == null) return null; + + // insert the pool network percentage + entity.PoolNetworkPercentage = poolNetworkPercRecorder.ToUIPoolNetworkPercentage(); return mapper.Map(entity); } + public decimal GetTotalPoolPayments(IDbConnection con, string poolId) { diff --git a/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/cleandb.sql b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/cleandb.sql index b494a5a..324bdcb 100644 --- a/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/cleandb.sql +++ b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/cleandb.sql @@ -2,3 +2,4 @@ DROP TABLE blocks; DROP TABLE balances; DROP TABLE payments; + diff --git a/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/createdb.sql b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/createdb.sql index 3ed1c7a..e948a5c 100644 --- a/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/createdb.sql +++ b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/createdb.sql @@ -108,6 +108,23 @@ CREATE TABLE minerstats created TIMESTAMP NOT NULL ); +CREATE TABLE poolhashratepercentagestats +( + id BIGSERIAL NOT NULL PRIMARY KEY, + poolid TEXT NOT NULL, + networkpercentage DOUBLE PRECISION NOT NULL DEFAULT 0, + created TIMESTAMP DEFAULT current_timestamp +); + +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED on poolnetworkpercentagestats(poolid, created); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_HOUR on poolnetworkpercentagestats(poolid, date_trunc('hour',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_DAY on poolnetworkpercentagestats(poolid, date_trunc('day',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_MONTH on poolnetworkpercentagestats(poolid, date_trunc('month',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_YEAR on poolnetworkpercentagestats(poolid, date_trunc('year',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_POOLID on poolnetworkpercentagestats(poolid); + + + CREATE TABLE IF NOT EXISTS coin_info ( cointype TEXT PRIMARY KEY NOT NULL, diff --git a/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/updatedb.sql b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/updatedb.sql new file mode 100644 index 0000000..ae76fe3 --- /dev/null +++ b/aion_pool/src/MiningCore/Persistence/Postgres/Scripts/updatedb.sql @@ -0,0 +1,16 @@ +set role miningcore; + +CREATE TABLE poolnetworkpercentagestats +( + id BIGSERIAL NOT NULL PRIMARY KEY, + poolid TEXT NOT NULL, + networkpercentage DOUBLE PRECISION NOT NULL DEFAULT 0, + created TIMESTAMP DEFAULT current_timestamp +); + +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED on poolnetworkpercentagestats(poolid, created); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_HOUR on poolnetworkpercentagestats(poolid, date_trunc('hour',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_DAY on poolnetworkpercentagestats(poolid, date_trunc('day',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_MONTH on poolnetworkpercentagestats(poolid, date_trunc('month',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_YEAR on poolnetworkpercentagestats(poolid, date_trunc('year',created)); +CREATE INDEX IDX_POOLNETWORKPERCENTAGESTATS_POOL_CREATED_POOLID on poolnetworkpercentagestats(poolid); diff --git a/aion_pool/src/MiningCore/Persistence/Repositories/IStatsRepository.cs b/aion_pool/src/MiningCore/Persistence/Repositories/IStatsRepository.cs index ccdcb69..5730ad0 100644 --- a/aion_pool/src/MiningCore/Persistence/Repositories/IStatsRepository.cs +++ b/aion_pool/src/MiningCore/Persistence/Repositories/IStatsRepository.cs @@ -22,7 +22,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System.Data; using MiningCore.Persistence.Model; using MiningCore.Persistence.Model.Projections; +using MiningCore.Persistence.Postgres.Entities; using MinerStats = MiningCore.Persistence.Model.Projections.MinerStats; +using MinerWorkerPerformanceStats = MiningCore.Persistence.Model.MinerWorkerPerformanceStats; +using PoolStats = MiningCore.Persistence.Model.PoolStats; +using PoolValueStat = MiningCore.Persistence.Model.PoolValueStat; namespace MiningCore.Persistence.Repositories { @@ -30,6 +34,8 @@ public interface IStatsRepository { void InsertPoolStats(IDbConnection con, IDbTransaction tx, PoolStats stats); void InsertMinerWorkerPerformanceStats(IDbConnection con, IDbTransaction tx, MinerWorkerPerformanceStats stats); + void InsertPoolNetworkPercentageStats(IDbConnection con, IDbTransaction tx, PoolNetworkPercentageStats stats); + PoolStats GetLastPoolStats(IDbConnection con, string poolId); decimal GetTotalPoolPayments(IDbConnection con, string poolId); PoolStats[] GetPoolPerformanceBetweenHourly(IDbConnection con, string poolId, DateTime start, DateTime end); @@ -40,6 +46,7 @@ public interface IStatsRepository WorkerPerformanceStatsContainer[] GetMinerPerformanceBetweenDaily(IDbConnection con, string poolId, string miner, DateTime start, DateTime end); PoolValueStat[] GetPoolConnectedMiners(IDbConnection con, string poolId, DateTime start, DateTime end, StatsGranularity granularity); PoolValueStat[] GetPoolHashrate(IDbConnection con, string poolId, DateTime start, DateTime end, StatsGranularity granularity); - PoolValueStat[] GetPoolNetworkPercentage(IDbConnection con, string poolId, DateTime start, DateTime end, StatsGranularity granularity); + PoolValueStat[] GetPoolNetworkPercentage(IDbConnection con, string poolId, DateTime start, DateTime end, StatsGranularity granularity); + } } diff --git a/aion_pool/src/MiningCore/Program.cs b/aion_pool/src/MiningCore/Program.cs index 30e9035..1521a1b 100644 --- a/aion_pool/src/MiningCore/Program.cs +++ b/aion_pool/src/MiningCore/Program.cs @@ -75,6 +75,7 @@ public class Program private static StatsRecorder statsRecorder; private static ClusterConfig clusterConfig; private static ApiServer apiServer; + private static PoolNetworkPercRecorder poolNetworkPercRecorder; public static AdminGcStats gcStats = new AdminGcStats(); @@ -106,7 +107,13 @@ public static void Main(string[] args) ValidateConfig(); Bootstrap(); LogRuntimeInfo(); - + + /* + //--- RUN THE HASHRATEPERCENTAGE SCHEDULER ----// + new PoolHashratePercRecorder(60); + //--- END THE HASHRATE PERCENTAGE SCHEDULAER ---// + */ + if (!shareRecoveryOption.HasValue()) { if(!cts.IsCancellationRequested) @@ -115,6 +122,7 @@ public static void Main(string[] args) else RecoverShares(shareRecoveryOption.Value()); + } catch (PoolStartupAbortException ex) @@ -543,6 +551,7 @@ private static async Task Start() // start share receiver (for external shares) shareReceiver = container.Resolve(); shareReceiver.Start(clusterConfig); + } else @@ -579,6 +588,11 @@ private static async Task Start() statsRecorder.Configure(clusterConfig); statsRecorder.Start(); } + + // start poolHashRatePercemtageRecorder + poolNetworkPercRecorder = container.Resolve(); + poolNetworkPercRecorder.Configure(clusterConfig); + poolNetworkPercRecorder.Start(); // start pools await Task.WhenAll(clusterConfig.Pools.Where(x => x.Enabled).Select(async poolConfig => @@ -594,6 +608,8 @@ await Task.WhenAll(clusterConfig.Pools.Where(x => x.Enabled).Select(async poolCo // pre-start attachments shareReceiver?.AttachPool(pool); statsRecorder?.AttachPool(pool); + poolNetworkPercRecorder?.AttachPool(pool); + await pool.StartAsync(cts.Token); })); @@ -658,6 +674,8 @@ private static void Shutdown() statsRecorder?.Stop(); payoutManager?.Stop(); shareReceiver?.Stop(); + poolNetworkPercRecorder?.Stop(); + } private static void TouchNativeLibs() diff --git a/ui/.idea/vcs.xml b/ui/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/ui/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index f393919..c914aee 100755 --- a/ui/package.json +++ b/ui/package.json @@ -42,7 +42,7 @@ "watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path node_modules src/ -o src/ --watch --recursive", "start-js": "react-scripts start", - "start": "npm-run-all -p watch-css start-js", + "start": "PORT=3000 NODE_PATH=./src npm-run-all -p watch-css start-js", "build-js": "react-scripts build", "build": "npm-run-all build-css build-js" },