Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Commit

Permalink
Dev (#455)
Browse files Browse the repository at this point in the history
* More flexible parameters for pool/performance API
* Fix network difficulty recorded with poolstats for Bitcoin family coins
* Added Balance related Admin-APIs
* Add Miner to BlockUnlockedNotification
* Implemented overt ASIC-boost stratum extension
  • Loading branch information
Oliver Weichhold authored Nov 4, 2018
1 parent 5cdb4b0 commit a2dd65a
Show file tree
Hide file tree
Showing 52 changed files with 710 additions and 292 deletions.
6 changes: 3 additions & 3 deletions src/Miningcore.Tests/Blockchain/Bitcoin/BitcoinJobTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public BitcoinJobTests()
readonly PoolConfig poolConfig;

readonly ClusterConfig clusterConfig = new ClusterConfig();
private readonly IDestination poolAddressDestination = BitcoinUtils.AddressToDestination("mjn3q42yxr9yLA3gyseHCZCHEptZC31PEh");
private readonly IDestination poolAddressDestination = BitcoinUtils.AddressToDestination("mjn3q42yxr9yLA3gyseHCZCHEptZC31PEh", Network.RegTest);

protected readonly IHashAlgorithm sha256d = new Sha256D();
protected readonly IHashAlgorithm sha256dReverse = new DigestReverser(new Sha256D());
Expand All @@ -50,7 +50,7 @@ public void BitcoinJob_Should_Accept_Valid_Share()
// set clock to job creation time
var clock = new MockMasterClock { CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869874).UtcDateTime };

job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, BitcoinNetworkType.RegTest,
job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, Network.RegTest,
false, 1, sha256d, sha256d, sha256dReverse);

// set clock to submission time
Expand Down Expand Up @@ -86,7 +86,7 @@ public void BitcoinJob_Should_Not_Accept_Invalid_Share()
// set clock to job creation time
var clock = new MockMasterClock { CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869874).UtcDateTime };

job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, BitcoinNetworkType.RegTest,
job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, Network.RegTest,
false, 1, sha256d, sha256d, sha256dReverse);

// set clock to submission time
Expand Down
8 changes: 4 additions & 4 deletions src/Miningcore.Tests/Blockchain/Equihash/EquihashJobTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public EquihashJobTests()
readonly PoolConfig poolConfig;

readonly ClusterConfig clusterConfig = new ClusterConfig();
private readonly IDestination poolAddressDestination = BitcoinUtils.AddressToDestination("tmUEUSYYGQY3G5KMNkxAqkYYNfstaCsRCM5");
private readonly IDestination poolAddressDestination = BitcoinUtils.AddressToDestination("tmUEUSYYGQY3G5KMNkxAqkYYNfstaCsRCM5", ZcashNetworks.Instance.Mainnet);

protected readonly IHashAlgorithm sha256d = new Sha256D();
protected readonly IHashAlgorithm sha256dReverse = new DigestReverser(new Sha256D());
Expand All @@ -39,7 +39,7 @@ public EquihashJobTests()
public void ZCashUtils_EncodeTarget()
{
var equihashCoin = poolConfig.Template.As<EquihashCoinTemplate>();
var chainConfig = equihashCoin.GetNetwork(BitcoinNetworkType.Main);
var chainConfig = equihashCoin.GetNetwork(ZcashNetworks.Instance.Mainnet.NetworkType);

var result = EquihashUtils.EncodeTarget(0.5, chainConfig);
Assert.Equal(result, "0010102040810204081020408102040810204081020408102040810204080fe0");
Expand Down Expand Up @@ -69,10 +69,10 @@ public void ZCashJob_Testnet_Validate_FoundersRewardAddress_At_Height()
var clock = new MockMasterClock { CurrentTime = DateTimeOffset.FromUnixTimeSeconds(1508869874).UtcDateTime };

var equihashCoin = poolConfig.Template.As<EquihashCoinTemplate>();
var chainConfig = equihashCoin.GetNetwork(BitcoinNetworkType.Main);
var chainConfig = equihashCoin.GetNetwork(ZcashNetworks.Instance.Mainnet.NetworkType);
var solver = EquihashSolverFactory.GetSolver(ModuleInitializer.Container, chainConfig.Solver);

job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, BitcoinNetworkType.Test, solver);
job.Init(bt, "1", poolConfig, clusterConfig, clock, poolAddressDestination, ZcashNetworks.Instance.Testnet, solver);

bt.Height = 1;
Assert.Equal(job.GetFoundersRewardAddress(), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi");
Expand Down
8 changes: 4 additions & 4 deletions src/Miningcore/Api/ApiException.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;

namespace Miningcore.Api
{
class ApiException : Exception
{
public ApiException(string message, int? responseStatusCode = null) : base(message)
public ApiException(string message, HttpStatusCode? responseStatusCode = null) : base(message)
{
ResponseStatusCode = responseStatusCode;
if(responseStatusCode.HasValue)
ResponseStatusCode = (int) responseStatusCode.Value;
}

public ApiException()
Expand Down
50 changes: 45 additions & 5 deletions src/Miningcore/Api/Controllers/AdminApiController.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
using Autofac;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Miningcore.Api.Extensions;
using Miningcore.Api.Requests;
using Miningcore.Api.Responses;
using Miningcore.Configuration;
using Miningcore.Extensions;
using Miningcore.Messaging;
using Miningcore.JsonRpc;
using Miningcore.Mining;
using Miningcore.Persistence;
using Miningcore.Persistence.Repositories;
using Miningcore.Time;
using Miningcore.Util;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace Miningcore.Api.Controllers
Expand All @@ -25,10 +24,23 @@ public class AdminApiController : ControllerBase
public AdminApiController(IComponentContext ctx)
{
gcStats = ctx.Resolve<AdminGcStats>();
clusterConfig = ctx.Resolve<ClusterConfig>();
pools = ctx.Resolve<ConcurrentDictionary<string, IMiningPool>>();
cf = ctx.Resolve<IConnectionFactory>();
paymentsRepo = ctx.Resolve<IPaymentRepository>();
balanceRepo = ctx.Resolve<IBalanceRepository>();
}

private readonly ClusterConfig clusterConfig;
private readonly IConnectionFactory cf;
private readonly IPaymentRepository paymentsRepo;
private readonly IBalanceRepository balanceRepo;
private readonly ConcurrentDictionary<string, IMiningPool> pools;

private AdminGcStats gcStats;

#region Actions

[HttpGet("stats/gc")]
public ActionResult<AdminGcStats> GetGcStats()
{
Expand All @@ -46,5 +58,33 @@ public ActionResult<string> ForceGc()
GC.Collect(2, GCCollectionMode.Forced);
return "Ok";
}

[HttpGet("pools/{poolId}/miners/{address}/getbalance")]
public async Task<decimal> GetMinerBalanceAsync(string poolId, string address)
{
return await cf.Run(con => balanceRepo.GetBalanceAsync(con, poolId, address));
}

[HttpPost("addbalance")]
public async Task<object> AddMinerBalanceAsync(AddBalanceRequest request)
{
request.Usage = request.Usage?.Trim();

if (string.IsNullOrEmpty(request.Usage))
request.Usage = $"Admin balance change from {Request.HttpContext.Connection.RemoteIpAddress}";

var oldBalance = await cf.Run(con => balanceRepo.GetBalanceAsync(con, request.PoolId, request.Address));

var count = await cf.RunTx(async (con, tx) =>
{
return await balanceRepo.AddAmountAsync(con, tx, request.PoolId, request.Address, request.Amount, request.Usage);
});

var newBalance = await cf.Run(con => balanceRepo.GetBalanceAsync(con, request.PoolId, request.Address));

return new { oldBalance, newBalance };
}

#endregion // Actions
}
}
91 changes: 54 additions & 37 deletions src/Miningcore/Api/Controllers/PoolApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
using Miningcore.Persistence.Model.Projections;
using Miningcore.Persistence.Repositories;
using Miningcore.Time;
using System;
using System.Collections.Concurrent;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace Miningcore.Api.Controllers
Expand Down Expand Up @@ -109,16 +111,32 @@ public async Task<GetPoolResponse> GetPoolInfoAsync(string poolId)
}

[HttpGet("{poolId}/performance")]
public async Task<GetPoolStatsResponse> GetPoolPerformanceAsync(string poolId)
public async Task<GetPoolStatsResponse> GetPoolPerformanceAsync(string poolId,
[FromQuery(Name = "r")] SampleRange range = SampleRange.Day,
[FromQuery(Name = "i")] SampleInterval interval = SampleInterval.Hour)
{
var pool = GetPool(poolId);

// set range
var end = clock.Now;
var start = end.AddDays(-1);
DateTime start;

switch (range)
{
case SampleRange.Day:
start = end.AddDays(-1);
break;

var stats = await cf.Run(con => statsRepo.GetPoolPerformanceBetweenHourlyAsync(
con, pool.Id, start, end));
case SampleRange.Month:
start = end.AddDays(-30);
break;

default:
throw new ApiException("invalid interval");
}

var stats = await cf.Run(con => statsRepo.GetPoolPerformanceBetweenAsync(
con, pool.Id, interval, start, end));

var response = new GetPoolStatsResponse
{
Expand Down Expand Up @@ -211,14 +229,12 @@ public async Task<MinerPerformanceStats[]> PagePoolMinersAsync(

[HttpGet("{poolId}/miners/{address}")]
public async Task<Responses.MinerStats> GetMinerInfoAsync(
string poolId, string address, [FromQuery] string perfMode)
string poolId, string address, [FromQuery] SampleRange perfMode = SampleRange.Day)
{
var pool = GetPool(poolId);

if (string.IsNullOrEmpty(address))
throw new ApiException($"Invalid or missing miner address", 401);

perfMode = perfMode ?? "day";
throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound);

var statsResult = await cf.RunTx((con, tx) =>
statsRepo.GetMinerStatsAsync(con, tx, pool.Id, address), true, IsolationLevel.Serializable);
Expand Down Expand Up @@ -254,7 +270,7 @@ public async Task<MinerPerformanceStats[]> PagePoolMinersAsync(
var pool = GetPool(poolId);

if (string.IsNullOrEmpty(address))
throw new ApiException($"Invalid or missing miner address", 401);
throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound);

var payments = (await cf.Run(con => paymentsRepo.PagePaymentsAsync(
con, pool.Id, address, page, pageSize)))
Expand Down Expand Up @@ -286,7 +302,7 @@ public async Task<MinerPerformanceStats[]> PagePoolMinersAsync(
var pool = GetPool(poolId);

if (string.IsNullOrEmpty(address))
throw new ApiException($"Invalid or missing miner address", 401);
throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound);

var balanceChanges = (await cf.Run(con => paymentsRepo.PageBalanceChangesAsync(
con, pool.Id, address, page, pageSize)))
Expand All @@ -303,7 +319,7 @@ public async Task<AmountByDate[]> PageMinerEarningsByDayAsync(
var pool = GetPool(poolId);

if (string.IsNullOrEmpty(address))
throw new ApiException($"Invalid or missing miner address", 401);
throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound);

var earnings = (await cf.Run(con => paymentsRepo.PageMinerPaymentsByDayAsync(
con, pool.Id, address, page, pageSize)))
Expand All @@ -314,14 +330,13 @@ public async Task<AmountByDate[]> PageMinerEarningsByDayAsync(

[HttpGet("{poolId}/miners/{address}/performance")]
public async Task<Responses.WorkerPerformanceStatsContainer[]> GetMinerPerformanceAsync(
string poolId, string address, [FromQuery] string mode)
string poolId, string address, [FromQuery] SampleRange mode = SampleRange.Day)
{
var pool = GetPool(poolId);

if (string.IsNullOrEmpty(address))
throw new ApiException($"Invalid or missing miner address", 401);
throw new ApiException($"Invalid or missing miner address", HttpStatusCode.NotFound);

mode = mode ?? "day";
var result = await GetMinerPerformanceInternal(mode, pool, address);

return result;
Expand All @@ -332,49 +347,51 @@ public async Task<AmountByDate[]> PageMinerEarningsByDayAsync(
private PoolConfig GetPool(string poolId)
{
if (string.IsNullOrEmpty(poolId))
throw new ApiException($"Invalid pool id", 401);
throw new ApiException($"Invalid pool id", HttpStatusCode.NotFound);

var pool = clusterConfig.Pools.FirstOrDefault(x => x.Id == poolId && x.Enabled);

if (pool == null)
throw new ApiException($"Pool {poolId} is not known", 401);
throw new ApiException($"Pool {poolId} is not known", HttpStatusCode.NotFound);

return pool;
}

private async Task<Responses.WorkerPerformanceStatsContainer[]> GetMinerPerformanceInternal(
string mode, PoolConfig pool, string address)
SampleRange mode, PoolConfig pool, string address)
{
Persistence.Model.Projections.WorkerPerformanceStatsContainer[] stats;
Persistence.Model.Projections.WorkerPerformanceStatsContainer[] stats = null;
var end = clock.Now;
DateTime start;

if (mode == "day" || mode != "month")
switch(mode)
{
// set range
if (end.Minute < 30)
end = end.AddHours(-1);
case SampleRange.Day:
// set range
if (end.Minute < 30)
end = end.AddHours(-1);

end = end.AddMinutes(-end.Minute);
end = end.AddSeconds(-end.Second);
end = end.AddMinutes(-end.Minute);
end = end.AddSeconds(-end.Second);

var start = end.AddDays(-1);
start = end.AddDays(-1);

stats = await cf.Run(con => statsRepo.GetMinerPerformanceBetweenHourlyAsync(
con, pool.Id, address, start, end));
}
stats = await cf.Run(con => statsRepo.GetMinerPerformanceBetweenHourlyAsync(
con, pool.Id, address, start, end));
break;

else
{
if (end.Hour < 12)
end = end.AddDays(-1);
case SampleRange.Month:
if (end.Hour < 12)
end = end.AddDays(-1);

end = end.Date;
end = end.Date;

// set range
var start = end.AddMonths(-1);
// set range
start = end.AddMonths(-1);

stats = await cf.Run(con => statsRepo.GetMinerPerformanceBetweenDailyAsync(
con, pool.Id, address, start, end));
stats = await cf.Run(con => statsRepo.GetMinerPerformanceBetweenDailyAsync(
con, pool.Id, address, start, end));
break;
}

// map
Expand Down
14 changes: 14 additions & 0 deletions src/Miningcore/Api/Requests/AddBalanceRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Miningcore.Api.Requests
{
public class AddBalanceRequest
{
public string PoolId { get; set; }
public string Address { get; set; }
public decimal Amount { get; set; }
public string Usage { get; set; }
}
}
1 change: 0 additions & 1 deletion src/Miningcore/Api/Responses/GetBalanceChangesResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ namespace Miningcore.Api.Responses
public class BalanceChange
{
public string PoolId { get; set; }
public string Coin { get; set; }
public string Address { get; set; }
public decimal Amount { get; set; }
public string Usage { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions src/Miningcore/Api/Responses/GetPoolStatsResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public partial class AggregatedPoolStats
public float PoolHashrate { get; set; }
public int ConnectedMiners { get; set; }
public int ValidSharesPerSecond { get; set; }
public double NetworkHashrate { get; set; }
public double NetworkDifficulty { get; set; }

public DateTime Created { get; set; }
}
Expand Down
3 changes: 3 additions & 0 deletions src/Miningcore/AutofacModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ protected override void Load(ContainerBuilder builder)
builder.RegisterType<ShareReceiver>()
.SingleInstance();

builder.RegisterType<BtStreamReceiver>()
.SingleInstance();

builder.RegisterType<ShareRelay>()
.SingleInstance();

Expand Down
Loading

0 comments on commit a2dd65a

Please sign in to comment.