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

Commit

Permalink
Merge pull request #842 from coinfoundry/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Oliver Weichhold authored Jun 16, 2021
2 parents 5fae0be + 0267a54 commit c6b4fd5
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 159 deletions.
18 changes: 0 additions & 18 deletions src/Miningcore.Tests/Crypto/HashingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,23 +364,5 @@ public void Sha3_512_Hash()

Assert.Equal("e0883cffc9ff0ecf41fca8ade29dba1fc0df4b15beccc06ca03283805e176e497f0dd33db3bda375b199a4bb5eb1bb3ba884f3cc26f65f7acf08e1307058cc8d", result);
}

[Fact]
public void RandomX()
{
var blobConverted = "0106a2aaafd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b42580100a4b1e2f4baf6ab7109071ab59bc52dba740d1de99fa0ae0c4afd6ea9f40c5d87ec01".HexToByteArray();
var buf = new byte[32];
var key = Encoding.UTF8.GetBytes("foo bar");

LibRandomX.CalculateHash(key, blobConverted, buf);
var result = buf.ToHexString();
Assert.Equal("ae46586e2b786b08cf3884747e391fc27695b40c2502b45b39727832099a19c0", result);

Array.Clear(buf, 0, buf.Length);

LibRandomX.CalculateHash(key, blobConverted, buf);
result = buf.ToHexString();
Assert.Equal("ae46586e2b786b08cf3884747e391fc27695b40c2502b45b39727832099a19c0", result);
}
}
}
80 changes: 80 additions & 0 deletions src/Miningcore.Tests/Crypto/LibRandomXTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using Miningcore.Extensions;
using Miningcore.Native;
using Xunit;

namespace Miningcore.Tests.Crypto
{
public class LibRandomXTests : TestBase
{
const string realm = "xmr";
const string seedHex = "7915d56de262bf23b1fb9104cf5d2a13fcbed2f6b4b9b657309c222b09f54bc0";
private static readonly byte[] data = "0106a2aaafd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b42580100a4b1e2f4baf6ab7109071ab59bc52dba740d1de99fa0ae0c4afd6ea9f40c5d87ec01".HexToByteArray();
private const string hashExpected = "55ef9dc0b8e0cb82c609a003c7d99504fc87f5e2dcd31f6fef318fc172cbc887";

[Fact]
public void CreateAndDeleteSeed()
{
// creation
LibRandomX.CreateSeed(realm, seedHex);
Assert.True(LibRandomX.realms.ContainsKey(realm));
Assert.True(LibRandomX.realms[realm].ContainsKey(seedHex));

// accessing the created seed should work
Assert.NotNull(LibRandomX.GetSeed(realm, seedHex));

// creating the same realm and key twice should not result in duplicates
LibRandomX.CreateSeed(realm, seedHex);
Assert.Equal(LibRandomX.realms.Count, 1);
Assert.Equal(LibRandomX.realms[realm].Count, 1);

// deletion
LibRandomX.DeleteSeed(realm, seedHex);
Assert.False(LibRandomX.realms[realm].ContainsKey(seedHex));
}

[Fact]
public void CalculateHashSlow()
{
var buf = new byte[32];

// light-mode
LibRandomX.CreateSeed(realm, seedHex);

LibRandomX.CalculateHash("xmr", seedHex, data, buf);
var result = buf.ToHexString();
Assert.Equal(hashExpected, result);

Array.Clear(buf, 0, buf.Length);

// second invocation should give the same result
LibRandomX.CalculateHash("xmr", seedHex, data, buf);
result = buf.ToHexString();
Assert.Equal(hashExpected, result);

LibRandomX.DeleteSeed(realm, seedHex);
}

[Fact]
public void CalculateHashFast()
{
var buf = new byte[32];

// fast-mode
LibRandomX.CreateSeed(realm, seedHex, null, LibRandomX.randomx_flags.RANDOMX_FLAG_FULL_MEM);

LibRandomX.CalculateHash("xmr", seedHex, data, buf);
var result = buf.ToHexString();
Assert.Equal(hashExpected, result);

Array.Clear(buf, 0, buf.Length);

// second invocation should give the same result
LibRandomX.CalculateHash("xmr", seedHex, data, buf);
result = buf.ToHexString();
Assert.Equal(hashExpected, result);

LibRandomX.DeleteSeed(realm, seedHex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

using Miningcore.Configuration;
using Miningcore.Native;
using Newtonsoft.Json.Linq;

namespace Miningcore.Blockchain.Cryptonote.Configuration
Expand All @@ -45,6 +44,7 @@ public class CryptonotePoolConfigExtra
/// Optional value for number of RandomX VMs allocated per generation (new seed hash)
/// Set to -1 to scale to number of cores
/// </summary>
// ReSharper disable once InconsistentNaming
public int RandomXVMCount { get; set; } = 1;
}
}
19 changes: 6 additions & 13 deletions src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,33 @@ namespace Miningcore.Blockchain.Cryptonote
public class CryptonoteJob
{
public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, string jobId,
PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash,
LibRandomX.randomx_flags? randomXFlagsOverride,
LibRandomX.randomx_flags? randomXFlagsAdd,
int randomXvmCount)
CryptonoteCoinTemplate coin, PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash, string randomXRealm)
{
Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate));
Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig));
Contract.RequiresNonNull(instanceId, nameof(instanceId));
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty");

coin = poolConfig.Template.As<CryptonoteCoinTemplate>();
this.coin = coin;
BlockTemplate = blockTemplate;
PrepareBlobTemplate(instanceId);
PrevHash = prevHash;

if(!string.IsNullOrEmpty(blockTemplate.SeedHash))
seedHashBytes = blockTemplate.SeedHash.HexToByteArray();

switch(coin.Hash)
{
case CryptonightHashType.RandomX:
hashFunc = ((key, data, result, height) =>
hashFunc = ((seedHex, data, result, height) =>
{
LibRandomX.CalculateHash(key, data, result, randomXFlagsOverride, randomXFlagsAdd, randomXvmCount);
LibRandomX.CalculateHash(randomXRealm, seedHex, data, result);
});
break;
}
}

public delegate void HashFunc(byte[] key, ReadOnlySpan<byte> data, Span<byte> result, ulong height);
public delegate void HashFunc(string seedHex, ReadOnlySpan<byte> data, Span<byte> result, ulong height);

private byte[] blobTemplate;
private readonly byte[] seedHashBytes;
private int extraNonce;
private readonly CryptonoteCoinTemplate coin;
private readonly HashFunc hashFunc;
Expand Down Expand Up @@ -171,7 +164,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out

// hash it
Span<byte> headerHash = stackalloc byte[32];
hashFunc(seedHashBytes, blobConverted, headerHash, BlockTemplate.Height);
hashFunc(BlockTemplate.SeedHash, blobConverted, headerHash, BlockTemplate.Height);

var headerHashString = headerHash.ToHexString();
if(headerHashString != workerHash)
Expand Down
73 changes: 69 additions & 4 deletions src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Reactive;
using System.Reactive.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
Expand All @@ -40,7 +42,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using Miningcore.Messaging;
using Miningcore.Native;
using Miningcore.Notifications.Messages;
using Miningcore.Payments;
using Miningcore.Stratum;
using Miningcore.Time;
using Miningcore.Util;
Expand Down Expand Up @@ -82,8 +83,11 @@ public CryptonoteJobManager(
private CryptonotePoolConfigExtra extraPoolConfig;
private LibRandomX.randomx_flags? randomXFlagsOverride;
private LibRandomX.randomx_flags? randomXFlagsAdd;
private string currentSeedHash;
private string randomXRealm;
private ulong poolAddressBase58Prefix;
private DaemonEndpointConfig[] walletDaemonEndpoints;
private CryptonoteCoinTemplate coin;

protected async Task<bool> UpdateJob(string via = null, string json = null)
{
Expand Down Expand Up @@ -115,7 +119,25 @@ protected async Task<bool> UpdateJob(string via = null, string json = null)
else
logger.Info(() => $"Detected new block {blockTemplate.Height}");

job = new CryptonoteJob(blockTemplate, instanceId, NextJobId(), poolConfig, clusterConfig, newHash, randomXFlagsOverride, randomXFlagsAdd, extraPoolConfig.RandomXVMCount);
// detect seed hash change
if(currentSeedHash != blockTemplate.SeedHash)
{
logger.Info(()=> $"Detected new seed hash {blockTemplate.SeedHash} starting @ height {blockTemplate.Height}");

LibRandomX.WithLock(() =>
{
// delete old seed
if(currentSeedHash != null)
LibRandomX.DeleteSeed(randomXRealm, currentSeedHash);

// activate new one
currentSeedHash = blockTemplate.SeedHash;
LibRandomX.CreateSeed(randomXRealm, currentSeedHash, randomXFlagsOverride, randomXFlagsAdd, extraPoolConfig.RandomXVMCount);
});
}

// init job
job = new CryptonoteJob(blockTemplate, instanceId, NextJobId(), coin, poolConfig, clusterConfig, newHash, randomXRealm);
currentJob = job;

// update stats
Expand Down Expand Up @@ -233,6 +255,8 @@ private async Task<bool> SubmitBlockAsync(Share share, string blobHex, string bl

public IObservable<Unit> Blocks { get; private set; }

public CryptonoteCoinTemplate Coin => coin;

public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig)
{
Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
Expand All @@ -242,7 +266,9 @@ public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfi
this.poolConfig = poolConfig;
this.clusterConfig = clusterConfig;
extraPoolConfig = poolConfig.Extra.SafeExtensionDataAs<CryptonotePoolConfigExtra>();
coin = poolConfig.Template.As<CryptonoteCoinTemplate>();

randomXRealm = poolConfig.Id;
randomXFlagsOverride = MakeRandomXFlags(extraPoolConfig.RandomXFlagsOverride);
randomXFlagsAdd = MakeRandomXFlags(extraPoolConfig.RandomXFlagsAdd);

Expand Down Expand Up @@ -377,6 +403,21 @@ public async ValueTask<Share> SubmitShareAsync(StratumClient worker,

#endregion // API-Surface

private static JToken GetFrameAsJToken(byte[] frame)
{
var text = Encoding.UTF8.GetString(frame);

// find end of message type indicator
var index = text.IndexOf(":");

if (index == -1)
return null;

var json = text.Substring(index + 1);

return JToken.Parse(json);
}

private LibRandomX.randomx_flags? MakeRandomXFlags(JToken token)
{
if(token == null)
Expand Down Expand Up @@ -631,14 +672,38 @@ protected virtual void SetupJobUpdates()
logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}");

var blockNotify = daemon.ZmqSubscribe(logger, zmq)
.Where(msg =>
{
bool result = false;

try
{
var text = Encoding.UTF8.GetString(msg[0].Read());

result = text.StartsWith("json-minimal-chain_main:");
}

catch
{
}

if(!result)
msg.Dispose();

return result;
})
.Select(msg =>
{
using(msg)
{
var token = GetFrameAsJToken(msg[0].Read());

if (token != null)
return token.Value<long>("first_height").ToString(CultureInfo.InvariantCulture);

// We just take the second frame's raw data and turn it into a hex string.
// If that string changes, we got an update (DistinctUntilChanged)
var result = msg[1].Read().ToHexString();
return result;
return msg[0].Read().ToHexString();
}
})
.DistinctUntilChanged()
Expand Down
17 changes: 17 additions & 0 deletions src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public CryptonotePool(IComponentContext ctx,
private long currentJobId;

private CryptonoteJobManager manager;
private string minerAlgo;

private async Task OnLoginAsync(StratumClient client, Timestamped<JsonRpcRequest> tsRequest)
{
Expand Down Expand Up @@ -173,6 +174,9 @@ private CryptonoteJobParams CreateWorkerJob(StratumClient client)
SeedHash = job.SeedHash,
};

if(!string.IsNullOrEmpty(minerAlgo))
result.Algorithm = minerAlgo;

// update context
lock(context)
{
Expand Down Expand Up @@ -312,6 +316,8 @@ protected override async Task SetupJobManager(CancellationToken ct)

if(poolConfig.EnableInternalStratum == true)
{
minerAlgo = GetMinerAlgo();

disposables.Add(manager.Blocks
.Select(_ => Observable.FromAsync(async () =>
{
Expand Down Expand Up @@ -342,6 +348,17 @@ protected override async Task SetupJobManager(CancellationToken ct)
}
}

private string GetMinerAlgo()
{
switch(manager.Coin.Hash)
{
case CryptonightHashType.RandomX:
return $"rx/{manager.Coin.HashVariant}";
}

return null;
}

protected override async Task InitStatsAsync()
{
await base.InitStatsAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public class CryptonoteJobParams
[JsonProperty("seed_hash")]
public string SeedHash { get; set; }

[JsonProperty("algo")]
public string Algorithm { get; set; }

/// <summary>
/// Introduced for CNv4 (aka CryptonightR)
/// </summary>
Expand Down
Loading

0 comments on commit c6b4fd5

Please sign in to comment.